blob: 8bb1ec271368c6e1981ab81a668e93f9e570d9ba [file] [log] [blame]
Michal Vasko730dfdf2015-08-11 14:48:05 +02001/**
2 * @file resolve.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief libyang resolve functions
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of the Company nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 */
21
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020022#define _GNU_SOURCE
23
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
Michal Vaskoe7fc19c2015-08-05 16:24:39 +020028#include <limits.h>
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020029
30#include "libyang.h"
31#include "resolve.h"
32#include "common.h"
Michal Vaskocf024702015-10-08 15:01:42 +020033#include "xpath.h"
Michal Vasko1dca6882015-10-22 14:29:42 +020034#include "parser.h"
Pavol Vicana0e4e672016-02-24 12:20:04 +010035#include "parser_yang.h"
Michal Vasko88c29542015-11-27 14:57:53 +010036#include "xml_internal.h"
Radek Krejci41912fe2015-10-22 10:22:12 +020037#include "dict_private.h"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020038#include "tree_internal.h"
39
Michal Vasko730dfdf2015-08-11 14:48:05 +020040/**
Radek Krejci6dc53a22015-08-17 13:27:59 +020041 * @brief Parse an identifier.
42 *
43 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
44 * identifier = (ALPHA / "_")
45 * *(ALPHA / DIGIT / "_" / "-" / ".")
46 *
Michal Vaskobb211122015-08-19 14:03:11 +020047 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +020048 *
49 * @return Number of characters successfully parsed.
50 */
Michal Vasko249e6b52015-08-19 11:08:52 +020051int
Radek Krejci6dc53a22015-08-17 13:27:59 +020052parse_identifier(const char *id)
53{
54 int parsed = 0;
55
56 if (((id[0] == 'x') || (id[0] == 'X'))
57 && ((id[1] == 'm') || (id[0] == 'M'))
58 && ((id[2] == 'l') || (id[2] == 'L'))) {
59 return -parsed;
60 }
61
62 if (!isalpha(id[0]) && (id[0] != '_')) {
63 return -parsed;
64 }
65
66 ++parsed;
67 ++id;
68
69 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
70 ++parsed;
71 ++id;
72 }
73
74 return parsed;
75}
76
77/**
78 * @brief Parse a node-identifier.
79 *
Michal Vasko723e50c2015-10-20 15:20:29 +020080 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +020081 *
Michal Vaskobb211122015-08-19 14:03:11 +020082 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +020083 * @param[out] mod_name Points to the module name, NULL if there is not any.
84 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +020085 * @param[out] name Points to the node name.
86 * @param[out] nam_len Length of the node name.
87 *
88 * @return Number of characters successfully parsed,
89 * positive on success, negative on failure.
90 */
91static int
Michal Vasko723e50c2015-10-20 15:20:29 +020092parse_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 +020093{
94 int parsed = 0, ret;
95
96 assert(id);
Michal Vasko723e50c2015-10-20 15:20:29 +020097 if (mod_name) {
98 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +020099 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200100 if (mod_name_len) {
101 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200102 }
103 if (name) {
104 *name = NULL;
105 }
106 if (nam_len) {
107 *nam_len = 0;
108 }
109
110 if ((ret = parse_identifier(id)) < 1) {
111 return ret;
112 }
113
Michal Vasko723e50c2015-10-20 15:20:29 +0200114 if (mod_name) {
115 *mod_name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200116 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200117 if (mod_name_len) {
118 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200119 }
120
121 parsed += ret;
122 id += ret;
123
124 /* there is prefix */
125 if (id[0] == ':') {
126 ++parsed;
127 ++id;
128
129 /* there isn't */
130 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200131 if (name && mod_name) {
132 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200133 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200134 if (mod_name) {
135 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200136 }
137
Michal Vasko723e50c2015-10-20 15:20:29 +0200138 if (nam_len && mod_name_len) {
139 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200140 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200141 if (mod_name_len) {
142 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200143 }
144
145 return parsed;
146 }
147
148 /* identifier (node name) */
149 if ((ret = parse_identifier(id)) < 1) {
150 return -parsed+ret;
151 }
152
153 if (name) {
154 *name = id;
155 }
156 if (nam_len) {
157 *nam_len = ret;
158 }
159
160 return parsed+ret;
161}
162
163/**
164 * @brief Parse a path-predicate (leafref).
165 *
166 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
167 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
168 *
Michal Vaskobb211122015-08-19 14:03:11 +0200169 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200170 * @param[out] prefix Points to the prefix, NULL if there is not any.
171 * @param[out] pref_len Length of the prefix, 0 if there is not any.
172 * @param[out] name Points to the node name.
173 * @param[out] nam_len Length of the node name.
174 * @param[out] path_key_expr Points to the path-key-expr.
175 * @param[out] pke_len Length of the path-key-expr.
176 * @param[out] has_predicate Flag to mark whether there is another predicate following.
177 *
178 * @return Number of characters successfully parsed,
179 * positive on success, negative on failure.
180 */
181static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200182parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
183 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200184{
185 const char *ptr;
186 int parsed = 0, ret;
187
188 assert(id);
189 if (prefix) {
190 *prefix = NULL;
191 }
192 if (pref_len) {
193 *pref_len = 0;
194 }
195 if (name) {
196 *name = NULL;
197 }
198 if (nam_len) {
199 *nam_len = 0;
200 }
201 if (path_key_expr) {
202 *path_key_expr = NULL;
203 }
204 if (pke_len) {
205 *pke_len = 0;
206 }
207 if (has_predicate) {
208 *has_predicate = 0;
209 }
210
211 if (id[0] != '[') {
212 return -parsed;
213 }
214
215 ++parsed;
216 ++id;
217
218 while (isspace(id[0])) {
219 ++parsed;
220 ++id;
221 }
222
223 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
224 return -parsed+ret;
225 }
226
227 parsed += ret;
228 id += ret;
229
230 while (isspace(id[0])) {
231 ++parsed;
232 ++id;
233 }
234
235 if (id[0] != '=') {
236 return -parsed;
237 }
238
239 ++parsed;
240 ++id;
241
242 while (isspace(id[0])) {
243 ++parsed;
244 ++id;
245 }
246
247 if ((ptr = strchr(id, ']')) == NULL) {
248 return -parsed;
249 }
250
251 --ptr;
252 while (isspace(ptr[0])) {
253 --ptr;
254 }
255 ++ptr;
256
257 ret = ptr-id;
258 if (path_key_expr) {
259 *path_key_expr = id;
260 }
261 if (pke_len) {
262 *pke_len = ret;
263 }
264
265 parsed += ret;
266 id += ret;
267
268 while (isspace(id[0])) {
269 ++parsed;
270 ++id;
271 }
272
273 assert(id[0] == ']');
274
275 if (id[1] == '[') {
276 *has_predicate = 1;
277 }
278
279 return parsed+1;
280}
281
282/**
283 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
284 * the ".." and the first node-identifier, other calls parse a single
285 * node-identifier each.
286 *
287 * path-key-expr = current-function-invocation *WSP "/" *WSP
288 * rel-path-keyexpr
289 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
290 * *(node-identifier *WSP "/" *WSP)
291 * node-identifier
292 *
Michal Vaskobb211122015-08-19 14:03:11 +0200293 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200294 * @param[out] prefix Points to the prefix, NULL if there is not any.
295 * @param[out] pref_len Length of the prefix, 0 if there is not any.
296 * @param[out] name Points to the node name.
297 * @param[out] nam_len Length of the node name.
298 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
299 * must not be changed between consecutive calls.
300 * @return Number of characters successfully parsed,
301 * positive on success, negative on failure.
302 */
303static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200304parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
305 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200306{
307 int parsed = 0, ret, par_times = 0;
308
309 assert(id);
310 assert(parent_times);
311 if (prefix) {
312 *prefix = NULL;
313 }
314 if (pref_len) {
315 *pref_len = 0;
316 }
317 if (name) {
318 *name = NULL;
319 }
320 if (nam_len) {
321 *nam_len = 0;
322 }
323
324 if (!*parent_times) {
325 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
326 if (strncmp(id, "current()", 9)) {
327 return -parsed;
328 }
329
330 parsed += 9;
331 id += 9;
332
333 while (isspace(id[0])) {
334 ++parsed;
335 ++id;
336 }
337
338 if (id[0] != '/') {
339 return -parsed;
340 }
341
342 ++parsed;
343 ++id;
344
345 while (isspace(id[0])) {
346 ++parsed;
347 ++id;
348 }
349
350 /* rel-path-keyexpr */
351 if (strncmp(id, "..", 2)) {
352 return -parsed;
353 }
354 ++par_times;
355
356 parsed += 2;
357 id += 2;
358
359 while (isspace(id[0])) {
360 ++parsed;
361 ++id;
362 }
363 }
364
365 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
366 *
367 * first parent reference with whitespaces already parsed
368 */
369 if (id[0] != '/') {
370 return -parsed;
371 }
372
373 ++parsed;
374 ++id;
375
376 while (isspace(id[0])) {
377 ++parsed;
378 ++id;
379 }
380
381 while (!strncmp(id, "..", 2) && !*parent_times) {
382 ++par_times;
383
384 parsed += 2;
385 id += 2;
386
387 while (isspace(id[0])) {
388 ++parsed;
389 ++id;
390 }
391
392 if (id[0] != '/') {
393 return -parsed;
394 }
395
396 ++parsed;
397 ++id;
398
399 while (isspace(id[0])) {
400 ++parsed;
401 ++id;
402 }
403 }
404
405 if (!*parent_times) {
406 *parent_times = par_times;
407 }
408
409 /* all parent references must be parsed at this point */
410 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
411 return -parsed+ret;
412 }
413
414 parsed += ret;
415 id += ret;
416
417 return parsed;
418}
419
420/**
421 * @brief Parse path-arg (leafref).
422 *
423 * path-arg = absolute-path / relative-path
424 * absolute-path = 1*("/" (node-identifier *path-predicate))
425 * relative-path = 1*(".." "/") descendant-path
426 *
Michal Vaskobb211122015-08-19 14:03:11 +0200427 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200428 * @param[out] prefix Points to the prefix, NULL if there is not any.
429 * @param[out] pref_len Length of the prefix, 0 if there is not any.
430 * @param[out] name Points to the node name.
431 * @param[out] nam_len Length of the node name.
432 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
433 * must not be changed between consecutive calls. -1 if the
434 * path is relative.
435 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
436 *
437 * @return Number of characters successfully parsed,
438 * positive on success, negative on failure.
439 */
440static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200441parse_path_arg(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len, int *parent_times,
442 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200443{
444 int parsed = 0, ret, par_times = 0;
445
446 assert(id);
447 assert(parent_times);
448 if (prefix) {
449 *prefix = NULL;
450 }
451 if (pref_len) {
452 *pref_len = 0;
453 }
454 if (name) {
455 *name = NULL;
456 }
457 if (nam_len) {
458 *nam_len = 0;
459 }
460 if (has_predicate) {
461 *has_predicate = 0;
462 }
463
464 if (!*parent_times && !strncmp(id, "..", 2)) {
465 ++par_times;
466
467 parsed += 2;
468 id += 2;
469
470 while (!strncmp(id, "/..", 3)) {
471 ++par_times;
472
473 parsed += 3;
474 id += 3;
475 }
476 }
477
478 if (!*parent_times) {
479 if (par_times) {
480 *parent_times = par_times;
481 } else {
482 *parent_times = -1;
483 }
484 }
485
486 if (id[0] != '/') {
487 return -parsed;
488 }
489
490 /* skip '/' */
491 ++parsed;
492 ++id;
493
494 /* node-identifier ([prefix:]identifier) */
495 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
496 return -parsed-ret;
497 }
498
499 parsed += ret;
500 id += ret;
501
502 /* there is no predicate */
503 if ((id[0] == '/') || !id[0]) {
504 return parsed;
505 } else if (id[0] != '[') {
506 return -parsed;
507 }
508
509 if (has_predicate) {
510 *has_predicate = 1;
511 }
512
513 return parsed;
514}
515
516/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200517 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200518 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200519 *
520 * instance-identifier = 1*("/" (node-identifier *predicate))
521 *
Michal Vaskobb211122015-08-19 14:03:11 +0200522 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200523 * @param[out] model Points to the model name.
524 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200525 * @param[out] name Points to the node name.
526 * @param[out] nam_len Length of the node name.
527 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
528 *
529 * @return Number of characters successfully parsed,
530 * positive on success, negative on failure.
531 */
532static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200533parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
534 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200535{
536 int parsed = 0, ret;
537
538 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200539 if (model) {
540 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200541 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200542 if (mod_len) {
543 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200544 }
545 if (name) {
546 *name = NULL;
547 }
548 if (nam_len) {
549 *nam_len = 0;
550 }
551 if (has_predicate) {
552 *has_predicate = 0;
553 }
554
555 if (id[0] != '/') {
556 return -parsed;
557 }
558
559 ++parsed;
560 ++id;
561
Michal Vasko1f2cc332015-08-19 11:18:32 +0200562 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200563 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200564 } else if (model && !*model) {
565 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200566 }
567
568 parsed += ret;
569 id += ret;
570
571 if ((id[0] == '[') && has_predicate) {
572 *has_predicate = 1;
573 }
574
575 return parsed;
576}
577
578/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200579 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200580 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200581 *
582 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
583 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
584 * ((DQUOTE string DQUOTE) /
585 * (SQUOTE string SQUOTE))
586 * pos = non-negative-integer-value
587 *
Michal Vaskobb211122015-08-19 14:03:11 +0200588 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200589 * @param[out] model Points to the model name.
590 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200591 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
592 * @param[out] nam_len Length of the node name.
593 * @param[out] value Value the node-identifier must have (string from the grammar),
594 * NULL if there is not any.
595 * @param[out] val_len Length of the value, 0 if there is not any.
596 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
597 *
598 * @return Number of characters successfully parsed,
599 * positive on success, negative on failure.
600 */
601static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200602parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
603 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200604{
605 const char *ptr;
606 int parsed = 0, ret;
607 char quote;
608
609 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200610 if (model) {
611 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200612 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200613 if (mod_len) {
614 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200615 }
616 if (name) {
617 *name = NULL;
618 }
619 if (nam_len) {
620 *nam_len = 0;
621 }
622 if (value) {
623 *value = NULL;
624 }
625 if (val_len) {
626 *val_len = 0;
627 }
628 if (has_predicate) {
629 *has_predicate = 0;
630 }
631
632 if (id[0] != '[') {
633 return -parsed;
634 }
635
636 ++parsed;
637 ++id;
638
639 while (isspace(id[0])) {
640 ++parsed;
641 ++id;
642 }
643
644 /* pos */
645 if (isdigit(id[0])) {
646 if (name) {
647 *name = id;
648 }
649
650 if (id[0] == '0') {
651 ++parsed;
652 ++id;
653
654 if (isdigit(id[0])) {
655 return -parsed;
656 }
657 }
658
659 while (isdigit(id[0])) {
660 ++parsed;
661 ++id;
662 }
663
664 if (nam_len) {
665 *nam_len = id-(*name);
666 }
667
668 /* "." */
669 } else if (id[0] == '.') {
670 if (name) {
671 *name = id;
672 }
673 if (nam_len) {
674 *nam_len = 1;
675 }
676
677 ++parsed;
678 ++id;
679
680 /* node-identifier */
681 } else {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200682 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200683 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200684 } else if (model && !*model) {
685 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200686 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200687
688 parsed += ret;
689 id += ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200690 }
691
692 while (isspace(id[0])) {
693 ++parsed;
694 ++id;
695 }
696
697 if (id[0] != '=') {
698 return -parsed;
699 }
700
701 ++parsed;
702 ++id;
703
704 while (isspace(id[0])) {
705 ++parsed;
706 ++id;
707 }
708
709 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
710 if ((id[0] == '\"') || (id[0] == '\'')) {
711 quote = id[0];
712
713 ++parsed;
714 ++id;
715
716 if ((ptr = strchr(id, quote)) == NULL) {
717 return -parsed;
718 }
719 ret = ptr-id;
720
721 if (value) {
722 *value = id;
723 }
724 if (val_len) {
725 *val_len = ret;
726 }
727
728 parsed += ret+1;
729 id += ret+1;
730 } else {
731 return -parsed;
732 }
733
734 while (isspace(id[0])) {
735 ++parsed;
736 ++id;
737 }
738
739 if (id[0] != ']') {
740 return -parsed;
741 }
742
743 ++parsed;
744 ++id;
745
746 if ((id[0] == '[') && has_predicate) {
747 *has_predicate = 1;
748 }
749
750 return parsed;
751}
752
753/**
754 * @brief Parse schema-nodeid.
755 *
756 * schema-nodeid = absolute-schema-nodeid /
757 * descendant-schema-nodeid
758 * absolute-schema-nodeid = 1*("/" node-identifier)
759 * descendant-schema-nodeid =
760 * node-identifier
761 * absolute-schema-nodeid
762 *
Michal Vaskobb211122015-08-19 14:03:11 +0200763 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200764 * @param[out] mod_name Points to the module name, NULL if there is not any.
765 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200766 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
767 * @param[out] nam_len Length of the node name.
768 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
769 * on the first call, must not be changed between consecutive calls.
770 *
771 * @return Number of characters successfully parsed,
772 * positive on success, negative on failure.
773 */
774static int
Michal Vasko723e50c2015-10-20 15:20:29 +0200775parse_schema_nodeid(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
Michal Vasko23b61ec2015-08-19 11:19:50 +0200776 int *is_relative)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200777{
778 int parsed = 0, ret;
779
780 assert(id);
781 assert(is_relative);
Michal Vasko723e50c2015-10-20 15:20:29 +0200782 if (mod_name) {
783 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200784 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200785 if (mod_name_len) {
786 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200787 }
788 if (name) {
789 *name = NULL;
790 }
791 if (nam_len) {
792 *nam_len = 0;
793 }
794
795 if (id[0] != '/') {
796 if (*is_relative != -1) {
797 return -parsed;
798 } else {
799 *is_relative = 1;
800 }
801 } else {
802 if (*is_relative == -1) {
803 *is_relative = 0;
804 }
805 ++parsed;
806 ++id;
807 }
808
Michal Vasko723e50c2015-10-20 15:20:29 +0200809 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200810 return -parsed+ret;
811 }
812
813 return parsed+ret;
814}
815
816/**
Michal Vasko3edeaf72016-02-11 13:17:43 +0100817 * @brief Resolve (find) a data node based on a schema-nodeid.
818 *
819 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
820 * module).
821 *
822 */
823struct lyd_node *
824resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
825{
826 char *str, *token, *p;
827 struct lyd_node *result = start, *iter;
828 const struct lys_node *schema = NULL;
829
830 assert(nodeid && start);
831
832 if (nodeid[0] == '/') {
833 return NULL;
834 }
835
836 str = p = strdup(nodeid);
837 if (!str) {
838 LOGMEM;
839 return NULL;
840 }
841 while (p) {
842 token = p;
843 p = strchr(p, '/');
844 if (p) {
845 *p = '\0';
846 p++;
847 }
848
849 schema = NULL;
850 if (resolve_descendant_schema_nodeid(token, result->schema, LYS_LEAF, &schema) || !schema) {
851 free(str);
852 return NULL;
853 }
854
855 LY_TREE_FOR(result, iter) {
856 if (iter->schema == schema) {
857 break;
858 }
859 }
860
861 if (!p) {
862 /* final result */
863 result = iter;
864 } else {
865 result = iter->child;
866 }
867 }
868 free(str);
869
870 return result;
871}
872
873/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
874int
875resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
876 const struct lys_node **ret)
877{
878 const char *name, *mod_name, *id;
879 const struct lys_node *sibling;
880 int r, nam_len, mod_name_len, is_relative = -1;
881 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vasko4f0dad02016-02-15 14:08:23 +0100882 const struct lys_module *prefix_mod, *start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +0100883
884 assert(nodeid && (start || module) && !(start && module) && ret);
885
886 id = nodeid;
887
888 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
889 return ((id - nodeid) - r) + 1;
890 }
891 id += r;
892
893 if ((is_relative && !start) || (!is_relative && !module)) {
894 return -1;
895 }
896
897 /* descendant-schema-nodeid */
898 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +0100899 module = start_mod = start->module;
Michal Vasko3edeaf72016-02-11 13:17:43 +0100900
901 /* absolute-schema-nodeid */
902 } else {
903 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +0100904 if (!start_mod) {
905 return -1;
906 }
Michal Vasko3edeaf72016-02-11 13:17:43 +0100907 start = start_mod->data;
908 }
909
910 while (1) {
911 sibling = NULL;
912 while ((sibling = lys_getnext(sibling, lys_parent(start), start_mod,
913 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
914 /* name match */
915 if ((sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len])
916 || (!strncmp(name, "input", 5) && (nam_len == 5) && (sibling->nodetype == LYS_INPUT))
917 || (!strncmp(name, "output", 6) && (nam_len == 6) && (sibling->nodetype == LYS_OUTPUT))) {
918
919 /* module check */
920 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
921 if (!prefix_mod) {
922 return -1;
923 }
Michal Vasko4f0dad02016-02-15 14:08:23 +0100924 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +0100925 continue;
926 }
927
928 /* the result node? */
929 if (!id[0]) {
930 *ret = sibling;
931 return EXIT_SUCCESS;
932 }
933
934 /* check for shorthand cases - then 'start' does not change */
935 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
936 || (sibling->nodetype == LYS_CASE)) {
937 start = sibling->child;
938 }
939 break;
940 }
941 }
942
943 /* no match */
944 if (!sibling) {
945 return EXIT_SUCCESS;
946 }
947
948 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
949 return ((id - nodeid) - r) + 1;
950 }
951 id += r;
952 }
953
954 /* cannot get here */
955 LOGINT;
956 return -1;
957}
958
959/* unique, refine, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
960int
961resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
962 const struct lys_node **ret)
963{
964 const char *name, *mod_name, *id;
965 const struct lys_node *sibling;
966 int r, nam_len, mod_name_len, is_relative = -1;
967 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vasko4f0dad02016-02-15 14:08:23 +0100968 const struct lys_module *prefix_mod, *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +0100969
970 assert(nodeid && start && ret);
971 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
972
973 id = nodeid;
974 module = start->module;
975
976 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
977 return ((id - nodeid) - r) + 1;
978 }
979 id += r;
980
981 if (!is_relative) {
982 return -1;
983 }
984
985 while (1) {
986 sibling = NULL;
987 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
988 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
989 /* name match */
990 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
991
992 /* module check */
993 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
994 if (!prefix_mod) {
995 return -1;
996 }
Michal Vasko4f0dad02016-02-15 14:08:23 +0100997 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +0100998 continue;
999 }
1000
1001 /* the result node? */
1002 if (!id[0]) {
1003 if (!(sibling->nodetype & ret_nodetype)) {
1004 /* wrong node type, too bad */
1005 continue;
1006 }
1007 *ret = sibling;
1008 return EXIT_SUCCESS;
1009 }
1010
1011 /* check for shorthand cases - then 'start' does not change */
1012 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1013 || (sibling->nodetype == LYS_CASE)) {
1014 start = sibling->child;
1015 }
1016 break;
1017 }
1018 }
1019
1020 /* no match */
1021 if (!sibling) {
1022 return EXIT_SUCCESS;
1023 }
1024
1025 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
1026 return ((id - nodeid) - r) + 1;
1027 }
1028 id += r;
1029 }
1030
1031 /* cannot get here */
1032 LOGINT;
1033 return -1;
1034}
1035
1036/* choice default */
1037int
1038resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1039{
1040 /* cannot actually be a path */
1041 if (strchr(nodeid, '/')) {
1042 return -1;
1043 }
1044
1045 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, ret);
1046}
1047
1048/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1049static int
1050resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1051{
1052 const struct lys_module *module;
1053 const char *mod_prefix, *name;
1054 int i, mod_prefix_len, nam_len;
1055
1056 /* parse the identifier, it must be parsed on one call */
1057 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1058 return -i + 1;
1059 }
1060
1061 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1062 if (!module) {
1063 return -1;
1064 }
1065 if (module != start->module) {
1066 start = module->data;
1067 }
1068
1069 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1070
1071 return EXIT_SUCCESS;
1072}
1073
1074int
1075resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1076 const struct lys_node **ret)
1077{
1078 const char *name, *mod_name, *id;
1079 const struct lys_node *sibling, *start;
1080 int r, nam_len, mod_name_len, is_relative = -1;
Michal Vasko4f0dad02016-02-15 14:08:23 +01001081 const struct lys_module *prefix_mod, *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001082
1083 assert(nodeid && module && ret);
1084 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1085
1086 id = nodeid;
1087 start = module->data;
1088
1089 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
1090 return ((id - nodeid) - r) + 1;
1091 }
1092 id += r;
1093
1094 if (is_relative) {
1095 return -1;
1096 }
1097
1098 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001099 if (!abs_start_mod) {
1100 return -1;
1101 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001102
1103 while (1) {
1104 sibling = NULL;
1105 while ((sibling = lys_getnext(sibling, lys_parent(start), abs_start_mod, LYS_GETNEXT_WITHCHOICE
1106 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1107 /* name match */
1108 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
1109
1110 /* module check */
1111 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1112 if (!prefix_mod) {
1113 return -1;
1114 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01001115 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001116 continue;
1117 }
1118
1119 /* the result node? */
1120 if (!id[0]) {
1121 if (!(sibling->nodetype & ret_nodetype)) {
1122 /* wrong node type, too bad */
1123 continue;
1124 }
1125 *ret = sibling;
1126 return EXIT_SUCCESS;
1127 }
1128
1129 /* check for shorthand cases - then 'start' does not change */
1130 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1131 || (sibling->nodetype == LYS_CASE)) {
1132 start = sibling->child;
1133 }
1134 break;
1135 }
1136 }
1137
1138 /* no match */
1139 if (!sibling) {
1140 return EXIT_SUCCESS;
1141 }
1142
1143 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
1144 return ((id - nodeid) - r) + 1;
1145 }
1146 id += r;
1147 }
1148
1149 /* cannot get here */
1150 LOGINT;
1151 return -1;
1152}
1153
1154/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES */
1155int
1156resolve_json_absolute_schema_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node **ret)
1157{
1158 char *str;
1159 const char *name, *mod_name, *id;
1160 const struct lys_node *sibling, *start;
1161 int r, nam_len, mod_name_len, is_relative = -1;
1162 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vasko4f0dad02016-02-15 14:08:23 +01001163 const struct lys_module *prefix_mod, *module, *prev_mod = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001164
1165 assert(nodeid && ctx && ret);
1166
1167 id = nodeid;
1168
1169 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
1170 return ((id - nodeid) - r) + 1;
1171 }
1172 id += r;
1173
1174 if (is_relative) {
1175 return -1;
1176 }
1177
Michal Vasko00980152016-02-17 13:10:33 +01001178 str = strndup(mod_name, mod_name_len);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001179 module = ly_ctx_get_module(ctx, str, NULL);
1180 free(str);
1181 if (!module) {
1182 return -1;
1183 }
1184 start = module->data;
1185
1186 while (1) {
1187 sibling = NULL;
1188 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1189 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1190 /* name match */
1191 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
1192
1193 /* module check */
1194 if (mod_name) {
1195 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1196 if (!prefix_mod) {
1197 return -1;
1198 }
1199 } else {
1200 prefix_mod = prev_mod;
1201 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01001202 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001203 continue;
1204 }
1205
1206 /* the result node? */
1207 if (!id[0]) {
1208 *ret = sibling;
1209 return EXIT_SUCCESS;
1210 }
1211
1212 /* check for shorthand cases - then 'start' does not change */
1213 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1214 || (sibling->nodetype == LYS_CASE)) {
1215 start = sibling->child;
1216 }
1217
1218 /* update prev mod */
1219 prev_mod = start->module;
1220 break;
1221 }
1222 }
1223
1224 /* no match */
1225 if (!sibling) {
1226 return EXIT_SUCCESS;
1227 }
1228
1229 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
1230 return ((id - nodeid) - r) + 1;
1231 }
1232 id += r;
1233 }
1234
1235 /* cannot get here */
1236 LOGINT;
1237 return -1;
1238}
1239
1240/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02001241 * @brief Resolves length or range intervals. Does not log.
1242 * Syntax is assumed to be correct, *local_intv MUST be NULL.
1243 *
1244 * @param[in] str_restr The restriction as a string.
1245 * @param[in] type The type of the restriction.
1246 * @param[in] superior_restr Flag whether to check superior
1247 * types.
1248 * @param[out] local_intv The final interval structure.
1249 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001250 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001251 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001252int
Michal Vasko23b61ec2015-08-19 11:19:50 +02001253resolve_len_ran_interval(const char *str_restr, struct lys_type *type, int superior_restr,
1254 struct len_ran_intv** local_intv)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001255{
1256 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001257 int kind, rc = EXIT_SUCCESS;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001258 int64_t local_smin, local_smax;
1259 uint64_t local_umin, local_umax;
1260 long double local_fmin, local_fmax;
1261 const char *seg_ptr, *ptr;
Michal Vaskoe01eca52015-08-13 14:42:02 +02001262 struct len_ran_intv *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001263
1264 switch (type->base) {
1265 case LY_TYPE_BINARY:
1266 kind = 0;
1267 local_umin = 0;
1268 local_umax = 18446744073709551615UL;
1269
1270 if (!str_restr && type->info.binary.length) {
1271 str_restr = type->info.binary.length->expr;
1272 }
1273 break;
1274 case LY_TYPE_DEC64:
1275 kind = 2;
1276 local_fmin = -9223372036854775808.0;
1277 local_fmin /= 1 << type->info.dec64.dig;
1278 local_fmax = 9223372036854775807.0;
1279 local_fmax /= 1 << type->info.dec64.dig;
1280
1281 if (!str_restr && type->info.dec64.range) {
1282 str_restr = type->info.dec64.range->expr;
1283 }
1284 break;
1285 case LY_TYPE_INT8:
1286 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001287 local_smin = __INT64_C(-128);
1288 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001289
1290 if (!str_restr && type->info.num.range) {
1291 str_restr = type->info.num.range->expr;
1292 }
1293 break;
1294 case LY_TYPE_INT16:
1295 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001296 local_smin = __INT64_C(-32768);
1297 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001298
1299 if (!str_restr && type->info.num.range) {
1300 str_restr = type->info.num.range->expr;
1301 }
1302 break;
1303 case LY_TYPE_INT32:
1304 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001305 local_smin = __INT64_C(-2147483648);
1306 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001307
1308 if (!str_restr && type->info.num.range) {
1309 str_restr = type->info.num.range->expr;
1310 }
1311 break;
1312 case LY_TYPE_INT64:
1313 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001314 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
1315 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001316
1317 if (!str_restr && type->info.num.range) {
1318 str_restr = type->info.num.range->expr;
1319 }
1320 break;
1321 case LY_TYPE_UINT8:
1322 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001323 local_umin = __UINT64_C(0);
1324 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001325
1326 if (!str_restr && type->info.num.range) {
1327 str_restr = type->info.num.range->expr;
1328 }
1329 break;
1330 case LY_TYPE_UINT16:
1331 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001332 local_umin = __UINT64_C(0);
1333 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001334
1335 if (!str_restr && type->info.num.range) {
1336 str_restr = type->info.num.range->expr;
1337 }
1338 break;
1339 case LY_TYPE_UINT32:
1340 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001341 local_umin = __UINT64_C(0);
1342 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001343
1344 if (!str_restr && type->info.num.range) {
1345 str_restr = type->info.num.range->expr;
1346 }
1347 break;
1348 case LY_TYPE_UINT64:
1349 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001350 local_umin = __UINT64_C(0);
1351 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001352
1353 if (!str_restr && type->info.num.range) {
1354 str_restr = type->info.num.range->expr;
1355 }
1356 break;
1357 case LY_TYPE_STRING:
1358 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001359 local_umin = __UINT64_C(0);
1360 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001361
1362 if (!str_restr && type->info.str.length) {
1363 str_restr = type->info.str.length->expr;
1364 }
1365 break;
1366 default:
1367 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001368 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001369 }
1370
1371 /* process superior types */
1372 if (type->der && superior_restr) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001373 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
1374 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001375 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001376 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001377 assert(!intv || (intv->kind == kind));
1378 }
1379
1380 if (!str_restr) {
1381 /* we are validating data and not have any restriction, but a superior type might have */
1382 if (type->der && !superior_restr && !intv) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001383 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
1384 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001385 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001386 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001387 assert(!intv || (intv->kind == kind));
1388 }
1389 *local_intv = intv;
1390 return EXIT_SUCCESS;
1391 }
1392
1393 /* adjust local min and max */
1394 if (intv) {
1395 tmp_intv = intv;
1396
1397 if (kind == 0) {
1398 local_umin = tmp_intv->value.uval.min;
1399 } else if (kind == 1) {
1400 local_smin = tmp_intv->value.sval.min;
1401 } else if (kind == 2) {
1402 local_fmin = tmp_intv->value.fval.min;
1403 }
1404
1405 while (tmp_intv->next) {
1406 tmp_intv = tmp_intv->next;
1407 }
1408
1409 if (kind == 0) {
1410 local_umax = tmp_intv->value.uval.max;
1411 } else if (kind == 1) {
1412 local_smax = tmp_intv->value.sval.max;
1413 } else if (kind == 2) {
1414 local_fmax = tmp_intv->value.fval.max;
1415 }
1416 }
1417
1418 /* finally parse our restriction */
1419 seg_ptr = str_restr;
1420 while (1) {
Michal Vaskoe01eca52015-08-13 14:42:02 +02001421 if (!*local_intv && !tmp_local_intv) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001422 *local_intv = malloc(sizeof **local_intv);
1423 tmp_local_intv = *local_intv;
1424 } else {
1425 tmp_local_intv->next = malloc(sizeof **local_intv);
1426 tmp_local_intv = tmp_local_intv->next;
1427 }
Michal Vasko253035f2015-12-17 16:58:13 +01001428 if (!tmp_local_intv) {
1429 LOGMEM;
1430 return -1;
1431 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001432
1433 tmp_local_intv->kind = kind;
1434 tmp_local_intv->next = NULL;
1435
1436 /* min */
1437 ptr = seg_ptr;
1438 while (isspace(ptr[0])) {
1439 ++ptr;
1440 }
1441 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1442 if (kind == 0) {
1443 tmp_local_intv->value.uval.min = atoll(ptr);
1444 } else if (kind == 1) {
1445 tmp_local_intv->value.sval.min = atoll(ptr);
1446 } else if (kind == 2) {
1447 tmp_local_intv->value.fval.min = atoll(ptr);
1448 }
1449
1450 if ((ptr[0] == '+') || (ptr[0] == '-')) {
1451 ++ptr;
1452 }
1453 while (isdigit(ptr[0])) {
1454 ++ptr;
1455 }
1456 } else if (!strncmp(ptr, "min", 3)) {
1457 if (kind == 0) {
1458 tmp_local_intv->value.uval.min = local_umin;
1459 } else if (kind == 1) {
1460 tmp_local_intv->value.sval.min = local_smin;
1461 } else if (kind == 2) {
1462 tmp_local_intv->value.fval.min = local_fmin;
1463 }
1464
1465 ptr += 3;
1466 } else if (!strncmp(ptr, "max", 3)) {
1467 if (kind == 0) {
1468 tmp_local_intv->value.uval.min = local_umax;
1469 } else if (kind == 1) {
1470 tmp_local_intv->value.sval.min = local_smax;
1471 } else if (kind == 2) {
1472 tmp_local_intv->value.fval.min = local_fmax;
1473 }
1474
1475 ptr += 3;
1476 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001477 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001478 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001479 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001480 }
1481
1482 while (isspace(ptr[0])) {
1483 ptr++;
1484 }
1485
1486 /* no interval or interval */
1487 if ((ptr[0] == '|') || !ptr[0]) {
1488 if (kind == 0) {
1489 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
1490 } else if (kind == 1) {
1491 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
1492 } else if (kind == 2) {
1493 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
1494 }
1495 } else if (!strncmp(ptr, "..", 2)) {
1496 /* skip ".." */
1497 ptr += 2;
1498 while (isspace(ptr[0])) {
1499 ++ptr;
1500 }
1501
1502 /* max */
1503 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1504 if (kind == 0) {
1505 tmp_local_intv->value.uval.max = atoll(ptr);
1506 } else if (kind == 1) {
1507 tmp_local_intv->value.sval.max = atoll(ptr);
1508 } else if (kind == 2) {
1509 tmp_local_intv->value.fval.max = atoll(ptr);
1510 }
1511 } else if (!strncmp(ptr, "max", 3)) {
1512 if (kind == 0) {
1513 tmp_local_intv->value.uval.max = local_umax;
1514 } else if (kind == 1) {
1515 tmp_local_intv->value.sval.max = local_smax;
1516 } else if (kind == 2) {
1517 tmp_local_intv->value.fval.max = local_fmax;
1518 }
1519 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001520 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001521 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001522 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001523 }
1524 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001525 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001526 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001527 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001528 }
1529
1530 /* next segment (next OR) */
1531 seg_ptr = strchr(seg_ptr, '|');
1532 if (!seg_ptr) {
1533 break;
1534 }
1535 seg_ptr++;
1536 }
1537
1538 /* check local restrictions against superior ones */
1539 if (intv) {
1540 tmp_intv = intv;
1541 tmp_local_intv = *local_intv;
1542
1543 while (tmp_local_intv && tmp_intv) {
1544 /* reuse local variables */
1545 if (kind == 0) {
1546 local_umin = tmp_local_intv->value.uval.min;
1547 local_umax = tmp_local_intv->value.uval.max;
1548
1549 /* it must be in this interval */
1550 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
1551 /* this interval is covered, next one */
1552 if (local_umax <= tmp_intv->value.uval.max) {
1553 tmp_local_intv = tmp_local_intv->next;
1554 continue;
1555 /* ascending order of restrictions -> fail */
1556 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001557 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001558 goto cleanup;
1559 }
1560 }
1561 } else if (kind == 1) {
1562 local_smin = tmp_local_intv->value.sval.min;
1563 local_smax = tmp_local_intv->value.sval.max;
1564
1565 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
1566 if (local_smax <= tmp_intv->value.sval.max) {
1567 tmp_local_intv = tmp_local_intv->next;
1568 continue;
1569 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001570 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001571 goto cleanup;
1572 }
1573 }
1574 } else if (kind == 2) {
1575 local_fmin = tmp_local_intv->value.fval.min;
1576 local_fmax = tmp_local_intv->value.fval.max;
1577
1578 if ((local_fmin >= tmp_intv->value.fval.min) && (local_fmin <= tmp_intv->value.fval.max)) {
1579 if (local_fmax <= tmp_intv->value.fval.max) {
1580 tmp_local_intv = tmp_local_intv->next;
1581 continue;
1582 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001583 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001584 goto cleanup;
1585 }
1586 }
1587 }
1588
1589 tmp_intv = tmp_intv->next;
1590 }
1591
1592 /* some interval left uncovered -> fail */
1593 if (tmp_local_intv) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001594 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001595 }
1596
1597 }
1598
1599cleanup:
1600 while (intv) {
1601 tmp_intv = intv->next;
1602 free(intv);
1603 intv = tmp_intv;
1604 }
1605
1606 /* fail */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001607 if (rc) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001608 while (*local_intv) {
1609 tmp_local_intv = (*local_intv)->next;
1610 free(*local_intv);
1611 *local_intv = tmp_local_intv;
1612 }
1613 }
1614
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001615 return rc;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001616}
1617
Michal Vasko730dfdf2015-08-11 14:48:05 +02001618/**
Michal Vasko88c29542015-11-27 14:57:53 +01001619 * @brief Resolve a typedef, return only resolved typedefs if derived. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001620 *
1621 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02001622 * @param[in] mod_name Typedef name module name.
1623 * @param[in] module Main module.
1624 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001625 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001626 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001627 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001628 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001629int
Michal Vasko1e62a092015-12-01 12:27:20 +01001630resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
1631 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001632{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001633 int i, j;
Radek Krejci1574a8d2015-08-03 14:16:52 +02001634 struct lys_tpdf *tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001635 int tpdf_size;
1636
Michal Vasko1dca6882015-10-22 14:29:42 +02001637 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001638 /* no prefix, try built-in types */
1639 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
1640 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001641 if (ret) {
1642 *ret = ly_types[i].def;
1643 }
1644 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001645 }
1646 }
1647 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02001648 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001649 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02001650 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001651 }
1652 }
1653
Michal Vasko1dca6882015-10-22 14:29:42 +02001654 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001655 /* search in local typedefs */
1656 while (parent) {
1657 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02001658 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02001659 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
1660 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001661 break;
1662
Radek Krejci76512572015-08-04 09:47:08 +02001663 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02001664 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
1665 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001666 break;
1667
Radek Krejci76512572015-08-04 09:47:08 +02001668 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02001669 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
1670 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001671 break;
1672
Radek Krejci76512572015-08-04 09:47:08 +02001673 case LYS_RPC:
Radek Krejcib8048692015-08-05 13:36:34 +02001674 tpdf_size = ((struct lys_node_rpc *)parent)->tpdf_size;
1675 tpdf = ((struct lys_node_rpc *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001676 break;
1677
Radek Krejci76512572015-08-04 09:47:08 +02001678 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02001679 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
1680 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001681 break;
1682
Radek Krejci76512572015-08-04 09:47:08 +02001683 case LYS_INPUT:
1684 case LYS_OUTPUT:
Radek Krejci4608ada2015-08-05 16:04:37 +02001685 tpdf_size = ((struct lys_node_rpc_inout *)parent)->tpdf_size;
1686 tpdf = ((struct lys_node_rpc_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001687 break;
1688
1689 default:
1690 parent = parent->parent;
1691 continue;
1692 }
1693
1694 for (i = 0; i < tpdf_size; i++) {
Michal Vasko88c29542015-11-27 14:57:53 +01001695 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001696 if (ret) {
1697 *ret = &tpdf[i];
1698 }
1699 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001700 }
1701 }
1702
1703 parent = parent->parent;
1704 }
Radek Krejcic071c542016-01-27 14:57:51 +01001705 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001706 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02001707 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02001708 if (!module) {
1709 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001710 }
1711 }
1712
1713 /* search in top level typedefs */
1714 for (i = 0; i < module->tpdf_size; i++) {
Michal Vasko88c29542015-11-27 14:57:53 +01001715 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001716 if (ret) {
1717 *ret = &module->tpdf[i];
1718 }
1719 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001720 }
1721 }
1722
1723 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01001724 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001725 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Michal Vasko88c29542015-11-27 14:57:53 +01001726 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 +02001727 if (ret) {
1728 *ret = &module->inc[i].submodule->tpdf[j];
1729 }
1730 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001731 }
1732 }
1733 }
1734
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001735 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001736}
1737
Michal Vasko1dca6882015-10-22 14:29:42 +02001738/**
1739 * @brief Check the default \p value of the \p type. Logs directly.
1740 *
1741 * @param[in] type Type definition to use.
1742 * @param[in] value Default value to check.
1743 * @param[in] first Whether this is the first resolution try. Affects logging.
1744 * @param[in] line Line in the input file.
1745 *
1746 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
1747 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001748static int
Michal Vasko1dca6882015-10-22 14:29:42 +02001749check_default(struct lys_type *type, const char *value, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001750{
Michal Vasko1dca6882015-10-22 14:29:42 +02001751 struct lyd_node_leaf_list node;
Radek Krejci37b756f2016-01-18 10:15:03 +01001752 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02001753
1754 /* dummy leaf */
1755 node.value_str = value;
1756 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01001757 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01001758 if (!node.schema) {
1759 LOGMEM;
1760 return -1;
1761 }
Michal Vasko1dca6882015-10-22 14:29:42 +02001762 node.schema->name = strdup("default");
Michal Vasko253035f2015-12-17 16:58:13 +01001763 if (!node.schema->name) {
1764 LOGMEM;
1765 return -1;
1766 }
Radek Krejci37b756f2016-01-18 10:15:03 +01001767 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02001768
Radek Krejci37b756f2016-01-18 10:15:03 +01001769 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02001770 if (!type->info.lref.target) {
1771 ret = EXIT_FAILURE;
1772 goto finish;
1773 }
1774 ret = check_default(&type->info.lref.target->type, value, first, line);
1775
1776 } else if ((type->base == LY_TYPE_INST) || (type->base == LY_TYPE_IDENT)) {
1777 /* it was converted to JSON format before, nothing else sensible we can do */
1778
1779 } else {
Radek Krejci37b756f2016-01-18 10:15:03 +01001780 ret = lyp_parse_value(&node, NULL, 1, NULL, line);
Michal Vasko1dca6882015-10-22 14:29:42 +02001781 }
1782
1783finish:
1784 if (node.value_type == LY_TYPE_BITS) {
1785 free(node.value.bit);
1786 }
1787 free((char *)node.schema->name);
1788 free(node.schema);
1789
1790 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001791}
1792
Michal Vasko730dfdf2015-08-11 14:48:05 +02001793/**
1794 * @brief Check a key for mandatory attributes. Logs directly.
1795 *
1796 * @param[in] key The key to check.
1797 * @param[in] flags What flags to check.
1798 * @param[in] list The list of all the keys.
1799 * @param[in] index Index of the key in the key list.
1800 * @param[in] name The name of the keys.
1801 * @param[in] len The name length.
1802 * @param[in] line The line in the input file.
1803 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001804 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001805 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001806static int
Radek Krejciadb57612016-02-16 13:34:34 +01001807check_key(struct lys_node_list *list, int index, const char *name, int len, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001808{
Radek Krejciadb57612016-02-16 13:34:34 +01001809 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001810 char *dup = NULL;
1811 int j;
1812
1813 /* existence */
1814 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02001815 if (name[len] != '\0') {
1816 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01001817 if (!dup) {
1818 LOGMEM;
1819 return -1;
1820 }
Michal Vaskof02e3742015-08-05 16:27:02 +02001821 dup[len] = '\0';
1822 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001823 }
Radek Krejciadb57612016-02-16 13:34:34 +01001824 LOGVAL(LYE_KEY_MISS, line, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001825 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001826 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001827 }
1828
1829 /* uniqueness */
1830 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01001831 if (key == list->keys[j]) {
1832 LOGVAL(LYE_KEY_DUP, line, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001833 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001834 }
1835 }
1836
1837 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02001838 if (key->nodetype != LYS_LEAF) {
Radek Krejciadb57612016-02-16 13:34:34 +01001839 LOGVAL(LYE_KEY_NLEAF, line, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001840 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001841 }
1842
1843 /* type of the leaf is not built-in empty */
1844 if (key->type.base == LY_TYPE_EMPTY) {
Radek Krejciadb57612016-02-16 13:34:34 +01001845 LOGVAL(LYE_KEY_TYPE, line, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001846 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001847 }
1848
1849 /* config attribute is the same as of the list */
Radek Krejciadb57612016-02-16 13:34:34 +01001850 if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
1851 LOGVAL(LYE_KEY_CONFIG, line, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001852 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001853 }
1854
1855 return EXIT_SUCCESS;
1856}
1857
Michal Vasko730dfdf2015-08-11 14:48:05 +02001858/**
Radek Krejci581ce772015-11-10 17:22:40 +01001859 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001860 *
1861 * @param[in] parent The parent node of the unique structure.
1862 * @param[in] uniq_str The value of the unique node.
Michal Vasko184521f2015-09-24 13:14:26 +02001863 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001864 * @param[in] line The line in the input file.
1865 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001866 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001867 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001868int
Radek Krejci581ce772015-11-10 17:22:40 +01001869resolve_unique(struct lys_node *parent, const char *uniq_str, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001870{
Radek Krejci581ce772015-11-10 17:22:40 +01001871 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01001872 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001873
Michal Vasko3edeaf72016-02-11 13:17:43 +01001874 rc = resolve_descendant_schema_nodeid(uniq_str, parent->child, LYS_LEAF, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01001875 if (rc || !leaf) {
Radek Krejci581ce772015-11-10 17:22:40 +01001876 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01001877 LOGVAL(LYE_INARG, line, LY_VLOG_LYS, parent, uniq_str, "unique");
Radek Krejci581ce772015-11-10 17:22:40 +01001878 if (rc == EXIT_FAILURE) {
Radek Krejciadb57612016-02-16 13:34:34 +01001879 LOGVAL(LYE_SPEC, 0, 0, NULL, "Target leaf not found.");
Radek Krejci581ce772015-11-10 17:22:40 +01001880 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001881 }
Radek Krejci581ce772015-11-10 17:22:40 +01001882 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001883 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01001884 if (leaf->nodetype != LYS_LEAF) {
Radek Krejciadb57612016-02-16 13:34:34 +01001885 LOGVAL(LYE_INARG, line, LY_VLOG_LYS, parent, uniq_str, "unique");
1886 LOGVAL(LYE_SPEC, 0, 0, NULL, "Target is not a leaf.");
Radek Krejci581ce772015-11-10 17:22:40 +01001887 rc = -1;
1888 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001889 }
1890
Radek Krejcicf509982015-12-15 09:22:44 +01001891 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01001892 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name,
1893 line, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01001894 return -1;
1895 }
1896
Radek Krejcica7efb72016-01-18 13:06:01 +01001897 /* set leaf's unique flag */
1898 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
1899
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001900 return EXIT_SUCCESS;
1901
1902error:
1903
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001904 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001905}
1906
Michal Vasko730dfdf2015-08-11 14:48:05 +02001907/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02001908 * @brief Resolve (find) a feature definition. Logs directly.
1909 *
1910 * @param[in] name Feature name.
1911 * @param[in] module Module to search in.
Michal Vasko184521f2015-09-24 13:14:26 +02001912 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001913 * @param[in] line The line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001914 * @param[out] ret Pointer to the resolved feature. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001915 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001916 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001917 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001918static int
Michal Vasko1e62a092015-12-01 12:27:20 +01001919resolve_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 +02001920{
Michal Vasko2d851a92015-10-20 16:16:36 +02001921 const char *mod_name, *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02001922 int mod_name_len, nam_len, i, j;
Radek Krejcicf509982015-12-15 09:22:44 +01001923 struct lys_node *node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001924
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001925 assert(id);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001926 assert(module);
1927
1928 /* check prefix */
Michal Vasko2d851a92015-10-20 16:16:36 +02001929 if ((i = parse_node_identifier(id, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01001930 LOGVAL(LYE_INCHAR, line, 0, NULL, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001931 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001932 }
1933
Radek Krejcic071c542016-01-27 14:57:51 +01001934 module = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1935 if (!module) {
1936 /* identity refers unknown data model */
Radek Krejciadb57612016-02-16 13:34:34 +01001937 LOGVAL(LYE_INMOD_LEN, line, 0, NULL, mod_name_len, mod_name);
Radek Krejcic071c542016-01-27 14:57:51 +01001938 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001939 }
1940
Radek Krejcic071c542016-01-27 14:57:51 +01001941 /* search in the identified module ... */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001942 for (j = 0; j < module->features_size; j++) {
1943 if (!strcmp(name, module->features[j].name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001944 if (ret) {
Radek Krejcicf509982015-12-15 09:22:44 +01001945 /* check status */
1946 node = (struct lys_node *)*ret;
Radek Krejcic6556022016-01-27 15:16:45 +01001947 if (lyp_check_status(node->flags, node->module, node->name, module->features[j].flags,
Radek Krejciadb57612016-02-16 13:34:34 +01001948 module->features[j].module, module->features[j].name, line, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01001949 return -1;
1950 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001951 *ret = &module->features[j];
1952 }
1953 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001954 }
1955 }
Radek Krejcic071c542016-01-27 14:57:51 +01001956 /* ... and all its submodules */
Michal Vasko27ab8222016-02-12 09:33:52 +01001957 for (i = 0; i < module->inc_size; i++) {
1958 if (!module->inc[i].submodule) {
1959 /* not yet resolved */
1960 continue;
1961 }
Radek Krejcic071c542016-01-27 14:57:51 +01001962 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
1963 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
1964 if (ret) {
1965 /* check status */
1966 node = (struct lys_node *)*ret;
Radek Krejcic6556022016-01-27 15:16:45 +01001967 if (lyp_check_status(node->flags, node->module, node->name,
Radek Krejcic071c542016-01-27 14:57:51 +01001968 module->inc[i].submodule->features[j].flags,
1969 module->inc[i].submodule->features[j].module,
Radek Krejciadb57612016-02-16 13:34:34 +01001970 module->inc[i].submodule->features[j].name, line, node)) {
Radek Krejcic071c542016-01-27 14:57:51 +01001971 return -1;
1972 }
1973 *ret = &(module->inc[i].submodule->features[j]);
1974 }
1975 return EXIT_SUCCESS;
1976 }
1977 }
1978 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001979
1980 /* not found */
Michal Vasko184521f2015-09-24 13:14:26 +02001981 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01001982 LOGVAL(LYE_INRESOLV, line, 0, NULL, "feature", id);
Michal Vasko184521f2015-09-24 13:14:26 +02001983 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001984 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001985}
1986
Michal Vasko23b61ec2015-08-19 11:19:50 +02001987/* ignores line */
1988static void
1989unres_data_del(struct unres_data *unres, uint32_t i)
1990{
1991 /* there are items after the one deleted */
1992 if (i+1 < unres->count) {
1993 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02001994 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02001995
1996 /* deleting the last item */
1997 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02001998 free(unres->node);
1999 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002000 }
2001
2002 /* if there are no items after and it is not the last one, just move the counter */
2003 --unres->count;
2004}
2005
Michal Vasko0491ab32015-08-19 14:28:29 +02002006/**
2007 * @brief Resolve (find) a data node from a specific module. Does not log.
2008 *
2009 * @param[in] mod Module to search in.
2010 * @param[in] name Name of the data node.
2011 * @param[in] nam_len Length of the name.
2012 * @param[in] start Data node to start the search from.
2013 * @param[in,out] parents Resolved nodes. If there are some parents,
2014 * they are replaced (!!) with the resolvents.
2015 *
2016 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
2017 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002018static int
Michal Vasko1e62a092015-12-01 12:27:20 +01002019resolve_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 +02002020{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002021 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02002022 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002023 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002024
Michal Vasko23b61ec2015-08-19 11:19:50 +02002025 if (!parents->count) {
2026 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002027 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01002028 if (!parents->node) {
2029 LOGMEM;
2030 return EXIT_FAILURE;
2031 }
Michal Vaskocf024702015-10-08 15:01:42 +02002032 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002033 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002034 for (i = 0; i < parents->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002035 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002036 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002037 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002038 continue;
2039 }
2040 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02002041 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002042 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
2043 && node->schema->name[nam_len] == '\0') {
2044 /* matching target */
2045 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02002046 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02002047 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002048 flag = 1;
2049 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02002050 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002051 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01002052 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
2053 if (!parents->node) {
2054 return EXIT_FAILURE;
2055 }
Michal Vaskocf024702015-10-08 15:01:42 +02002056 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002057 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002058 }
2059 }
2060 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002061
2062 if (!flag) {
2063 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002064 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02002065 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002066 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02002067 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002068 }
2069
Michal Vasko0491ab32015-08-19 14:28:29 +02002070 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02002071}
2072
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002073/**
2074 * @brief Resolve (find) a data node. Does not log.
2075 *
Radek Krejci581ce772015-11-10 17:22:40 +01002076 * @param[in] mod_name Module name of the data node.
2077 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002078 * @param[in] name Name of the data node.
2079 * @param[in] nam_len Length of the name.
2080 * @param[in] start Data node to start the search from.
2081 * @param[in,out] parents Resolved nodes. If there are some parents,
2082 * they are replaced (!!) with the resolvents.
2083 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002084 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002085 */
Radek Krejcic5090c32015-08-12 09:46:19 +02002086static int
Radek Krejci581ce772015-11-10 17:22:40 +01002087resolve_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 +02002088 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02002089{
Michal Vasko1e62a092015-12-01 12:27:20 +01002090 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02002091 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02002092
Michal Vasko23b61ec2015-08-19 11:19:50 +02002093 assert(start);
2094
Michal Vasko31fc3672015-10-21 12:08:13 +02002095 if (mod_name) {
2096 /* we have mod_name, find appropriate module */
2097 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01002098 if (!str) {
2099 LOGMEM;
2100 return -1;
2101 }
Michal Vasko31fc3672015-10-21 12:08:13 +02002102 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
2103 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02002104 if (!mod) {
2105 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002106 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02002107 }
2108 } else {
2109 /* no prefix, module is the same as of current node */
2110 mod = start->schema->module;
2111 }
2112
2113 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002114}
2115
Michal Vasko730dfdf2015-08-11 14:48:05 +02002116/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002117 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Michal Vaskod9173342015-08-17 14:35:36 +02002118 * only specific errors, general no-resolvent error is left to the caller,
2119 * but line fail is always displayed.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002120 *
Michal Vaskobb211122015-08-19 14:03:11 +02002121 * @param[in] pred Predicate to use.
Michal Vasko184521f2015-09-24 13:14:26 +02002122 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko0491ab32015-08-19 14:28:29 +02002123 * @param[in] line Line in the input file.
Radek Krejciadb57612016-02-16 13:34:34 +01002124 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02002125 * @param[in,out] node_match Nodes satisfying the restriction
2126 * without the predicate. Nodes not
2127 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02002128 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002129 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002130 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002131 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002132static int
Radek Krejciadb57612016-02-16 13:34:34 +01002133resolve_path_predicate_data(const char *pred, int first, uint32_t line,struct lyd_node *node,
2134 struct unres_data *node_match, int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002135{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002136 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002137 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002138 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02002139 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
2140 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002141 uint32_t j;
2142
2143 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002144 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002145 if (!source_match.node) {
2146 LOGMEM;
2147 return -1;
2148 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002149 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002150 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002151 if (!dest_match.node) {
2152 LOGMEM;
2153 return -1;
2154 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002155
2156 do {
2157 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
2158 &pke_len, &has_predicate)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002159 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002160 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002161 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002162 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002163 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002164 pred += i;
2165
Michal Vasko23b61ec2015-08-19 11:19:50 +02002166 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002167 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02002168 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02002169
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002170 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01002171 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02002172 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002173 /* general error, the one written later will suffice */
Michal Vasko184521f2015-09-24 13:14:26 +02002174 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002175 LOGVAL(LYE_LINE, line, 0, NULL);
Michal Vasko184521f2015-09-24 13:14:26 +02002176 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002177 i = 0;
2178 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002179 }
2180
2181 /* destination */
Michal Vaskocf024702015-10-08 15:01:42 +02002182 dest_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02002183 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002184 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2185 &dest_parent_times)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002186 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002187 rc = -1;
2188 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002189 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002190 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002191 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02002192 dest_match.node[0] = dest_match.node[0]->parent;
2193 if (!dest_match.node[0]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002194 /* general error, the one written later will suffice */
Michal Vasko184521f2015-09-24 13:14:26 +02002195 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002196 LOGVAL(LYE_LINE, line, 0, NULL);
Michal Vasko184521f2015-09-24 13:14:26 +02002197 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002198 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02002199 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002200 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002201 }
2202 }
2203 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01002204 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02002205 &dest_match)) || (dest_match.count != 1)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002206 /* general error, the one written later will suffice */
Michal Vasko184521f2015-09-24 13:14:26 +02002207 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002208 LOGVAL(LYE_LINE, line, 0, NULL);
Michal Vasko184521f2015-09-24 13:14:26 +02002209 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002210 i = 0;
2211 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002212 }
2213
2214 if (pke_len == pke_parsed) {
2215 break;
2216 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002217 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 +02002218 &dest_parent_times)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002219 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002220 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002221 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002222 }
2223 pke_parsed += i;
2224 }
2225
2226 /* check match between source and destination nodes */
Michal Vaskocf024702015-10-08 15:01:42 +02002227 if (((struct lys_node_leaf *)source_match.node[0]->schema)->type.base
2228 != ((struct lys_node_leaf *)dest_match.node[0]->schema)->type.base) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002229 goto remove_leafref;
2230 }
2231
Radek Krejcic1ffa4d2016-02-17 13:11:11 +01002232 if (!ly_strequal(((struct lyd_node_leaf_list *)source_match.node[0])->value_str,
Radek Krejci749190d2016-02-18 16:26:25 +01002233 ((struct lyd_node_leaf_list *)dest_match.node[0])->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002234 goto remove_leafref;
2235 }
2236
2237 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002238 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002239 continue;
2240
2241remove_leafref:
2242 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002243 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002244 }
2245 } while (has_predicate);
2246
Michal Vaskocf024702015-10-08 15:01:42 +02002247 free(source_match.node);
2248 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02002249 if (parsed) {
2250 *parsed = parsed_loc;
2251 }
2252 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002253
2254error:
2255
2256 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002257 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002258 }
2259 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002260 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002261 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002262 if (parsed) {
2263 *parsed = -parsed_loc+i;
2264 }
2265 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002266}
2267
Michal Vasko730dfdf2015-08-11 14:48:05 +02002268/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002269 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002270 *
Michal Vaskocf024702015-10-08 15:01:42 +02002271 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02002272 * @param[in] path Path of the leafref.
Michal Vasko184521f2015-09-24 13:14:26 +02002273 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko23b61ec2015-08-19 11:19:50 +02002274 * @param[in] line Line in the input file.
Michal Vaskobb211122015-08-19 14:03:11 +02002275 * @param[out] ret Matching nodes. Expects an empty, but allocated structure. Lines left untouched.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002276 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002277 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002278 */
Michal Vasko184521f2015-09-24 13:14:26 +02002279static int
Michal Vaskocf024702015-10-08 15:01:42 +02002280resolve_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 +02002281{
Radek Krejci71b795b2015-08-10 16:20:39 +02002282 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002283 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02002284 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002285 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002286
Michal Vaskocf024702015-10-08 15:01:42 +02002287 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002288
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002289 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02002290 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002291
2292 /* searching for nodeset */
2293 do {
2294 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002295 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002296 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002297 goto error;
2298 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002299 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002300 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002301
Michal Vasko23b61ec2015-08-19 11:19:50 +02002302 if (!ret->count) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02002303 if (parent_times != -1) {
2304 ret->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002305 ret->node = calloc(1, sizeof *ret->node);
Michal Vasko253035f2015-12-17 16:58:13 +01002306 if (!ret->node) {
2307 LOGMEM;
Radek Krejci50501732016-01-07 13:06:39 +01002308 rc = -1;
Michal Vasko253035f2015-12-17 16:58:13 +01002309 goto error;
2310 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02002311 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002312 for (i = 0; i < parent_times; ++i) {
2313 /* relative path */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002314 if (!ret->count) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002315 /* error, too many .. */
Radek Krejciadb57612016-02-16 13:34:34 +01002316 LOGVAL(LYE_INVAL, line, LY_VLOG_LYD, node, path, node->schema->name);
Michal Vasko0491ab32015-08-19 14:28:29 +02002317 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002318 goto error;
Michal Vaskocf024702015-10-08 15:01:42 +02002319 } else if (!ret->node[0]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002320 /* first .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002321 data = ret->node[0] = node->parent;
2322 } else if (!ret->node[0]->parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002323 /* we are in root */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002324 ret->count = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02002325 free(ret->node);
2326 ret->node = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002327 } else {
2328 /* multiple .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002329 data = ret->node[0] = ret->node[0]->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002330 }
2331 }
2332
2333 /* absolute path */
2334 if (parent_times == -1) {
Michal Vaskocf024702015-10-08 15:01:42 +02002335 for (data = node; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02002336 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko8bcdf292015-08-19 14:04:43 +02002337 if (data->prev) {
2338 for (; data->prev->next; data = data->prev);
2339 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002340 }
2341 }
2342
2343 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01002344 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Michal Vasko184521f2015-09-24 13:14:26 +02002345 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002346 LOGVAL(LYE_INELEM_LEN, line, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02002347 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002348 goto error;
2349 }
2350
2351 if (has_predicate) {
2352 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002353 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002354 if (ret->node[j]->schema->nodetype == LYS_LIST &&
2355 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002356 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002357 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002358 continue;
2359 }
2360
2361 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002362 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002363 }
Radek Krejciadb57612016-02-16 13:34:34 +01002364 if ((rc = resolve_path_predicate_data(path, first, line, node, ret, &i))) {
Michal Vaskod9173342015-08-17 14:35:36 +02002365 /* line was already displayed */
Michal Vasko184521f2015-09-24 13:14:26 +02002366 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002367 LOGVAL(LYE_NORESOLV, 0, LY_VLOG_LYD, node, path);
Michal Vasko184521f2015-09-24 13:14:26 +02002368 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002369 goto error;
2370 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002371 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002372 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002373
Michal Vasko23b61ec2015-08-19 11:19:50 +02002374 if (!ret->count) {
Michal Vasko184521f2015-09-24 13:14:26 +02002375 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002376 LOGVAL(LYE_NORESOLV, line, LY_VLOG_LYD, node, path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02002377 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002378 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002379 goto error;
2380 }
2381 }
2382 } while (path[0] != '\0');
2383
Michal Vaskof02e3742015-08-05 16:27:02 +02002384 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002385
2386error:
2387
Michal Vaskocf024702015-10-08 15:01:42 +02002388 free(ret->node);
2389 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002390 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002391
Michal Vasko0491ab32015-08-19 14:28:29 +02002392 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002393}
2394
Michal Vasko730dfdf2015-08-11 14:48:05 +02002395/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002396 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002397 *
Michal Vaskobb211122015-08-19 14:03:11 +02002398 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01002399 * @param[in] context_node Predicate context node (where the predicate is placed).
2400 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vasko184521f2015-09-24 13:14:26 +02002401 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002402 * @param[in] line Line in the input file.
2403 *
Michal Vasko184521f2015-09-24 13:14:26 +02002404 * @return 0 on forward reference, otherwise the number
2405 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002406 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002407 */
Michal Vasko1f76a282015-08-04 16:16:53 +02002408static int
Radek Krejciadb57612016-02-16 13:34:34 +01002409resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
2410 struct lys_node *parent, int first, uint32_t line)
Michal Vasko1f76a282015-08-04 16:16:53 +02002411{
Michal Vasko1e62a092015-12-01 12:27:20 +01002412 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02002413 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
2414 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 +02002415 int has_predicate, dest_parent_times = 0, i, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002416
2417 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002418 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02002419 &pke_len, &has_predicate)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002420 LOGVAL(LYE_INCHAR, line, parent ? LY_VLOG_LYS : 0, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002421 return -parsed+i;
2422 }
2423 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02002424 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02002425
Michal Vasko58090902015-08-13 14:04:15 +02002426 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01002427 if (!sour_pref) {
Radek Krejciadb57612016-02-16 13:34:34 +01002428 sour_pref = context_node->module->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01002429 }
Radek Krejciadb57612016-02-16 13:34:34 +01002430 rc = lys_get_sibling(context_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02002431 LYS_LEAF | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002432 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02002433 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002434 LOGVAL(LYE_NORESOLV, line, parent ? LY_VLOG_LYS : 0, parent, path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02002435 }
2436 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002437 }
2438
2439 /* destination */
2440 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2441 &dest_parent_times)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002442 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 +02002443 return -parsed;
2444 }
2445 pke_parsed += i;
2446
Radek Krejciadb57612016-02-16 13:34:34 +01002447 /* parent is actually the parent of this leaf, so skip the first ".." */
2448 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002449 if (!dst_node) {
Radek Krejciadb57612016-02-16 13:34:34 +01002450 LOGVAL(LYE_NORESOLV, line, parent ? LY_VLOG_LYS : 0, parent, path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02002451 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002452 }
Radek Krejciadb57612016-02-16 13:34:34 +01002453 dst_node = dst_node->parent;
Michal Vasko1f76a282015-08-04 16:16:53 +02002454 }
2455 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01002456 if (!dest_pref) {
2457 dest_pref = dst_node->module->name;
2458 }
2459 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02002460 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002461 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02002462 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002463 LOGVAL(LYE_NORESOLV, line, parent ? LY_VLOG_LYS : 0, parent, path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02002464 }
2465 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002466 }
2467
2468 if (pke_len == pke_parsed) {
2469 break;
2470 }
2471
2472 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
2473 &dest_parent_times)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002474 LOGVAL(LYE_INCHAR, line, parent ? LY_VLOG_LYS : 0, parent,
2475 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002476 return -parsed;
2477 }
2478 pke_parsed += i;
2479 }
2480
2481 /* check source - dest match */
Michal Vasko184521f2015-09-24 13:14:26 +02002482 if (dst_node->nodetype != LYS_LEAF) {
Radek Krejciadb57612016-02-16 13:34:34 +01002483 LOGVAL(LYE_NORESOLV, line, parent ? LY_VLOG_LYS : 0, parent, path-parsed);
2484 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 +02002485 return -parsed;
2486 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002487 } while (has_predicate);
2488
2489 return parsed;
2490}
2491
Michal Vasko730dfdf2015-08-11 14:48:05 +02002492/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002493 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002494 *
Michal Vaskobb211122015-08-19 14:03:11 +02002495 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002496 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01002497 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
2498 * has to contain absolute path
Michal Vasko184521f2015-09-24 13:14:26 +02002499 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002500 * @param[in] line Line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002501 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002502 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002503 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002504 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002505static int
Radek Krejciadb57612016-02-16 13:34:34 +01002506resolve_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 +01002507 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02002508{
Michal Vasko1e62a092015-12-01 12:27:20 +01002509 const struct lys_node *node;
Radek Krejcic071c542016-01-27 14:57:51 +01002510 const struct lys_module *mod;
Michal Vasko1f76a282015-08-04 16:16:53 +02002511 const char *id, *prefix, *name;
2512 int pref_len, nam_len, parent_times, has_predicate;
Michal Vasko184521f2015-09-24 13:14:26 +02002513 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002514
Michal Vasko184521f2015-09-24 13:14:26 +02002515 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002516 parent_times = 0;
2517 id = path;
2518
2519 do {
2520 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002521 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 +02002522 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002523 }
2524 id += i;
2525
Michal Vasko184521f2015-09-24 13:14:26 +02002526 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002527 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01002528 /* resolve prefix of the module */
Radek Krejciadb57612016-02-16 13:34:34 +01002529 mod = lys_get_import_module(parent->module, NULL, 0, prefix, pref_len);
Radek Krejcic071c542016-01-27 14:57:51 +01002530 /* get start node */
2531 node = mod ? mod->data : NULL;
Michal Vasko58090902015-08-13 14:04:15 +02002532 if (!node) {
Michal Vasko184521f2015-09-24 13:14:26 +02002533 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002534 LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko184521f2015-09-24 13:14:26 +02002535 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002536 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02002537 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002538 } else if (parent_times > 0) {
Michal Vasko73ae2562015-08-06 11:58:13 +02002539 /* node is the parent already, skip one ".." */
Radek Krejci2f12f852016-01-08 12:59:57 +01002540 if (parent_tpdf) {
2541 /* the path is not allowed to contain relative path since we are in top level typedef */
Radek Krejciadb57612016-02-16 13:34:34 +01002542 LOGVAL(LYE_NORESOLV, line, 0, NULL, path);
Radek Krejci2f12f852016-01-08 12:59:57 +01002543 return -1;
2544 }
2545
Radek Krejciadb57612016-02-16 13:34:34 +01002546 node = parent;
Michal Vasko58090902015-08-13 14:04:15 +02002547 i = 0;
2548 while (1) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002549 if (!node) {
Michal Vasko184521f2015-09-24 13:14:26 +02002550 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002551 LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko184521f2015-09-24 13:14:26 +02002552 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002553 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02002554 }
Michal Vasko58090902015-08-13 14:04:15 +02002555
2556 /* this node is a wrong node, we actually need the augment target */
2557 if (node->nodetype == LYS_AUGMENT) {
2558 node = ((struct lys_node_augment *)node)->target;
2559 if (!node) {
2560 continue;
2561 }
2562 }
2563
2564 ++i;
2565 if (i == parent_times) {
2566 break;
2567 }
2568 node = node->parent;
Michal Vasko1f76a282015-08-04 16:16:53 +02002569 }
Michal Vasko36cbaa42015-12-14 13:15:48 +01002570
Michal Vasko1f76a282015-08-04 16:16:53 +02002571 node = node->child;
Michal Vaskoe01eca52015-08-13 14:42:02 +02002572 } else {
2573 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002574 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002575 }
Michal Vasko36cbaa42015-12-14 13:15:48 +01002576
Michal Vasko184521f2015-09-24 13:14:26 +02002577 first_iter = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002578 } else {
2579 node = node->child;
2580 }
2581
Michal Vasko4f0dad02016-02-15 14:08:23 +01002582 if (!prefix) {
Radek Krejciadb57612016-02-16 13:34:34 +01002583 prefix = lys_node_module(parent)->name;
Michal Vasko4f0dad02016-02-15 14:08:23 +01002584 }
2585
Michal Vasko36cbaa42015-12-14 13:15:48 +01002586 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 +02002587 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02002588 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002589 LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko184521f2015-09-24 13:14:26 +02002590 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002591 return rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002592 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002593
2594 if (has_predicate) {
2595 /* we have predicate, so the current result must be list */
2596 if (node->nodetype != LYS_LIST) {
Radek Krejciadb57612016-02-16 13:34:34 +01002597 LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002598 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002599 }
2600
Radek Krejciadb57612016-02-16 13:34:34 +01002601 i = resolve_path_predicate_schema(id, node, parent, first, line);
Michal Vasko184521f2015-09-24 13:14:26 +02002602 if (!i) {
Michal Vaskof9664da2015-08-24 15:03:30 +02002603 return EXIT_FAILURE;
Michal Vasko184521f2015-09-24 13:14:26 +02002604 } else if (i < 0) {
2605 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002606 }
2607 id += i;
2608 }
2609 } while (id[0]);
2610
Radek Krejcib1c12512015-08-11 11:22:04 +02002611 /* the target must be leaf or leaf-list */
2612 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Radek Krejciadb57612016-02-16 13:34:34 +01002613 LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002614 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02002615 }
2616
Radek Krejcicf509982015-12-15 09:22:44 +01002617 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01002618 if (lyp_check_status(parent->flags, parent->module, parent->name,
2619 node->flags, node->module, node->name, line, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01002620 return -1;
2621 }
2622
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002623 if (ret) {
2624 *ret = node;
2625 }
2626 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02002627}
2628
Michal Vasko730dfdf2015-08-11 14:48:05 +02002629/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002630 * @brief Resolve instance-identifier predicate in JSON data format.
2631 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002632 *
Michal Vaskobb211122015-08-19 14:03:11 +02002633 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002634 * @param[in,out] node_match Nodes matching the restriction without
2635 * the predicate. Nodes not satisfying
2636 * the predicate are removed.
2637 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002638 * @return Number of characters successfully parsed,
2639 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002640 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002641static int
Michal Vaskof39142b2015-10-21 11:40:05 +02002642resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002643{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002644 /* ... /node[target = value] ... */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002645 struct unres_data target_match;
2646 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +01002647 const struct lys_module *mod;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002648 const char *model, *name, *value;
2649 char *str;
2650 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed;
2651 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002652
Michal Vasko1f2cc332015-08-19 11:18:32 +02002653 assert(pred && node_match->count);
2654
Michal Vaskocf024702015-10-08 15:01:42 +02002655 ctx = node_match->node[0]->schema->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002656 idx = -1;
2657 parsed = 0;
2658
2659 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02002660 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002661 return -parsed+i;
2662 }
2663 parsed += i;
2664 pred += i;
2665
Michal Vasko1f2cc332015-08-19 11:18:32 +02002666 /* pos */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002667 if (isdigit(name[0])) {
2668 idx = atoi(name);
2669 }
2670
Michal Vasko1f2cc332015-08-19 11:18:32 +02002671 for (cur_idx = 0, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002672 /* target */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002673 memset(&target_match, 0, sizeof target_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002674 if ((name[0] == '.') || !value) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002675 target_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002676 target_match.node = malloc(sizeof *target_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002677 if (!target_match.node) {
2678 LOGMEM;
2679 return -1;
2680 }
Michal Vaskocf024702015-10-08 15:01:42 +02002681 target_match.node[0] = node_match->node[j];
Michal Vasko1f2cc332015-08-19 11:18:32 +02002682 } else {
2683 str = strndup(model, mod_len);
2684 mod = ly_ctx_get_module(ctx, str, NULL);
2685 free(str);
2686
Radek Krejci804836a2016-02-03 10:39:55 +01002687 if (resolve_data(mod, name, nam_len, node_match->node[j]->child, &target_match)) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002688 goto remove_instid;
2689 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002690 }
2691
2692 /* check that we have the correct type */
2693 if (name[0] == '.') {
Michal Vaskocf024702015-10-08 15:01:42 +02002694 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002695 goto remove_instid;
2696 }
2697 } else if (value) {
Michal Vaskocf024702015-10-08 15:01:42 +02002698 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002699 goto remove_instid;
2700 }
2701 }
2702
Michal Vasko83a6c462015-10-08 16:43:53 +02002703 if ((value && (strncmp(((struct lyd_node_leaf_list *)target_match.node[0])->value_str, value, val_len)
2704 || ((struct lyd_node_leaf_list *)target_match.node[0])->value_str[val_len]))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002705 || (!value && (idx != cur_idx))) {
2706 goto remove_instid;
2707 }
2708
Michal Vaskocf024702015-10-08 15:01:42 +02002709 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002710
2711 /* leafref is ok, continue check with next leafref */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002712 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002713 continue;
2714
2715remove_instid:
Michal Vaskocf024702015-10-08 15:01:42 +02002716 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002717
2718 /* does not fulfill conditions, remove leafref record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002719 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002720 }
2721 } while (has_predicate);
2722
2723 return parsed;
2724}
2725
Michal Vasko730dfdf2015-08-11 14:48:05 +02002726/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002727 * @brief Resolve instance-identifier in JSON data format. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002728 *
Radek Krejciadb57612016-02-16 13:34:34 +01002729 * @param[in] data Data node where the path is used
Michal Vasko730dfdf2015-08-11 14:48:05 +02002730 * @param[in] path Instance-identifier node value.
Radek Krejcic5090c32015-08-12 09:46:19 +02002731 * @param[in] line Source line for error messages.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002732 *
Radek Krejcic5090c32015-08-12 09:46:19 +02002733 * @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 +02002734 */
Michal Vasko184521f2015-09-24 13:14:26 +02002735static struct lyd_node *
Michal Vaskof39142b2015-10-21 11:40:05 +02002736resolve_instid(struct lyd_node *data, const char *path, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002737{
Radek Krejcic5090c32015-08-12 09:46:19 +02002738 int i = 0, j;
2739 struct lyd_node *result = NULL;
Michal Vasko1e62a092015-12-01 12:27:20 +01002740 const struct lys_module *mod = NULL;
Radek Krejcic5090c32015-08-12 09:46:19 +02002741 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002742 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02002743 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002744 int mod_len, name_len, has_predicate;
2745 struct unres_data node_match;
2746 uint32_t k;
2747
2748 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002749
Radek Krejcic5090c32015-08-12 09:46:19 +02002750 /* we need root to resolve absolute path */
2751 for (; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02002752 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko0491ab32015-08-19 14:28:29 +02002753 if (data->prev) {
2754 for (; data->prev->next; data = data->prev);
2755 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002756
Radek Krejcic5090c32015-08-12 09:46:19 +02002757 /* search for the instance node */
2758 while (path[i]) {
Michal Vaskof39142b2015-10-21 11:40:05 +02002759 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02002760 if (j <= 0) {
Radek Krejciadb57612016-02-16 13:34:34 +01002761 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002762 goto error;
2763 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002764 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02002765
Michal Vasko1f2cc332015-08-19 11:18:32 +02002766 str = strndup(model, mod_len);
Michal Vasko253035f2015-12-17 16:58:13 +01002767 if (!str) {
2768 LOGMEM;
2769 goto error;
2770 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02002771 mod = ly_ctx_get_module(ctx, str, NULL);
2772 free(str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002773
Radek Krejcic5090c32015-08-12 09:46:19 +02002774 if (!mod) {
2775 /* no instance exists */
2776 return NULL;
2777 }
2778
Michal Vasko1f2cc332015-08-19 11:18:32 +02002779 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002780 /* no instance exists */
2781 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002782 }
2783
2784 if (has_predicate) {
2785 /* we have predicate, so the current results must be list or leaf-list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002786 for (k = 0; k < node_match.count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002787 if ((node_match.node[k]->schema->nodetype == LYS_LIST &&
2788 ((struct lys_node_list *)node_match.node[k]->schema)->keys)
2789 || (node_match.node[k]->schema->nodetype == LYS_LEAFLIST)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002790 /* instid is ok, continue check with next instid */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002791 ++k;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002792 continue;
2793 }
2794
2795 /* does not fulfill conditions, remove inst record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002796 unres_data_del(&node_match, k);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002797 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002798
Michal Vaskof39142b2015-10-21 11:40:05 +02002799 j = resolve_predicate(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02002800 if (j < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002801 LOGVAL(LYE_INPRED, line, LY_VLOG_LYD, data, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002802 goto error;
2803 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02002804 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02002805
Michal Vasko1f2cc332015-08-19 11:18:32 +02002806 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002807 /* no instance exists */
2808 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002809 }
2810 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002811 }
2812
Michal Vasko1f2cc332015-08-19 11:18:32 +02002813 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002814 /* no instance exists */
2815 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002816 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002817 /* instance identifier must resolve to a single node */
Radek Krejciadb57612016-02-16 13:34:34 +01002818 LOGVAL(LYE_TOOMANY, line, LY_VLOG_LYD, data, path, "data tree");
Radek Krejcic5090c32015-08-12 09:46:19 +02002819
2820 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02002821 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02002822
2823 return NULL;
2824 } else {
2825 /* we have required result, remember it and cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02002826 result = node_match.node[0];
2827 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02002828
2829 return result;
2830 }
2831
2832error:
2833
2834 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02002835 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02002836
2837 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002838}
2839
Michal Vasko730dfdf2015-08-11 14:48:05 +02002840/**
2841 * @brief Passes config flag down to children. Does not log.
2842 *
2843 * @param[in] node Parent node.
2844 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002845static void
Radek Krejci1d82ef62015-08-07 14:44:40 +02002846inherit_config_flag(struct lys_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002847{
Radek Krejci1d82ef62015-08-07 14:44:40 +02002848 LY_TREE_FOR(node, node) {
2849 node->flags |= node->parent->flags & LYS_CONFIG_MASK;
2850 inherit_config_flag(node->child);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002851 }
2852}
2853
Michal Vasko730dfdf2015-08-11 14:48:05 +02002854/**
Michal Vasko7178e692016-02-12 15:58:05 +01002855 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002856 *
Michal Vaskobb211122015-08-19 14:03:11 +02002857 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01002858 * @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 +01002859 * @param[in] first Whether this is the first resolution try.
2860 * @param[in] line Line in the input file.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002861 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002862 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002863 */
Michal Vasko7178e692016-02-12 15:58:05 +01002864static int
2865resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002866{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002867 int rc;
Michal Vasko1d87a922015-08-21 12:57:16 +02002868 struct lys_node *sub;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002869
Michal Vasko1d87a922015-08-21 12:57:16 +02002870 assert(aug);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002871
2872 /* resolve target node */
Michal Vasko3edeaf72016-02-11 13:17:43 +01002873 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 +01002874 if (rc == -1) {
2875 return -1;
2876 }
2877 if (rc > 0) {
Radek Krejciadb57612016-02-16 13:34:34 +01002878 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 +01002879 return -1;
2880 }
2881 if (!aug->target) {
Michal Vasko7178e692016-02-12 15:58:05 +01002882 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002883 LOGVAL(LYE_INRESOLV, line, LY_VLOG_LYS, aug, "augment", aug->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01002884 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002885 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002886 }
2887
2888 if (!aug->child) {
2889 /* nothing to do */
Michal Vasko1d87a922015-08-21 12:57:16 +02002890 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002891 return EXIT_SUCCESS;
2892 }
2893
2894 /* inherit config information from parent, augment does not have
2895 * config property, but we need to keep the information for subelements
2896 */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002897 aug->flags |= aug->target->flags & LYS_CONFIG_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002898 LY_TREE_FOR(aug->child, sub) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002899 inherit_config_flag(sub);
2900 }
2901
Radek Krejcic071c542016-01-27 14:57:51 +01002902 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02002903 LY_TREE_FOR(aug->child, sub) {
Michal Vasko4f0dad02016-02-15 14:08:23 +01002904 if (lys_check_id(sub, aug->parent, lys_module(aug->module))) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02002905 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02002906 }
2907 }
Radek Krejci0acbe1b2015-08-04 09:33:49 +02002908 /* reconnect augmenting data into the target - add them to the target child list */
2909 if (aug->target->child) {
Michal Vasko1d87a922015-08-21 12:57:16 +02002910 sub = aug->target->child->prev; /* remember current target's last node */
2911 sub->next = aug->child; /* connect augmenting data after target's last node */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02002912 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
Michal Vasko1d87a922015-08-21 12:57:16 +02002913 aug->child->prev = sub; /* finish connecting of both child lists */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02002914 } else {
2915 aug->target->child = aug->child;
2916 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002917
2918 return EXIT_SUCCESS;
2919}
2920
Michal Vasko730dfdf2015-08-11 14:48:05 +02002921/**
2922 * @brief Resolve uses, apply augments, refines. Logs directly.
2923 *
Michal Vaskobb211122015-08-19 14:03:11 +02002924 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002925 * @param[in,out] unres List of unresolved items.
2926 * @param[in] line Line in the input file.
2927 *
Michal Vaskodef0db12015-10-07 13:22:48 +02002928 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002929 */
Michal Vasko184521f2015-09-24 13:14:26 +02002930static int
Michal Vaskodef0db12015-10-07 13:22:48 +02002931resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002932{
2933 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +01002934 struct lys_node *node = NULL;
2935 const struct lys_node *node_aux;
Radek Krejci76512572015-08-04 09:47:08 +02002936 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002937 struct lys_restr *must, **old_must;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002938 int i, j, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002939 uint8_t size, *old_size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002940
Michal Vasko71e1aa82015-08-12 12:17:51 +02002941 assert(uses->grp);
Michal Vaskodef0db12015-10-07 13:22:48 +02002942 /* HACK just check that the grouing is resolved */
2943 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02002944
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002945 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01002946 LY_TREE_FOR(uses->grp->child, node_aux) {
Michal Vaskod51d6ad2016-02-16 13:24:31 +01002947 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 +01002948 if (!node) {
Radek Krejciadb57612016-02-16 13:34:34 +01002949 LOGVAL(LYE_SPEC, line, LY_VLOG_LYS, uses, "Copying data from grouping failed.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002950 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002951 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002952 }
2953 ctx = uses->module->ctx;
2954
Michal Vaskodef0db12015-10-07 13:22:48 +02002955 /* we managed to copy the grouping, the rest must be possible to resolve */
2956
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002957 /* apply refines */
2958 for (i = 0; i < uses->refine_size; i++) {
2959 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01002960 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
2961 (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01002962 if (rc || !node) {
Radek Krejciadb57612016-02-16 13:34:34 +01002963 LOGVAL(LYE_INARG, line, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskodef0db12015-10-07 13:22:48 +02002964 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002965 }
2966
Radek Krejci1d82ef62015-08-07 14:44:40 +02002967 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejciadb57612016-02-16 13:34:34 +01002968 LOGVAL(LYE_SPEC, line, LY_VLOG_LYS, uses, "Refine substatements not applicable to the target-node.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002969 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002970 }
2971
2972 /* description on any nodetype */
2973 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002974 lydict_remove(ctx, node->dsc);
2975 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002976 }
2977
2978 /* reference on any nodetype */
2979 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002980 lydict_remove(ctx, node->ref);
2981 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002982 }
2983
2984 /* config on any nodetype */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002985 if (rfn->flags & LYS_CONFIG_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002986 node->flags &= ~LYS_CONFIG_MASK;
2987 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002988 }
2989
2990 /* default value ... */
2991 if (rfn->mod.dflt) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002992 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002993 /* leaf */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002994 lydict_remove(ctx, ((struct lys_node_leaf *)node)->dflt);
2995 ((struct lys_node_leaf *)node)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
2996 } else if (node->nodetype == LYS_CHOICE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002997 /* choice */
Michal Vasko3edeaf72016-02-11 13:17:43 +01002998 rc = resolve_choice_default_schema_nodeid(rfn->mod.dflt, node->child,
2999 (const struct lys_node **)&((struct lys_node_choice *)node)->dflt);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003000 if (rc || !((struct lys_node_choice *)node)->dflt) {
Radek Krejciadb57612016-02-16 13:34:34 +01003001 LOGVAL(LYE_INARG, line, LY_VLOG_LYS, uses, rfn->mod.dflt, "default");
Michal Vaskodef0db12015-10-07 13:22:48 +02003002 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003003 }
3004 }
3005 }
3006
3007 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02003008 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003009 if (node->nodetype & (LYS_LEAF | LYS_ANYXML | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003010 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003011 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003012
3013 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003014 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003015 }
3016 }
3017
3018 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003019 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
3020 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
3021 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003022 }
3023
3024 /* min/max-elements on list or leaf-list */
3025 /* magic - bit 3 in flags means min set, bit 4 says max set */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003026 if (node->nodetype == LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003027 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003028 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003029 }
3030 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003031 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003032 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02003033 } else if (node->nodetype == LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003034 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003035 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003036 }
3037 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003038 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003039 }
3040 }
3041
3042 /* must in leaf, leaf-list, list, container or anyxml */
3043 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003044 switch (node->nodetype) {
3045 case LYS_LEAF:
3046 old_size = &((struct lys_node_leaf *)node)->must_size;
3047 old_must = &((struct lys_node_leaf *)node)->must;
3048 break;
3049 case LYS_LEAFLIST:
3050 old_size = &((struct lys_node_leaflist *)node)->must_size;
3051 old_must = &((struct lys_node_leaflist *)node)->must;
3052 break;
3053 case LYS_LIST:
3054 old_size = &((struct lys_node_list *)node)->must_size;
3055 old_must = &((struct lys_node_list *)node)->must;
3056 break;
3057 case LYS_CONTAINER:
3058 old_size = &((struct lys_node_container *)node)->must_size;
3059 old_must = &((struct lys_node_container *)node)->must;
3060 break;
3061 case LYS_ANYXML:
3062 old_size = &((struct lys_node_anyxml *)node)->must_size;
3063 old_must = &((struct lys_node_anyxml *)node)->must;
3064 break;
3065 default:
3066 LOGINT;
Radek Krejcie4e4d722015-10-05 16:53:50 +02003067 return -1;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003068 }
3069
3070 size = *old_size + rfn->must_size;
3071 must = realloc(*old_must, size * sizeof *rfn->must);
3072 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003073 LOGMEM;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003074 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003075 }
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003076 for (i = 0, j = *old_size; i < rfn->must_size; i++, j++) {
3077 must[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
3078 must[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
3079 must[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
3080 must[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
3081 must[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003082 }
3083
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003084 *old_must = must;
3085 *old_size = size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003086 }
3087 }
3088
3089 /* apply augments */
3090 for (i = 0; i < uses->augment_size; i++) {
Michal Vasko7178e692016-02-12 15:58:05 +01003091 rc = resolve_augment(&uses->augment[i], uses->child, 0, line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003092 if (rc) {
Michal Vaskodef0db12015-10-07 13:22:48 +02003093 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003094 }
3095 }
3096
3097 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003098}
3099
Michal Vasko730dfdf2015-08-11 14:48:05 +02003100/**
3101 * @brief Resolve base identity recursively. Does not log.
3102 *
3103 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003104 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003105 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003106 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003107 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003108 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003109 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003110static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003111resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003112 struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003113{
Michal Vaskof02e3742015-08-05 16:27:02 +02003114 uint32_t i, j;
Radek Krejcibabbff82016-02-19 13:31:37 +01003115 struct lys_ident *base = NULL, *base_iter;
Radek Krejcia52656e2015-08-05 13:41:50 +02003116 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003117
Radek Krejcicf509982015-12-15 09:22:44 +01003118 assert(ret);
3119
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003120 /* search module */
3121 for (i = 0; i < module->ident_size; i++) {
3122 if (!strcmp(basename, module->ident[i].name)) {
3123
3124 if (!ident) {
3125 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003126 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01003127 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003128 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003129 }
3130
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003131 base = &module->ident[i];
3132 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003133 }
3134 }
3135
3136 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003137 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
3138 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
3139 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003140
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003141 if (!ident) {
3142 *ret = &module->inc[j].submodule->ident[i];
3143 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003144 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003145
3146 base = &module->inc[j].submodule->ident[i];
3147 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003148 }
3149 }
3150 }
3151
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003152matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003153 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01003154 if (base) {
3155 /* check for circular reference */
3156 for (base_iter = base; base_iter; base_iter = base_iter->base) {
3157 if (ident == base_iter) {
3158 LOGVAL(LYE_SPEC, 0, 0, NULL, "Circular reference of \"%s\" identity", basename);
3159 return EXIT_FAILURE;
3160 }
3161 }
3162 /* checks done, store the result */
3163 ident->base = base;
3164
3165 /* maintain backlinks to the derived identitise */
3166 while (base) {
3167 for (der = base->der; der && der->next; der = der->next);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003168 if (der) {
3169 der->next = malloc(sizeof *der);
3170 der = der->next;
3171 } else {
3172 ident->base->der = der = malloc(sizeof *der);
3173 }
Michal Vasko253035f2015-12-17 16:58:13 +01003174 if (!der) {
3175 LOGMEM;
3176 return EXIT_FAILURE;
3177 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003178 der->next = NULL;
3179 der->ident = ident;
3180
Radek Krejcibabbff82016-02-19 13:31:37 +01003181 base = base->base;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003182 }
Radek Krejcicf509982015-12-15 09:22:44 +01003183 *ret = ident->base;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003184 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003185 }
3186
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003187 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003188}
3189
Michal Vasko730dfdf2015-08-11 14:48:05 +02003190/**
3191 * @brief Resolve base identity. Logs directly.
3192 *
3193 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003194 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003195 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01003196 * @param[in] parent Either "type" or "identity".
Michal Vasko184521f2015-09-24 13:14:26 +02003197 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003198 * @param[in] line Line in the input file.
Radek Krejcicf509982015-12-15 09:22:44 +01003199 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003200 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003201 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003202 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003203static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003204resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char* parent,
Radek Krejcicf509982015-12-15 09:22:44 +01003205 int first, uint32_t line, struct lys_type *type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003206{
3207 const char *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02003208 int i, mod_name_len = 0;
Radek Krejcicf509982015-12-15 09:22:44 +01003209 struct lys_ident *target, **ret;
3210 uint8_t flags;
3211 struct lys_module *mod;
3212
3213 assert((ident && !type) || (!ident && type));
3214
3215 if (!type) {
3216 /* have ident to resolve */
3217 ret = &target;
3218 flags = ident->flags;
3219 mod = ident->module;
3220 } else {
3221 /* have type to fill */
3222 ret = &type->info.ident.ref;
3223 flags = type->parent->flags;
3224 mod = type->parent->module;
3225 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003226
3227 /* search for the base identity */
3228 name = strchr(basename, ':');
3229 if (name) {
3230 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02003231 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003232 name++;
3233
Michal Vasko2d851a92015-10-20 16:16:36 +02003234 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003235 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02003236 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003237 }
3238 } else {
3239 name = basename;
3240 }
3241
Radek Krejcic071c542016-01-27 14:57:51 +01003242 /* get module where to search */
3243 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
3244 if (!module) {
3245 /* identity refers unknown data model */
Radek Krejciadb57612016-02-16 13:34:34 +01003246 LOGVAL(LYE_INMOD, line, 0, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01003247 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003248 }
3249
Radek Krejcic071c542016-01-27 14:57:51 +01003250 /* search in the identified module ... */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003251 if (!resolve_base_ident_sub(module, ident, name, ret)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003252 goto success;
Radek Krejcibabbff82016-02-19 13:31:37 +01003253 } else if (ly_errno) {
3254 LOGVAL(LYE_LINE, line, 0, NULL);
3255 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003256 }
Radek Krejcic071c542016-01-27 14:57:51 +01003257 /* and all its submodules */
3258 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
3259 if (!resolve_base_ident_sub((struct lys_module *)module->inc[i].submodule, ident, name, ret)) {
3260 goto success;
Radek Krejcibabbff82016-02-19 13:31:37 +01003261 } else if (ly_errno) {
3262 LOGVAL(LYE_LINE, line, 0, NULL);
3263 return EXIT_FAILURE;
Radek Krejcic071c542016-01-27 14:57:51 +01003264 }
3265 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003266
Michal Vasko184521f2015-09-24 13:14:26 +02003267 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01003268 LOGVAL(LYE_INARG, line, 0, NULL, basename, parent);
Michal Vasko184521f2015-09-24 13:14:26 +02003269 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003270 return EXIT_FAILURE;
Radek Krejcicf509982015-12-15 09:22:44 +01003271
3272success:
3273 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003274 if (lyp_check_status(flags, mod, ident ? ident->name : "of type", (*ret)->flags, (*ret)->module, (*ret)->name,
3275 line, NULL)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003276 return -1;
3277 }
3278
3279 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003280}
3281
Michal Vasko730dfdf2015-08-11 14:48:05 +02003282/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003283 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003284 *
3285 * @param[in] base Base identity.
Michal Vaskofb0873c2015-08-21 09:00:07 +02003286 * @param[in] ident_name Identityref name.
3287 * @param[in] line Line from the input file.
Radek Krejciadb57612016-02-16 13:34:34 +01003288 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003289 *
3290 * @return Pointer to the identity resolvent, NULL on error.
3291 */
Radek Krejcia52656e2015-08-05 13:41:50 +02003292struct lys_ident *
Radek Krejciadb57612016-02-16 13:34:34 +01003293resolve_identref(struct lys_ident *base, const char *ident_name, uint32_t line, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003294{
Michal Vaskoc633ca02015-08-21 14:03:51 +02003295 const char *mod_name, *name;
3296 int mod_name_len, rc;
Radek Krejcia52656e2015-08-05 13:41:50 +02003297 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003298
Michal Vaskofb0873c2015-08-21 09:00:07 +02003299 if (!base || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003300 return NULL;
3301 }
3302
Michal Vaskoc633ca02015-08-21 14:03:51 +02003303 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskofb0873c2015-08-21 09:00:07 +02003304 if (rc < (signed)strlen(ident_name)) {
Radek Krejciadb57612016-02-16 13:34:34 +01003305 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02003306 return NULL;
3307 }
3308
Michal Vaskoc633ca02015-08-21 14:03:51 +02003309 if (!strcmp(base->name, name) && (!mod_name
3310 || (!strncmp(base->module->name, mod_name, mod_name_len) && !base->module->name[mod_name_len]))) {
Michal Vaskofb0873c2015-08-21 09:00:07 +02003311 return base;
3312 }
3313
3314 for (der = base->der; der; der = der->next) {
Michal Vaskoc633ca02015-08-21 14:03:51 +02003315 if (!strcmp(der->ident->name, name) && (!mod_name
3316 || (!strncmp(der->ident->module->name, mod_name, mod_name_len)
3317 && !der->ident->module->name[mod_name_len]))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003318 /* we have match */
3319 return der->ident;
3320 }
3321 }
3322
Radek Krejciadb57612016-02-16 13:34:34 +01003323 LOGVAL(LYE_INRESOLV, line, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003324 return NULL;
3325}
3326
Michal Vasko730dfdf2015-08-11 14:48:05 +02003327/**
Michal Vasko7955b362015-09-04 14:18:15 +02003328 * @brief Resolve (find) choice default case. Does not log.
3329 *
3330 * @param[in] choic Choice to use.
3331 * @param[in] dflt Name of the default case.
3332 *
3333 * @return Pointer to the default node or NULL.
3334 */
3335static struct lys_node *
3336resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
3337{
3338 struct lys_node *child, *ret;
3339
3340 LY_TREE_FOR(choic->child, child) {
3341 if (child->nodetype == LYS_USES) {
3342 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
3343 if (ret) {
3344 return ret;
3345 }
3346 }
3347
Radek Krejci749190d2016-02-18 16:26:25 +01003348 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYXML | LYS_CASE
Michal Vasko7955b362015-09-04 14:18:15 +02003349 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST))) {
3350 return child;
3351 }
3352 }
3353
3354 return NULL;
3355}
3356
3357/**
Michal Vaskobb211122015-08-19 14:03:11 +02003358 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003359 *
Michal Vaskobb211122015-08-19 14:03:11 +02003360 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003361 * @param[in] unres Specific unres item.
Michal Vasko407f1bb2015-09-23 15:51:07 +02003362 * @param[in] first Whether this is the first resolution try.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003363 * @param[in] line Line in the input file.
3364 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003365 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003366 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003367static int
Michal Vasko407f1bb2015-09-23 15:51:07 +02003368resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003369{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003370 int rc;
Michal Vaskoe91afce2015-08-12 12:21:00 +02003371 struct lys_node *parent;
3372
3373 /* HACK change unres uses count if it's in a grouping (nacm field used for it) */
3374 for (parent = uses->parent; parent && (parent->nodetype != LYS_GROUPING); parent = parent->parent);
3375
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003376 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01003377 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
3378 if (rc == -1) {
Radek Krejciadb57612016-02-16 13:34:34 +01003379 LOGVAL(LYE_INRESOLV, line, LY_VLOG_LYS, uses, "grouping", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003380 return -1;
3381 } else if (rc > 0) {
Radek Krejciadb57612016-02-16 13:34:34 +01003382 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003383 return -1;
3384 } else if (!uses->grp) {
3385 if (parent && first) {
Michal Vasko407f1bb2015-09-23 15:51:07 +02003386 ++parent->nacm;
3387 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01003388 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02003389 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003390 }
3391
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003392 if (uses->grp->nacm) {
Michal Vasko407f1bb2015-09-23 15:51:07 +02003393 if (parent && first) {
3394 ++parent->nacm;
3395 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003396 return EXIT_FAILURE;
3397 }
3398
Michal Vaskodef0db12015-10-07 13:22:48 +02003399 rc = resolve_uses(uses, unres, line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003400 if (!rc) {
3401 /* decrease unres count only if not first try */
Michal Vasko407f1bb2015-09-23 15:51:07 +02003402 if (parent && !first) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003403 if (!parent->nacm) {
3404 LOGINT;
3405 return -1;
3406 }
3407 --parent->nacm;
3408 }
Radek Krejcicf509982015-12-15 09:22:44 +01003409
3410 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01003411 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01003412 uses->grp->flags, uses->grp->module, uses->grp->name,
3413 line, (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003414 return -1;
3415 }
3416
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003417 return EXIT_SUCCESS;
3418 }
3419
Michal Vasko407f1bb2015-09-23 15:51:07 +02003420 if (parent && first && (rc == EXIT_FAILURE)) {
Michal Vaskoe91afce2015-08-12 12:21:00 +02003421 ++parent->nacm;
3422 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003423 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003424}
3425
Michal Vasko730dfdf2015-08-11 14:48:05 +02003426/**
Michal Vasko9957e592015-08-17 15:04:09 +02003427 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003428 *
Michal Vaskobb211122015-08-19 14:03:11 +02003429 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003430 * @param[in] keys_str Keys node value.
Michal Vasko184521f2015-09-24 13:14:26 +02003431 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003432 * @param[in] line Line in the input file.
3433 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003434 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003435 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003436static int
Michal Vasko36cbaa42015-12-14 13:15:48 +01003437resolve_list_keys(struct lys_node_list *list, const char *keys_str, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003438{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003439 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01003440 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003441
3442 for (i = 0; i < list->keys_size; ++i) {
3443 /* get the key name */
3444 if ((value = strpbrk(keys_str, " \t\n"))) {
3445 len = value - keys_str;
3446 while (isspace(value[0])) {
3447 value++;
3448 }
3449 } else {
3450 len = strlen(keys_str);
3451 }
3452
Michal Vasko4f0dad02016-02-15 14:08:23 +01003453 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 +02003454 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02003455 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01003456 LOGVAL(LYE_INRESOLV, line, LY_VLOG_LYS, list, "list keys", keys_str);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003457 }
3458 return rc;
3459 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003460
Radek Krejciadb57612016-02-16 13:34:34 +01003461 if (check_key(list, i, keys_str, len, line)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003462 /* check_key logs */
3463 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003464 }
3465
Radek Krejcicf509982015-12-15 09:22:44 +01003466 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01003467 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejciadb57612016-02-16 13:34:34 +01003468 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
3469 line, (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01003470 return -1;
3471 }
3472
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003473 /* prepare for next iteration */
3474 while (value && isspace(value[0])) {
3475 value++;
3476 }
3477 keys_str = value;
3478 }
3479
Michal Vaskof02e3742015-08-05 16:27:02 +02003480 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003481}
3482
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003483/**
Michal Vaskobf19d252015-10-08 15:39:17 +02003484 * @brief Resolve (check) all must conditions of \p node.
3485 * Logs directly.
3486 *
3487 * @param[in] node Data node with optional must statements.
3488 * @param[in] first Whether this is the first resolution to try.
3489 * @param[in] line Line in the input file.
3490 *
3491 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
3492 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003493static int
Michal Vaskobf19d252015-10-08 15:39:17 +02003494resolve_must(struct lyd_node *node, int first, uint32_t line)
Michal Vaskof02e3742015-08-05 16:27:02 +02003495{
Michal Vaskobf19d252015-10-08 15:39:17 +02003496 uint8_t i, must_size;
3497 struct lys_restr *must;
3498 struct lyxp_set set;
3499
3500 assert(node);
3501 memset(&set, 0, sizeof set);
3502
3503 switch (node->schema->nodetype) {
3504 case LYS_CONTAINER:
3505 must_size = ((struct lys_node_container *)node->schema)->must_size;
3506 must = ((struct lys_node_container *)node->schema)->must;
3507 break;
3508 case LYS_LEAF:
3509 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
3510 must = ((struct lys_node_leaf *)node->schema)->must;
3511 break;
3512 case LYS_LEAFLIST:
3513 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
3514 must = ((struct lys_node_leaflist *)node->schema)->must;
3515 break;
3516 case LYS_LIST:
3517 must_size = ((struct lys_node_list *)node->schema)->must_size;
3518 must = ((struct lys_node_list *)node->schema)->must;
3519 break;
3520 case LYS_ANYXML:
3521 must_size = ((struct lys_node_anyxml *)node->schema)->must_size;
3522 must = ((struct lys_node_anyxml *)node->schema)->must;
3523 break;
3524 default:
3525 must_size = 0;
3526 break;
3527 }
3528
3529 for (i = 0; i < must_size; ++i) {
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003530 if (lyxp_eval(must[i].expr, node, &set, 1, line)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02003531 return -1;
3532 }
3533
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003534 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, 1);
Michal Vaskobf19d252015-10-08 15:39:17 +02003535
3536 if (!set.value.bool) {
3537 if (!first) {
Michal Vasko7d3ec592016-02-17 12:06:44 +01003538 LOGVAL(LYE_NOCOND, line, LY_VLOG_LYD, node, "Must", must[i].expr);
Michal Vaskobf19d252015-10-08 15:39:17 +02003539 }
3540 return 1;
3541 }
3542 }
3543
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003544 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02003545}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003546
Michal Vaskobf19d252015-10-08 15:39:17 +02003547/**
Michal Vaskocf024702015-10-08 15:01:42 +02003548 * @brief Resolve (find) when condition context node. Does not log.
3549 *
3550 * @param[in] node Data node, whose conditional definition is being decided.
3551 * @param[in] schema Schema node with a when condition.
3552 *
3553 * @return Context node.
3554 */
3555static struct lyd_node *
3556resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003557{
Michal Vaskocf024702015-10-08 15:01:42 +02003558 struct lyd_node *parent;
3559 struct lys_node *sparent;
3560 uint16_t i, data_depth, schema_depth;
3561
3562 /* find a not schema-only node */
3563 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
3564 schema = lys_parent(schema);
3565 if (!schema) {
3566 return NULL;
3567 }
3568 }
3569
3570 /* get node depths */
3571 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
3572 for (sparent = lys_parent(schema), schema_depth = 1; sparent; sparent = lys_parent(sparent)) {
3573 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYXML | LYS_NOTIF | LYS_RPC)) {
3574 ++schema_depth;
3575 }
3576 }
3577 if (data_depth < schema_depth) {
3578 return NULL;
3579 }
3580
3581 /* find the corresponding data node */
3582 for (i = 0; i < data_depth - schema_depth; ++i) {
3583 node = node->parent;
3584 }
3585 if (node->schema != schema) {
3586 return NULL;
3587 }
3588
3589 return node;
3590}
3591
3592/**
3593 * @brief Resolve (check) all when conditions relevant for \p node.
3594 * Logs directly.
3595 *
3596 * @param[in] node Data node, whose conditional reference, if such, is being decided.
3597 * @param[in] first Whether this is the first resolution to try.
3598 * @param[in] line Line in the input file.
3599 *
3600 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
3601 */
3602static int
3603resolve_when(struct lyd_node *node, int first, uint32_t line)
3604{
3605 struct lyd_node *ctx_node = NULL;
3606 struct lys_node *parent;
3607 struct lyxp_set set;
3608
3609 assert(node);
3610 memset(&set, 0, sizeof set);
3611
3612 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003613 if (lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, &set, 1, line)) {
Michal Vaskocf024702015-10-08 15:01:42 +02003614 return -1;
3615 }
3616
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003617 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, 1);
Michal Vaskocf024702015-10-08 15:01:42 +02003618
3619 if (!set.value.bool) {
3620 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01003621 LOGVAL(LYE_NOCOND, line, LY_VLOG_LYS, node, "When", ((struct lys_node_container *)node->schema)->when->cond);
Michal Vaskocf024702015-10-08 15:01:42 +02003622 }
3623 return 1;
3624 }
3625 }
3626
3627 parent = node->schema;
3628 goto check_augment;
3629
3630 /* check when in every schema node that affects node */
3631 while (parent && (parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
3632 if (((struct lys_node_uses *)parent)->when) {
3633 if (!ctx_node) {
3634 ctx_node = resolve_when_ctx_node(node, parent);
3635 if (!ctx_node) {
3636 LOGINT;
3637 return -1;
3638 }
3639 }
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003640 if (lyxp_eval(((struct lys_node_uses *)parent)->when->cond, ctx_node, &set, 1, line)) {
Michal Vaskocf024702015-10-08 15:01:42 +02003641 return -1;
3642 }
3643
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003644 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, 1);
Michal Vaskocf024702015-10-08 15:01:42 +02003645
3646 if (!set.value.bool) {
3647 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01003648 LOGVAL(LYE_NOCOND, line, LY_VLOG_LYS, node, "When", ((struct lys_node_uses *)parent)->when->cond);
Michal Vaskocf024702015-10-08 15:01:42 +02003649 }
3650 return 1;
3651 }
3652 }
3653
3654check_augment:
3655 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)parent->parent)->when))) {
3656 if (!ctx_node) {
3657 ctx_node = resolve_when_ctx_node(node, parent->parent);
3658 if (!ctx_node) {
3659 LOGINT;
3660 return -1;
3661 }
3662 }
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003663 if (lyxp_eval(((struct lys_node_augment *)parent->parent)->when->cond, ctx_node, &set, 1, line)) {
Michal Vaskocf024702015-10-08 15:01:42 +02003664 return -1;
3665 }
3666
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003667 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, 1);
Michal Vaskocf024702015-10-08 15:01:42 +02003668
3669 if (!set.value.bool) {
3670 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01003671 LOGVAL(LYE_NOCOND, line, LY_VLOG_LYS, node, "When", ((struct lys_node_augment *)parent->parent)->when->cond);
Michal Vaskocf024702015-10-08 15:01:42 +02003672 }
3673 return 1;
3674 }
3675 }
3676
3677 parent = lys_parent(parent);
3678 }
3679
3680 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003681}
3682
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003683/**
Michal Vaskobb211122015-08-19 14:03:11 +02003684 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003685 *
3686 * @param[in] mod Main module.
3687 * @param[in] item Item to resolve. Type determined by \p type.
3688 * @param[in] type Type of the unresolved item.
3689 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02003690 * @param[in] unres Unres schema structure to use.
Michal Vasko407f1bb2015-09-23 15:51:07 +02003691 * @param[in] first Whether this is the first resolution try.
Michal Vasko184521f2015-09-24 13:14:26 +02003692 * @param[in] line Line in the input file. 0 skips line print.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003693 *
3694 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3695 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003696static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003697resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Michal Vasko407f1bb2015-09-23 15:51:07 +02003698 struct unres_schema *unres, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003699{
Radek Krejci4f78b532016-02-17 13:43:00 +01003700 int rc = -1, has_str = 0, tpdf_flag = 0;
Michal Vasko563ef092015-09-04 13:17:23 +02003701 struct lys_node *node;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003702 const char *base_name;
3703
3704 struct lys_ident *ident;
3705 struct lys_type *stype;
3706 struct lys_feature **feat_ptr;
3707 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01003708 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01003709 struct yang_type *yang;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003710
3711 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003712 case UNRES_IDENT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003713 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01003714 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003715 ident = item;
3716
Radek Krejcibabbff82016-02-19 13:31:37 +01003717 rc = resolve_base_ident(mod, ident, base_name, "identity", first, line, NULL);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003718 break;
3719 case UNRES_TYPE_IDENTREF:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003720 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01003721 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003722 stype = item;
3723
Radek Krejcicf509982015-12-15 09:22:44 +01003724 rc = resolve_base_ident(mod, NULL, base_name, "type", first, line, stype);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003725 break;
3726 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02003727 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003728 stype = item;
3729
Radek Krejci2f12f852016-01-08 12:59:57 +01003730 /* HACK - when there is no parent, we are in top level typedef and in that
3731 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
3732 * know it via tpdf_flag */
3733 if (!node) {
Radek Krejci4f78b532016-02-17 13:43:00 +01003734 tpdf_flag = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01003735 node = (struct lys_node *)stype->parent;
3736 }
3737
3738 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag, first, line,
Michal Vasko1e62a092015-12-01 12:27:20 +01003739 (const struct lys_node **)&stype->info.lref.target);
Radek Krejci46c4cd72016-01-21 15:13:52 +01003740 if (stype->info.lref.target) {
3741 /* store the backlink from leafref target */
3742 if (!stype->info.lref.target->child) {
3743 stype->info.lref.target->child = (void*)ly_set_new();
3744 if (!stype->info.lref.target->child) {
3745 LOGMEM;
3746 return -1;
3747 }
3748 }
3749 ly_set_add((struct ly_set *)stype->info.lref.target->child, stype->parent);
3750 }
3751
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003752 break;
3753 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01003754 /* parent */
3755 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003756 stype = item;
3757
Michal Vasko88c29542015-11-27 14:57:53 +01003758 /* HACK type->der is temporarily unparsed type statement */
3759 yin = (struct lyxml_elem *)stype->der;
3760 stype->der = NULL;
3761
Pavol Vicana0e4e672016-02-24 12:20:04 +01003762 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
3763 yang = (struct yang_type *)yin;
3764 rc = yang_check_type(mod, node, yang, unres);
3765
3766 if (rc) {
3767 /* may try again later */
3768 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01003769 } else {
3770 /* we need to always be able to free this, it's safe only in this case */
3771 if (yang->name) {
3772 free(yang->name);
3773 }
3774 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01003775 }
3776
Michal Vasko88c29542015-11-27 14:57:53 +01003777 } else {
Pavol Vicana0e4e672016-02-24 12:20:04 +01003778 rc = fill_yin_type(mod, node, yin, stype, unres);
3779 if (!rc) {
3780 /* we need to always be able to free this, it's safe only in this case */
3781 lyxml_free(mod->ctx, yin);
3782 } else {
3783 /* may try again later, put all back how it was */
3784 stype->der = (struct lys_tpdf *)yin;
3785 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003786 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003787 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003788 case UNRES_IFFEAT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003789 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01003790 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003791 feat_ptr = item;
3792
Michal Vasko184521f2015-09-24 13:14:26 +02003793 rc = resolve_feature(base_name, mod, first, line, feat_ptr);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003794 break;
3795 case UNRES_USES:
Michal Vasko407f1bb2015-09-23 15:51:07 +02003796 rc = resolve_unres_schema_uses(item, unres, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003797 break;
3798 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003799 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01003800 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003801 stype = item;
3802
Michal Vasko1dca6882015-10-22 14:29:42 +02003803 rc = check_default(stype, base_name, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003804 break;
3805 case UNRES_CHOICE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003806 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01003807 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003808 choic = item;
3809
Michal Vasko7955b362015-09-04 14:18:15 +02003810 choic->dflt = resolve_choice_dflt(choic, base_name);
3811 if (choic->dflt) {
3812 rc = EXIT_SUCCESS;
3813 } else {
3814 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003815 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003816 break;
3817 case UNRES_LIST_KEYS:
Radek Krejci4f78b532016-02-17 13:43:00 +01003818 has_str = 1;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003819 rc = resolve_list_keys(item, str_snode, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003820 break;
3821 case UNRES_LIST_UNIQ:
Radek Krejci4f78b532016-02-17 13:43:00 +01003822 has_str = 1;
Radek Krejci581ce772015-11-10 17:22:40 +01003823 rc = resolve_unique(item, str_snode, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003824 break;
Michal Vasko7178e692016-02-12 15:58:05 +01003825 case UNRES_AUGMENT:
3826 rc = resolve_augment(item, NULL, first, line);
Michal Vasko7178e692016-02-12 15:58:05 +01003827 break;
Michal Vaskocf024702015-10-08 15:01:42 +02003828 default:
3829 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003830 break;
3831 }
3832
Radek Krejci4f78b532016-02-17 13:43:00 +01003833 if (has_str && !rc) {
3834 lydict_remove(mod->ctx, str_snode);
3835 }
3836
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003837 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003838}
3839
Michal Vaskof02e3742015-08-05 16:27:02 +02003840/* logs directly */
3841static void
Michal Vasko0bd29d12015-08-19 11:45:49 +02003842print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003843{
Michal Vaskof02e3742015-08-05 16:27:02 +02003844 char line_str[18];
3845
3846 if (line) {
3847 sprintf(line_str, " (line %u)", line);
3848 } else {
3849 line_str[0] = '\0';
3850 }
3851
3852 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003853 case UNRES_IDENT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003854 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identity", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003855 break;
3856 case UNRES_TYPE_IDENTREF:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003857 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identityref", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003858 break;
3859 case UNRES_TYPE_LEAFREF:
3860 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "leafref", ((struct lys_type *)item)->info.lref.path, line_str);
3861 break;
3862 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01003863 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "derived type",
3864 ((struct lyxml_elem *)((struct lys_type *)item)->der)->attr->value, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003865 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02003866 case UNRES_IFFEAT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003867 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 +02003868 break;
3869 case UNRES_USES:
3870 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "uses", ((struct lys_node_uses *)item)->name, line_str);
3871 break;
3872 case UNRES_TYPE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003873 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 +02003874 break;
3875 case UNRES_CHOICE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003876 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 +02003877 break;
3878 case UNRES_LIST_KEYS:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003879 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 +02003880 break;
3881 case UNRES_LIST_UNIQ:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003882 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 +02003883 break;
Michal Vasko7178e692016-02-12 15:58:05 +01003884 case UNRES_AUGMENT:
Michal Vasko729d2912016-02-12 16:01:43 +01003885 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 +01003886 break;
Michal Vaskocf024702015-10-08 15:01:42 +02003887 default:
3888 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02003889 break;
3890 }
3891}
3892
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003893/**
Michal Vaskobb211122015-08-19 14:03:11 +02003894 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003895 *
3896 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003897 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003898 *
Michal Vasko92b8a382015-08-19 14:03:49 +02003899 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003900 */
Michal Vaskof02e3742015-08-05 16:27:02 +02003901int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003902resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02003903{
Michal Vasko88c29542015-11-27 14:57:53 +01003904 uint32_t i, resolved, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003905 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003906
3907 assert(unres);
3908
Michal Vasko51054ca2015-08-12 12:20:00 +02003909 resolved = 0;
3910
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003911 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02003912 do {
Michal Vasko88c29542015-11-27 14:57:53 +01003913 unres_count = 0;
3914 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02003915
3916 for (i = 0; i < unres->count; ++i) {
Michal Vasko88c29542015-11-27 14:57:53 +01003917 /* we do not need to have UNRES_TYPE_IDENTREF or UNRES_TYPE_LEAFREF resolved,
3918 * we need every type's base only */
3919 if ((unres->type[i] != UNRES_USES) && (unres->type[i] != UNRES_TYPE_DER)) {
Michal Vasko51054ca2015-08-12 12:20:00 +02003920 continue;
3921 }
3922
Michal Vasko88c29542015-11-27 14:57:53 +01003923 ++unres_count;
Michal Vasko407f1bb2015-09-23 15:51:07 +02003924 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0,
3925 LOGLINE_IDX(unres, i));
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003926 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02003927 unres->type[i] = UNRES_RESOLVED;
3928 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01003929 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02003930 } else if (rc == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003931 return -1;
Michal Vasko51054ca2015-08-12 12:20:00 +02003932 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003933 }
Michal Vasko88c29542015-11-27 14:57:53 +01003934 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02003935
Michal Vasko88c29542015-11-27 14:57:53 +01003936 if (res_count < unres_count) {
Radek Krejciadb57612016-02-16 13:34:34 +01003937 LOGVAL(LYE_SPEC, 0, 0, NULL, "There are unresolved uses left.");
Michal Vasko92b8a382015-08-19 14:03:49 +02003938 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003939 }
3940
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003941 /* the rest */
3942 for (i = 0; i < unres->count; ++i) {
3943 if (unres->type[i] == UNRES_RESOLVED) {
3944 continue;
3945 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02003946
Michal Vasko407f1bb2015-09-23 15:51:07 +02003947 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0,
3948 LOGLINE_IDX(unres, i));
Michal Vasko184521f2015-09-24 13:14:26 +02003949 if (rc) {
3950 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003951 }
Michal Vasko184521f2015-09-24 13:14:26 +02003952
3953 unres->type[i] = UNRES_RESOLVED;
3954 ++resolved;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003955 }
3956
3957 if (resolved < unres->count) {
Radek Krejciadb57612016-02-16 13:34:34 +01003958 LOGVAL(LYE_SPEC, 0, 0, NULL, "There are unresolved schema items left.");
Michal Vasko92b8a382015-08-19 14:03:49 +02003959 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003960 }
3961
Radek Krejcic071c542016-01-27 14:57:51 +01003962 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003963 return EXIT_SUCCESS;
3964}
3965
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003966/**
Michal Vaskobb211122015-08-19 14:03:11 +02003967 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003968 *
3969 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003970 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003971 * @param[in] item Item to resolve. Type determined by \p type.
3972 * @param[in] type Type of the unresolved item.
3973 * @param[in] str String argument.
3974 * @param[in] line Line in the input file.
3975 *
3976 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3977 */
3978int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003979unres_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 +02003980 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003981{
Radek Krejci4f78b532016-02-17 13:43:00 +01003982 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 +02003983}
3984
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003985/**
Michal Vaskobb211122015-08-19 14:03:11 +02003986 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003987 *
3988 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003989 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003990 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01003991 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003992 * @param[in] snode Schema node argument.
3993 * @param[in] line Line in the input file.
3994 *
3995 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3996 */
3997int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003998unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Michal Vasko7955b362015-09-04 14:18:15 +02003999 struct lys_node *snode, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004000{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004001 int rc;
Michal Vasko88c29542015-11-27 14:57:53 +01004002 struct lyxml_elem *yin;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004003
Michal Vasko9bf425b2015-10-22 11:42:03 +02004004 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
4005 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004006
Michal Vasko184521f2015-09-24 13:14:26 +02004007 rc = resolve_unres_schema_item(mod, item, type, snode, unres, 1, line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004008 if (rc != EXIT_FAILURE) {
4009 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004010 }
4011
Michal Vasko0bd29d12015-08-19 11:45:49 +02004012 print_unres_schema_item_fail(item, type, snode, line);
Michal Vaskof02e3742015-08-05 16:27:02 +02004013
Michal Vasko88c29542015-11-27 14:57:53 +01004014 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
4015 if (type == UNRES_TYPE_DER) {
4016 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
Pavol Vicana0e4e672016-02-24 12:20:04 +01004017 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
4018 lyxml_unlink_elem(mod->ctx, yin, 1);
4019 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
4020 }
Michal Vasko88c29542015-11-27 14:57:53 +01004021 }
4022
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004023 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01004024 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
4025 if (!unres->item) {
4026 LOGMEM;
4027 return -1;
4028 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004029 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01004030 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
4031 if (!unres->type) {
4032 LOGMEM;
4033 return -1;
4034 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004035 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01004036 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
4037 if (!unres->str_snode) {
4038 LOGMEM;
4039 return -1;
4040 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004041 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01004042 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
4043 if (!unres->module) {
4044 LOGMEM;
4045 return -1;
4046 }
4047 unres->module[unres->count-1] = mod;
Michal Vaskoc07187d2015-08-13 15:20:57 +02004048#ifndef NDEBUG
Michal Vasko253035f2015-12-17 16:58:13 +01004049 unres->line = ly_realloc(unres->line, unres->count*sizeof *unres->line);
4050 if (!unres->line) {
4051 LOGMEM;
4052 return -1;
4053 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004054 unres->line[unres->count-1] = line;
Michal Vaskoc07187d2015-08-13 15:20:57 +02004055#endif
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004056
4057 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004058}
4059
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004060/**
Michal Vaskobb211122015-08-19 14:03:11 +02004061 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004062 *
4063 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004064 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004065 * @param[in] item Old item to be resolved.
4066 * @param[in] type Type of the old unresolved item.
4067 * @param[in] new_item New item to use in the duplicate.
4068 *
4069 * @return EXIT_SUCCESS on success, -1 on error.
4070 */
Michal Vaskodad19402015-08-06 09:51:53 +02004071int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004072unres_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 +02004073{
4074 int i;
4075
Michal Vaskocf024702015-10-08 15:01:42 +02004076 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004077
Michal Vasko0bd29d12015-08-19 11:45:49 +02004078 i = unres_schema_find(unres, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004079
4080 if (i == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004081 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004082 }
4083
Michal Vasko0d204592015-10-07 09:50:04 +02004084 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT)) {
Michal Vasko0bd29d12015-08-19 11:45:49 +02004085 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004086 LOGINT;
4087 return -1;
4088 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004089 } else {
Michal Vasko0bd29d12015-08-19 11:45:49 +02004090 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004091 LOGINT;
4092 return -1;
4093 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004094 }
Michal Vaskodad19402015-08-06 09:51:53 +02004095
4096 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004097}
4098
Michal Vaskof02e3742015-08-05 16:27:02 +02004099/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004100int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004101unres_schema_find(struct unres_schema *unres, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004102{
4103 uint32_t ret = -1, i;
4104
4105 for (i = 0; i < unres->count; ++i) {
4106 if ((unres->item[i] == item) && (unres->type[i] == type)) {
4107 ret = i;
4108 break;
4109 }
4110 }
4111
4112 return ret;
4113}
Michal Vasko8bcdf292015-08-19 14:04:43 +02004114
Michal Vasko88c29542015-11-27 14:57:53 +01004115void
Radek Krejcic071c542016-01-27 14:57:51 +01004116unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01004117{
4118 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01004119 unsigned int unresolved = 0;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01004120 struct lyxml_elem *yin;
4121 struct yang_type *yang;
Michal Vasko88c29542015-11-27 14:57:53 +01004122
Radek Krejcic071c542016-01-27 14:57:51 +01004123 if (!unres || !(*unres)) {
4124 return;
Michal Vasko88c29542015-11-27 14:57:53 +01004125 }
4126
Radek Krejcic071c542016-01-27 14:57:51 +01004127 assert(module || (*unres)->count == 0);
4128
4129 for (i = 0; i < (*unres)->count; ++i) {
4130 if ((*unres)->module[i] != module) {
4131 if ((*unres)->type[i] != UNRES_RESOLVED) {
4132 unresolved++;
4133 }
4134 continue;
4135 }
4136 if ((*unres)->type[i] == UNRES_TYPE_DER) {
Pavol Vicand01d8ae2016-03-01 10:45:59 +01004137 yin = (struct lyxml_elem *)((struct lys_type *)(*unres)->item[i])->der;
4138 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
4139 yang =(struct yang_type *)yin;
4140 if (yang->name) {
4141 free(yang->name);
4142 }
4143 free(yang);
4144 } else {
4145 lyxml_free(module->ctx, yin);
4146 }
Radek Krejcic071c542016-01-27 14:57:51 +01004147 }
4148 (*unres)->type[i] = UNRES_RESOLVED;
4149 }
4150
4151 if (!module || (!unresolved && !module->type)) {
4152 free((*unres)->item);
4153 free((*unres)->type);
4154 free((*unres)->str_snode);
4155 free((*unres)->module);
Michal Vasko88c29542015-11-27 14:57:53 +01004156#ifndef NDEBUG
Radek Krejcic071c542016-01-27 14:57:51 +01004157 free((*unres)->line);
Michal Vasko88c29542015-11-27 14:57:53 +01004158#endif
Radek Krejcic071c542016-01-27 14:57:51 +01004159 free((*unres));
4160 (*unres) = NULL;
4161 }
Michal Vasko88c29542015-11-27 14:57:53 +01004162}
4163
Michal Vasko8bcdf292015-08-19 14:04:43 +02004164/* logs directly */
4165static void
Michal Vaskocf024702015-10-08 15:01:42 +02004166print_unres_data_item_fail(struct lyd_node *node, enum UNRES_ITEM type, uint32_t line)
Michal Vasko8bcdf292015-08-19 14:04:43 +02004167{
4168 struct lys_node_leaf *sleaf;
4169 char line_str[18];
4170
4171 if (line) {
4172 sprintf(line_str, " (line %u)", line);
4173 } else {
4174 line_str[0] = '\0';
4175 }
4176
Michal Vaskocf024702015-10-08 15:01:42 +02004177 sleaf = (struct lys_node_leaf *)node->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004178
Michal Vaskocf024702015-10-08 15:01:42 +02004179 switch (type) {
4180 case UNRES_LEAFREF:
Michal Vasko8bcdf292015-08-19 14:04:43 +02004181 LOGVRB("Leafref \"%s\" could not be resolved, it will be attempted later%s.",
4182 sleaf->type.info.lref.path, line_str);
Michal Vaskocf024702015-10-08 15:01:42 +02004183 break;
4184 case UNRES_INSTID:
Michal Vasko8bcdf292015-08-19 14:04:43 +02004185 LOGVRB("Instance-identifier \"%s\" could not be resolved, it will be attempted later%s.",
Michal Vasko83a6c462015-10-08 16:43:53 +02004186 ((struct lyd_node_leaf_list *)node)->value_str, line_str);
Michal Vaskocf024702015-10-08 15:01:42 +02004187 break;
4188 case UNRES_WHEN:
4189 LOGVRB("There was an unsatisfied when condition, evaluation will be attempted later%s.", line_str);
4190 break;
Michal Vaskobf19d252015-10-08 15:39:17 +02004191 case UNRES_MUST:
4192 LOGVRB("There was an unsatisfied must condition, evaluation will be attempted later%s.", line_str);
4193 break;
Michal Vaskocf024702015-10-08 15:01:42 +02004194 default:
4195 LOGINT;
4196 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004197 }
4198}
4199
4200/**
4201 * @brief Resolve a single unres data item. Logs directly.
4202 *
Michal Vaskocf024702015-10-08 15:01:42 +02004203 * @param[in] node Data node to resolve.
Michal Vasko184521f2015-09-24 13:14:26 +02004204 * @param[in] first Whether this is the first resolution try.
Michal Vaskocf024702015-10-08 15:01:42 +02004205 * @param[in] type Type of the unresolved item.
Michal Vasko184521f2015-09-24 13:14:26 +02004206 * @param[in] line Line in the input file. 0 skips line print.
Michal Vasko8bcdf292015-08-19 14:04:43 +02004207 *
4208 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
4209 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02004210int
Michal Vaskocf024702015-10-08 15:01:42 +02004211resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int first, uint32_t line)
Michal Vasko8bcdf292015-08-19 14:04:43 +02004212{
4213 uint32_t i;
Michal Vasko0491ab32015-08-19 14:28:29 +02004214 int rc;
Michal Vasko83a6c462015-10-08 16:43:53 +02004215 struct lyd_node_leaf_list *leaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004216 struct lys_node_leaf *sleaf;
4217 struct unres_data matches;
4218
4219 memset(&matches, 0, sizeof matches);
Michal Vasko83a6c462015-10-08 16:43:53 +02004220 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02004221 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004222
Michal Vaskocf024702015-10-08 15:01:42 +02004223 switch (type) {
4224 case UNRES_LEAFREF:
4225 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vaskof7677612015-10-16 14:27:23 +02004226 if ((rc = resolve_path_arg_data(node, sleaf->type.info.lref.path, first, line, &matches))) {
Michal Vasko0491ab32015-08-19 14:28:29 +02004227 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004228 }
4229
4230 /* check that value matches */
4231 for (i = 0; i < matches.count; ++i) {
Radek Krejci749190d2016-02-18 16:26:25 +01004232 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
Michal Vaskocf024702015-10-08 15:01:42 +02004233 leaf->value.leafref = matches.node[i];
Michal Vasko8bcdf292015-08-19 14:04:43 +02004234 break;
4235 }
4236 }
4237
Michal Vaskocf024702015-10-08 15:01:42 +02004238 free(matches.node);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004239 memset(&matches, 0, sizeof matches);
4240
Michal Vaskocf024702015-10-08 15:01:42 +02004241 if (!leaf->value.leafref) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02004242 /* reference not found */
Michal Vasko184521f2015-09-24 13:14:26 +02004243 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01004244 LOGVAL(LYE_SPEC, line, LY_VLOG_LYD, leaf, "Leafref \"%s\" value \"%s\" did not match any node value.",
Michal Vaskocf024702015-10-08 15:01:42 +02004245 sleaf->type.info.lref.path, leaf->value_str);
Michal Vasko184521f2015-09-24 13:14:26 +02004246 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02004247 return EXIT_FAILURE;
4248 }
Michal Vaskocf024702015-10-08 15:01:42 +02004249 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004250
Michal Vaskocf024702015-10-08 15:01:42 +02004251 case UNRES_INSTID:
4252 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004253 ly_errno = 0;
Radek Krejci40f17b92016-02-03 14:30:43 +01004254 leaf->value.instance = resolve_instid(node, leaf->value_str, line);
4255 if (!leaf->value.instance) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02004256 if (ly_errno) {
4257 return -1;
4258 } else if (sleaf->type.info.inst.req > -1) {
Michal Vasko184521f2015-09-24 13:14:26 +02004259 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01004260 LOGVAL(LYE_SPEC, line, LY_VLOG_LYD, leaf, "There is no instance of \"%s\".", leaf->value_str);
Michal Vasko184521f2015-09-24 13:14:26 +02004261 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02004262 return EXIT_FAILURE;
4263 } else {
Radek Krejci4ce42be2016-02-03 13:04:41 +01004264 LOGVRB("There is no instance of \"%s\", but it is not required.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004265 }
4266 }
Michal Vaskocf024702015-10-08 15:01:42 +02004267 break;
4268
4269 case UNRES_WHEN:
4270 if ((rc = resolve_when(node, first, line))) {
4271 return rc;
4272 }
4273 break;
4274
Michal Vaskobf19d252015-10-08 15:39:17 +02004275 case UNRES_MUST:
4276 if ((rc = resolve_must(node, first, line))) {
4277 return rc;
4278 }
4279 break;
4280
Michal Vaskocf024702015-10-08 15:01:42 +02004281 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02004282 LOGINT;
4283 return -1;
4284 }
4285
4286 return EXIT_SUCCESS;
4287}
4288
4289/**
4290 * @brief Try to resolve an unres data item. Logs indirectly.
4291 *
4292 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02004293 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02004294 * @param[in] line Line in the input file.
4295 *
4296 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
4297 */
4298int
Michal Vaskocf024702015-10-08 15:01:42 +02004299unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type, uint32_t line)
Michal Vasko8bcdf292015-08-19 14:04:43 +02004300{
4301 int rc;
4302
Michal Vaskobf19d252015-10-08 15:39:17 +02004303 assert(unres && node && ((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)));
Michal Vasko8bcdf292015-08-19 14:04:43 +02004304
Michal Vaskocf024702015-10-08 15:01:42 +02004305 rc = resolve_unres_data_item(node, type, 1, line);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004306 if (rc != EXIT_FAILURE) {
4307 return rc;
4308 }
4309
Michal Vaskocf024702015-10-08 15:01:42 +02004310 print_unres_data_item_fail(node, type, line);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004311
4312 ++unres->count;
Michal Vasko253035f2015-12-17 16:58:13 +01004313 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
4314 if (!unres->node) {
4315 LOGMEM;
4316 return -1;
4317 }
Michal Vaskocf024702015-10-08 15:01:42 +02004318 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01004319 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
4320 if (!unres->type) {
4321 LOGMEM;
4322 return -1;
4323 }
Michal Vaskocf024702015-10-08 15:01:42 +02004324 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004325#ifndef NDEBUG
Michal Vasko253035f2015-12-17 16:58:13 +01004326 unres->line = ly_realloc(unres->line, unres->count * sizeof *unres->line);
4327 if (!unres->line) {
4328 LOGMEM;
4329 return -1;
4330 }
Michal Vaskocf024702015-10-08 15:01:42 +02004331 unres->line[unres->count - 1] = line;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004332#endif
4333
4334 return EXIT_SUCCESS;
4335}
4336
4337/**
4338 * @brief Resolve every unres data item in the structure. Logs directly.
4339 *
4340 * @param[in] unres Unres data structure to use.
4341 *
4342 * @return EXIT_SUCCESS on success, -1 on error.
4343 */
4344int
4345resolve_unres_data(struct unres_data *unres)
4346{
4347 uint32_t i;
4348 int rc;
4349
4350 for (i = 0; i < unres->count; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02004351 rc = resolve_unres_data_item(unres->node[i], unres->type[i], 0, LOGLINE_IDX(unres, i));
Michal Vasko8bcdf292015-08-19 14:04:43 +02004352 if (rc) {
Radek Krejciadb57612016-02-16 13:34:34 +01004353 LOGVAL(LYE_SPEC, 0, 0, NULL, "There are unresolved data items left.");
Michal Vasko8bcdf292015-08-19 14:04:43 +02004354 return -1;
4355 }
4356 }
4357
4358 return EXIT_SUCCESS;
4359}