blob: 676d6ed7c224cb853499d7a5c70a62ff9af2bdbd [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"
Radek Krejci41912fe2015-10-22 10:22:12 +020035#include "dict_private.h"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020036#include "tree_internal.h"
37
Michal Vasko730dfdf2015-08-11 14:48:05 +020038/**
Radek Krejci6dc53a22015-08-17 13:27:59 +020039 * @brief Parse an identifier.
40 *
41 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
42 * identifier = (ALPHA / "_")
43 * *(ALPHA / DIGIT / "_" / "-" / ".")
44 *
Michal Vaskobb211122015-08-19 14:03:11 +020045 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +020046 *
47 * @return Number of characters successfully parsed.
48 */
Michal Vasko249e6b52015-08-19 11:08:52 +020049int
Radek Krejci6dc53a22015-08-17 13:27:59 +020050parse_identifier(const char *id)
51{
52 int parsed = 0;
53
54 if (((id[0] == 'x') || (id[0] == 'X'))
55 && ((id[1] == 'm') || (id[0] == 'M'))
56 && ((id[2] == 'l') || (id[2] == 'L'))) {
57 return -parsed;
58 }
59
60 if (!isalpha(id[0]) && (id[0] != '_')) {
61 return -parsed;
62 }
63
64 ++parsed;
65 ++id;
66
67 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
68 ++parsed;
69 ++id;
70 }
71
72 return parsed;
73}
74
75/**
76 * @brief Parse a node-identifier.
77 *
Michal Vasko723e50c2015-10-20 15:20:29 +020078 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +020079 *
Michal Vaskobb211122015-08-19 14:03:11 +020080 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +020081 * @param[out] mod_name Points to the module name, NULL if there is not any.
82 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +020083 * @param[out] name Points to the node name.
84 * @param[out] nam_len Length of the node name.
85 *
86 * @return Number of characters successfully parsed,
87 * positive on success, negative on failure.
88 */
89static int
Michal Vasko723e50c2015-10-20 15:20:29 +020090parse_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 +020091{
92 int parsed = 0, ret;
93
94 assert(id);
Michal Vasko723e50c2015-10-20 15:20:29 +020095 if (mod_name) {
96 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +020097 }
Michal Vasko723e50c2015-10-20 15:20:29 +020098 if (mod_name_len) {
99 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200100 }
101 if (name) {
102 *name = NULL;
103 }
104 if (nam_len) {
105 *nam_len = 0;
106 }
107
108 if ((ret = parse_identifier(id)) < 1) {
109 return ret;
110 }
111
Michal Vasko723e50c2015-10-20 15:20:29 +0200112 if (mod_name) {
113 *mod_name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200114 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200115 if (mod_name_len) {
116 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200117 }
118
119 parsed += ret;
120 id += ret;
121
122 /* there is prefix */
123 if (id[0] == ':') {
124 ++parsed;
125 ++id;
126
127 /* there isn't */
128 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200129 if (name && mod_name) {
130 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200131 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200132 if (mod_name) {
133 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200134 }
135
Michal Vasko723e50c2015-10-20 15:20:29 +0200136 if (nam_len && mod_name_len) {
137 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200138 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200139 if (mod_name_len) {
140 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200141 }
142
143 return parsed;
144 }
145
146 /* identifier (node name) */
147 if ((ret = parse_identifier(id)) < 1) {
148 return -parsed+ret;
149 }
150
151 if (name) {
152 *name = id;
153 }
154 if (nam_len) {
155 *nam_len = ret;
156 }
157
158 return parsed+ret;
159}
160
161/**
162 * @brief Parse a path-predicate (leafref).
163 *
164 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
165 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
166 *
Michal Vaskobb211122015-08-19 14:03:11 +0200167 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200168 * @param[out] prefix Points to the prefix, NULL if there is not any.
169 * @param[out] pref_len Length of the prefix, 0 if there is not any.
170 * @param[out] name Points to the node name.
171 * @param[out] nam_len Length of the node name.
172 * @param[out] path_key_expr Points to the path-key-expr.
173 * @param[out] pke_len Length of the path-key-expr.
174 * @param[out] has_predicate Flag to mark whether there is another predicate following.
175 *
176 * @return Number of characters successfully parsed,
177 * positive on success, negative on failure.
178 */
179static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200180parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
181 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200182{
183 const char *ptr;
184 int parsed = 0, ret;
185
186 assert(id);
187 if (prefix) {
188 *prefix = NULL;
189 }
190 if (pref_len) {
191 *pref_len = 0;
192 }
193 if (name) {
194 *name = NULL;
195 }
196 if (nam_len) {
197 *nam_len = 0;
198 }
199 if (path_key_expr) {
200 *path_key_expr = NULL;
201 }
202 if (pke_len) {
203 *pke_len = 0;
204 }
205 if (has_predicate) {
206 *has_predicate = 0;
207 }
208
209 if (id[0] != '[') {
210 return -parsed;
211 }
212
213 ++parsed;
214 ++id;
215
216 while (isspace(id[0])) {
217 ++parsed;
218 ++id;
219 }
220
221 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
222 return -parsed+ret;
223 }
224
225 parsed += ret;
226 id += ret;
227
228 while (isspace(id[0])) {
229 ++parsed;
230 ++id;
231 }
232
233 if (id[0] != '=') {
234 return -parsed;
235 }
236
237 ++parsed;
238 ++id;
239
240 while (isspace(id[0])) {
241 ++parsed;
242 ++id;
243 }
244
245 if ((ptr = strchr(id, ']')) == NULL) {
246 return -parsed;
247 }
248
249 --ptr;
250 while (isspace(ptr[0])) {
251 --ptr;
252 }
253 ++ptr;
254
255 ret = ptr-id;
256 if (path_key_expr) {
257 *path_key_expr = id;
258 }
259 if (pke_len) {
260 *pke_len = ret;
261 }
262
263 parsed += ret;
264 id += ret;
265
266 while (isspace(id[0])) {
267 ++parsed;
268 ++id;
269 }
270
271 assert(id[0] == ']');
272
273 if (id[1] == '[') {
274 *has_predicate = 1;
275 }
276
277 return parsed+1;
278}
279
280/**
281 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
282 * the ".." and the first node-identifier, other calls parse a single
283 * node-identifier each.
284 *
285 * path-key-expr = current-function-invocation *WSP "/" *WSP
286 * rel-path-keyexpr
287 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
288 * *(node-identifier *WSP "/" *WSP)
289 * node-identifier
290 *
Michal Vaskobb211122015-08-19 14:03:11 +0200291 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200292 * @param[out] prefix Points to the prefix, NULL if there is not any.
293 * @param[out] pref_len Length of the prefix, 0 if there is not any.
294 * @param[out] name Points to the node name.
295 * @param[out] nam_len Length of the node name.
296 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
297 * must not be changed between consecutive calls.
298 * @return Number of characters successfully parsed,
299 * positive on success, negative on failure.
300 */
301static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200302parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
303 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200304{
305 int parsed = 0, ret, par_times = 0;
306
307 assert(id);
308 assert(parent_times);
309 if (prefix) {
310 *prefix = NULL;
311 }
312 if (pref_len) {
313 *pref_len = 0;
314 }
315 if (name) {
316 *name = NULL;
317 }
318 if (nam_len) {
319 *nam_len = 0;
320 }
321
322 if (!*parent_times) {
323 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
324 if (strncmp(id, "current()", 9)) {
325 return -parsed;
326 }
327
328 parsed += 9;
329 id += 9;
330
331 while (isspace(id[0])) {
332 ++parsed;
333 ++id;
334 }
335
336 if (id[0] != '/') {
337 return -parsed;
338 }
339
340 ++parsed;
341 ++id;
342
343 while (isspace(id[0])) {
344 ++parsed;
345 ++id;
346 }
347
348 /* rel-path-keyexpr */
349 if (strncmp(id, "..", 2)) {
350 return -parsed;
351 }
352 ++par_times;
353
354 parsed += 2;
355 id += 2;
356
357 while (isspace(id[0])) {
358 ++parsed;
359 ++id;
360 }
361 }
362
363 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
364 *
365 * first parent reference with whitespaces already parsed
366 */
367 if (id[0] != '/') {
368 return -parsed;
369 }
370
371 ++parsed;
372 ++id;
373
374 while (isspace(id[0])) {
375 ++parsed;
376 ++id;
377 }
378
379 while (!strncmp(id, "..", 2) && !*parent_times) {
380 ++par_times;
381
382 parsed += 2;
383 id += 2;
384
385 while (isspace(id[0])) {
386 ++parsed;
387 ++id;
388 }
389
390 if (id[0] != '/') {
391 return -parsed;
392 }
393
394 ++parsed;
395 ++id;
396
397 while (isspace(id[0])) {
398 ++parsed;
399 ++id;
400 }
401 }
402
403 if (!*parent_times) {
404 *parent_times = par_times;
405 }
406
407 /* all parent references must be parsed at this point */
408 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
409 return -parsed+ret;
410 }
411
412 parsed += ret;
413 id += ret;
414
415 return parsed;
416}
417
418/**
419 * @brief Parse path-arg (leafref).
420 *
421 * path-arg = absolute-path / relative-path
422 * absolute-path = 1*("/" (node-identifier *path-predicate))
423 * relative-path = 1*(".." "/") descendant-path
424 *
Michal Vaskobb211122015-08-19 14:03:11 +0200425 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200426 * @param[out] prefix Points to the prefix, NULL if there is not any.
427 * @param[out] pref_len Length of the prefix, 0 if there is not any.
428 * @param[out] name Points to the node name.
429 * @param[out] nam_len Length of the node name.
430 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
431 * must not be changed between consecutive calls. -1 if the
432 * path is relative.
433 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
434 *
435 * @return Number of characters successfully parsed,
436 * positive on success, negative on failure.
437 */
438static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200439parse_path_arg(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len, int *parent_times,
440 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200441{
442 int parsed = 0, ret, par_times = 0;
443
444 assert(id);
445 assert(parent_times);
446 if (prefix) {
447 *prefix = NULL;
448 }
449 if (pref_len) {
450 *pref_len = 0;
451 }
452 if (name) {
453 *name = NULL;
454 }
455 if (nam_len) {
456 *nam_len = 0;
457 }
458 if (has_predicate) {
459 *has_predicate = 0;
460 }
461
462 if (!*parent_times && !strncmp(id, "..", 2)) {
463 ++par_times;
464
465 parsed += 2;
466 id += 2;
467
468 while (!strncmp(id, "/..", 3)) {
469 ++par_times;
470
471 parsed += 3;
472 id += 3;
473 }
474 }
475
476 if (!*parent_times) {
477 if (par_times) {
478 *parent_times = par_times;
479 } else {
480 *parent_times = -1;
481 }
482 }
483
484 if (id[0] != '/') {
485 return -parsed;
486 }
487
488 /* skip '/' */
489 ++parsed;
490 ++id;
491
492 /* node-identifier ([prefix:]identifier) */
493 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
494 return -parsed-ret;
495 }
496
497 parsed += ret;
498 id += ret;
499
500 /* there is no predicate */
501 if ((id[0] == '/') || !id[0]) {
502 return parsed;
503 } else if (id[0] != '[') {
504 return -parsed;
505 }
506
507 if (has_predicate) {
508 *has_predicate = 1;
509 }
510
511 return parsed;
512}
513
514/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200515 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200516 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200517 *
518 * instance-identifier = 1*("/" (node-identifier *predicate))
519 *
Michal Vaskobb211122015-08-19 14:03:11 +0200520 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200521 * @param[out] model Points to the model name.
522 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200523 * @param[out] name Points to the node name.
524 * @param[out] nam_len Length of the node name.
525 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
526 *
527 * @return Number of characters successfully parsed,
528 * positive on success, negative on failure.
529 */
530static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200531parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
532 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200533{
534 int parsed = 0, ret;
535
536 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200537 if (model) {
538 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200539 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200540 if (mod_len) {
541 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200542 }
543 if (name) {
544 *name = NULL;
545 }
546 if (nam_len) {
547 *nam_len = 0;
548 }
549 if (has_predicate) {
550 *has_predicate = 0;
551 }
552
553 if (id[0] != '/') {
554 return -parsed;
555 }
556
557 ++parsed;
558 ++id;
559
Michal Vasko1f2cc332015-08-19 11:18:32 +0200560 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200561 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200562 } else if (model && !*model) {
563 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200564 }
565
566 parsed += ret;
567 id += ret;
568
569 if ((id[0] == '[') && has_predicate) {
570 *has_predicate = 1;
571 }
572
573 return parsed;
574}
575
576/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200577 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200578 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200579 *
580 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
581 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
582 * ((DQUOTE string DQUOTE) /
583 * (SQUOTE string SQUOTE))
584 * pos = non-negative-integer-value
585 *
Michal Vaskobb211122015-08-19 14:03:11 +0200586 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200587 * @param[out] model Points to the model name.
588 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200589 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
590 * @param[out] nam_len Length of the node name.
591 * @param[out] value Value the node-identifier must have (string from the grammar),
592 * NULL if there is not any.
593 * @param[out] val_len Length of the value, 0 if there is not any.
594 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
595 *
596 * @return Number of characters successfully parsed,
597 * positive on success, negative on failure.
598 */
599static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200600parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
601 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200602{
603 const char *ptr;
604 int parsed = 0, ret;
605 char quote;
606
607 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200608 if (model) {
609 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200610 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200611 if (mod_len) {
612 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200613 }
614 if (name) {
615 *name = NULL;
616 }
617 if (nam_len) {
618 *nam_len = 0;
619 }
620 if (value) {
621 *value = NULL;
622 }
623 if (val_len) {
624 *val_len = 0;
625 }
626 if (has_predicate) {
627 *has_predicate = 0;
628 }
629
630 if (id[0] != '[') {
631 return -parsed;
632 }
633
634 ++parsed;
635 ++id;
636
637 while (isspace(id[0])) {
638 ++parsed;
639 ++id;
640 }
641
642 /* pos */
643 if (isdigit(id[0])) {
644 if (name) {
645 *name = id;
646 }
647
648 if (id[0] == '0') {
649 ++parsed;
650 ++id;
651
652 if (isdigit(id[0])) {
653 return -parsed;
654 }
655 }
656
657 while (isdigit(id[0])) {
658 ++parsed;
659 ++id;
660 }
661
662 if (nam_len) {
663 *nam_len = id-(*name);
664 }
665
666 /* "." */
667 } else if (id[0] == '.') {
668 if (name) {
669 *name = id;
670 }
671 if (nam_len) {
672 *nam_len = 1;
673 }
674
675 ++parsed;
676 ++id;
677
678 /* node-identifier */
679 } else {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200680 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200681 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200682 } else if (model && !*model) {
683 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200684 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200685
686 parsed += ret;
687 id += ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200688 }
689
690 while (isspace(id[0])) {
691 ++parsed;
692 ++id;
693 }
694
695 if (id[0] != '=') {
696 return -parsed;
697 }
698
699 ++parsed;
700 ++id;
701
702 while (isspace(id[0])) {
703 ++parsed;
704 ++id;
705 }
706
707 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
708 if ((id[0] == '\"') || (id[0] == '\'')) {
709 quote = id[0];
710
711 ++parsed;
712 ++id;
713
714 if ((ptr = strchr(id, quote)) == NULL) {
715 return -parsed;
716 }
717 ret = ptr-id;
718
719 if (value) {
720 *value = id;
721 }
722 if (val_len) {
723 *val_len = ret;
724 }
725
726 parsed += ret+1;
727 id += ret+1;
728 } else {
729 return -parsed;
730 }
731
732 while (isspace(id[0])) {
733 ++parsed;
734 ++id;
735 }
736
737 if (id[0] != ']') {
738 return -parsed;
739 }
740
741 ++parsed;
742 ++id;
743
744 if ((id[0] == '[') && has_predicate) {
745 *has_predicate = 1;
746 }
747
748 return parsed;
749}
750
751/**
752 * @brief Parse schema-nodeid.
753 *
754 * schema-nodeid = absolute-schema-nodeid /
755 * descendant-schema-nodeid
756 * absolute-schema-nodeid = 1*("/" node-identifier)
757 * descendant-schema-nodeid =
758 * node-identifier
759 * absolute-schema-nodeid
760 *
Michal Vaskobb211122015-08-19 14:03:11 +0200761 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200762 * @param[out] mod_name Points to the module name, NULL if there is not any.
763 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200764 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
765 * @param[out] nam_len Length of the node name.
766 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
767 * on the first call, must not be changed between consecutive calls.
768 *
769 * @return Number of characters successfully parsed,
770 * positive on success, negative on failure.
771 */
772static int
Michal Vasko723e50c2015-10-20 15:20:29 +0200773parse_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 +0200774 int *is_relative)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200775{
776 int parsed = 0, ret;
777
778 assert(id);
779 assert(is_relative);
Michal Vasko723e50c2015-10-20 15:20:29 +0200780 if (mod_name) {
781 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200782 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200783 if (mod_name_len) {
784 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200785 }
786 if (name) {
787 *name = NULL;
788 }
789 if (nam_len) {
790 *nam_len = 0;
791 }
792
793 if (id[0] != '/') {
794 if (*is_relative != -1) {
795 return -parsed;
796 } else {
797 *is_relative = 1;
798 }
799 } else {
800 if (*is_relative == -1) {
801 *is_relative = 0;
802 }
803 ++parsed;
804 ++id;
805 }
806
Michal Vasko723e50c2015-10-20 15:20:29 +0200807 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200808 return -parsed+ret;
809 }
810
811 return parsed+ret;
812}
813
814/**
Michal Vasko730dfdf2015-08-11 14:48:05 +0200815 * @brief Resolves length or range intervals. Does not log.
816 * Syntax is assumed to be correct, *local_intv MUST be NULL.
817 *
818 * @param[in] str_restr The restriction as a string.
819 * @param[in] type The type of the restriction.
820 * @param[in] superior_restr Flag whether to check superior
821 * types.
822 * @param[out] local_intv The final interval structure.
823 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +0200824 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +0200825 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200826int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200827resolve_len_ran_interval(const char *str_restr, struct lys_type *type, int superior_restr,
828 struct len_ran_intv** local_intv)
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200829{
830 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vasko3ab70fc2015-08-17 14:06:23 +0200831 int kind, rc = EXIT_SUCCESS;
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200832 int64_t local_smin, local_smax;
833 uint64_t local_umin, local_umax;
834 long double local_fmin, local_fmax;
835 const char *seg_ptr, *ptr;
Michal Vaskoe01eca52015-08-13 14:42:02 +0200836 struct len_ran_intv *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200837
838 switch (type->base) {
839 case LY_TYPE_BINARY:
840 kind = 0;
841 local_umin = 0;
842 local_umax = 18446744073709551615UL;
843
844 if (!str_restr && type->info.binary.length) {
845 str_restr = type->info.binary.length->expr;
846 }
847 break;
848 case LY_TYPE_DEC64:
849 kind = 2;
850 local_fmin = -9223372036854775808.0;
851 local_fmin /= 1 << type->info.dec64.dig;
852 local_fmax = 9223372036854775807.0;
853 local_fmax /= 1 << type->info.dec64.dig;
854
855 if (!str_restr && type->info.dec64.range) {
856 str_restr = type->info.dec64.range->expr;
857 }
858 break;
859 case LY_TYPE_INT8:
860 kind = 1;
861 local_smin = -128;
862 local_smax = 127;
863
864 if (!str_restr && type->info.num.range) {
865 str_restr = type->info.num.range->expr;
866 }
867 break;
868 case LY_TYPE_INT16:
869 kind = 1;
870 local_smin = -32768;
871 local_smax = 32767;
872
873 if (!str_restr && type->info.num.range) {
874 str_restr = type->info.num.range->expr;
875 }
876 break;
877 case LY_TYPE_INT32:
878 kind = 1;
879 local_smin = -2147483648;
880 local_smax = 2147483647;
881
882 if (!str_restr && type->info.num.range) {
883 str_restr = type->info.num.range->expr;
884 }
885 break;
886 case LY_TYPE_INT64:
887 kind = 1;
888 local_smin = -9223372036854775807L - 1L;
889 local_smax = 9223372036854775807L;
890
891 if (!str_restr && type->info.num.range) {
892 str_restr = type->info.num.range->expr;
893 }
894 break;
895 case LY_TYPE_UINT8:
896 kind = 0;
897 local_umin = 0;
898 local_umax = 255;
899
900 if (!str_restr && type->info.num.range) {
901 str_restr = type->info.num.range->expr;
902 }
903 break;
904 case LY_TYPE_UINT16:
905 kind = 0;
906 local_umin = 0;
907 local_umax = 65535;
908
909 if (!str_restr && type->info.num.range) {
910 str_restr = type->info.num.range->expr;
911 }
912 break;
913 case LY_TYPE_UINT32:
914 kind = 0;
915 local_umin = 0;
916 local_umax = 4294967295;
917
918 if (!str_restr && type->info.num.range) {
919 str_restr = type->info.num.range->expr;
920 }
921 break;
922 case LY_TYPE_UINT64:
923 kind = 0;
924 local_umin = 0;
925 local_umax = 18446744073709551615UL;
926
927 if (!str_restr && type->info.num.range) {
928 str_restr = type->info.num.range->expr;
929 }
930 break;
931 case LY_TYPE_STRING:
932 kind = 0;
933 local_umin = 0;
934 local_umax = 18446744073709551615UL;
935
936 if (!str_restr && type->info.str.length) {
937 str_restr = type->info.str.length->expr;
938 }
939 break;
940 default:
941 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +0200942 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200943 }
944
945 /* process superior types */
946 if (type->der && superior_restr) {
Michal Vasko0c888fd2015-08-11 15:54:08 +0200947 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
948 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +0200949 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +0200950 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200951 assert(!intv || (intv->kind == kind));
952 }
953
954 if (!str_restr) {
955 /* we are validating data and not have any restriction, but a superior type might have */
956 if (type->der && !superior_restr && !intv) {
Michal Vasko0c888fd2015-08-11 15:54:08 +0200957 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
958 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +0200959 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +0200960 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200961 assert(!intv || (intv->kind == kind));
962 }
963 *local_intv = intv;
964 return EXIT_SUCCESS;
965 }
966
967 /* adjust local min and max */
968 if (intv) {
969 tmp_intv = intv;
970
971 if (kind == 0) {
972 local_umin = tmp_intv->value.uval.min;
973 } else if (kind == 1) {
974 local_smin = tmp_intv->value.sval.min;
975 } else if (kind == 2) {
976 local_fmin = tmp_intv->value.fval.min;
977 }
978
979 while (tmp_intv->next) {
980 tmp_intv = tmp_intv->next;
981 }
982
983 if (kind == 0) {
984 local_umax = tmp_intv->value.uval.max;
985 } else if (kind == 1) {
986 local_smax = tmp_intv->value.sval.max;
987 } else if (kind == 2) {
988 local_fmax = tmp_intv->value.fval.max;
989 }
990 }
991
992 /* finally parse our restriction */
993 seg_ptr = str_restr;
994 while (1) {
Michal Vaskoe01eca52015-08-13 14:42:02 +0200995 if (!*local_intv && !tmp_local_intv) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +0200996 *local_intv = malloc(sizeof **local_intv);
997 tmp_local_intv = *local_intv;
998 } else {
999 tmp_local_intv->next = malloc(sizeof **local_intv);
1000 tmp_local_intv = tmp_local_intv->next;
1001 }
1002
1003 tmp_local_intv->kind = kind;
1004 tmp_local_intv->next = NULL;
1005
1006 /* min */
1007 ptr = seg_ptr;
1008 while (isspace(ptr[0])) {
1009 ++ptr;
1010 }
1011 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1012 if (kind == 0) {
1013 tmp_local_intv->value.uval.min = atoll(ptr);
1014 } else if (kind == 1) {
1015 tmp_local_intv->value.sval.min = atoll(ptr);
1016 } else if (kind == 2) {
1017 tmp_local_intv->value.fval.min = atoll(ptr);
1018 }
1019
1020 if ((ptr[0] == '+') || (ptr[0] == '-')) {
1021 ++ptr;
1022 }
1023 while (isdigit(ptr[0])) {
1024 ++ptr;
1025 }
1026 } else if (!strncmp(ptr, "min", 3)) {
1027 if (kind == 0) {
1028 tmp_local_intv->value.uval.min = local_umin;
1029 } else if (kind == 1) {
1030 tmp_local_intv->value.sval.min = local_smin;
1031 } else if (kind == 2) {
1032 tmp_local_intv->value.fval.min = local_fmin;
1033 }
1034
1035 ptr += 3;
1036 } else if (!strncmp(ptr, "max", 3)) {
1037 if (kind == 0) {
1038 tmp_local_intv->value.uval.min = local_umax;
1039 } else if (kind == 1) {
1040 tmp_local_intv->value.sval.min = local_smax;
1041 } else if (kind == 2) {
1042 tmp_local_intv->value.fval.min = local_fmax;
1043 }
1044
1045 ptr += 3;
1046 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001047 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001048 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001049 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001050 }
1051
1052 while (isspace(ptr[0])) {
1053 ptr++;
1054 }
1055
1056 /* no interval or interval */
1057 if ((ptr[0] == '|') || !ptr[0]) {
1058 if (kind == 0) {
1059 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
1060 } else if (kind == 1) {
1061 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
1062 } else if (kind == 2) {
1063 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
1064 }
1065 } else if (!strncmp(ptr, "..", 2)) {
1066 /* skip ".." */
1067 ptr += 2;
1068 while (isspace(ptr[0])) {
1069 ++ptr;
1070 }
1071
1072 /* max */
1073 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1074 if (kind == 0) {
1075 tmp_local_intv->value.uval.max = atoll(ptr);
1076 } else if (kind == 1) {
1077 tmp_local_intv->value.sval.max = atoll(ptr);
1078 } else if (kind == 2) {
1079 tmp_local_intv->value.fval.max = atoll(ptr);
1080 }
1081 } else if (!strncmp(ptr, "max", 3)) {
1082 if (kind == 0) {
1083 tmp_local_intv->value.uval.max = local_umax;
1084 } else if (kind == 1) {
1085 tmp_local_intv->value.sval.max = local_smax;
1086 } else if (kind == 2) {
1087 tmp_local_intv->value.fval.max = local_fmax;
1088 }
1089 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001090 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001091 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001092 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001093 }
1094 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001095 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001096 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001097 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001098 }
1099
1100 /* next segment (next OR) */
1101 seg_ptr = strchr(seg_ptr, '|');
1102 if (!seg_ptr) {
1103 break;
1104 }
1105 seg_ptr++;
1106 }
1107
1108 /* check local restrictions against superior ones */
1109 if (intv) {
1110 tmp_intv = intv;
1111 tmp_local_intv = *local_intv;
1112
1113 while (tmp_local_intv && tmp_intv) {
1114 /* reuse local variables */
1115 if (kind == 0) {
1116 local_umin = tmp_local_intv->value.uval.min;
1117 local_umax = tmp_local_intv->value.uval.max;
1118
1119 /* it must be in this interval */
1120 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
1121 /* this interval is covered, next one */
1122 if (local_umax <= tmp_intv->value.uval.max) {
1123 tmp_local_intv = tmp_local_intv->next;
1124 continue;
1125 /* ascending order of restrictions -> fail */
1126 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001127 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001128 goto cleanup;
1129 }
1130 }
1131 } else if (kind == 1) {
1132 local_smin = tmp_local_intv->value.sval.min;
1133 local_smax = tmp_local_intv->value.sval.max;
1134
1135 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
1136 if (local_smax <= tmp_intv->value.sval.max) {
1137 tmp_local_intv = tmp_local_intv->next;
1138 continue;
1139 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001140 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001141 goto cleanup;
1142 }
1143 }
1144 } else if (kind == 2) {
1145 local_fmin = tmp_local_intv->value.fval.min;
1146 local_fmax = tmp_local_intv->value.fval.max;
1147
1148 if ((local_fmin >= tmp_intv->value.fval.min) && (local_fmin <= tmp_intv->value.fval.max)) {
1149 if (local_fmax <= tmp_intv->value.fval.max) {
1150 tmp_local_intv = tmp_local_intv->next;
1151 continue;
1152 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001153 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001154 goto cleanup;
1155 }
1156 }
1157 }
1158
1159 tmp_intv = tmp_intv->next;
1160 }
1161
1162 /* some interval left uncovered -> fail */
1163 if (tmp_local_intv) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001164 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001165 }
1166
1167 }
1168
1169cleanup:
1170 while (intv) {
1171 tmp_intv = intv->next;
1172 free(intv);
1173 intv = tmp_intv;
1174 }
1175
1176 /* fail */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001177 if (rc) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001178 while (*local_intv) {
1179 tmp_local_intv = (*local_intv)->next;
1180 free(*local_intv);
1181 *local_intv = tmp_local_intv;
1182 }
1183 }
1184
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001185 return rc;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001186}
1187
Michal Vasko730dfdf2015-08-11 14:48:05 +02001188/**
1189 * @brief Resolve a typedef. Does not log.
1190 *
1191 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02001192 * @param[in] mod_name Typedef name module name.
1193 * @param[in] module Main module.
1194 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001195 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001196 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001197 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001198 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001199int
Michal Vasko1dca6882015-10-22 14:29:42 +02001200resolve_superior_type(const char *name, const char *mod_name, struct lys_module *module, struct lys_node *parent,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001201 struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001202{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001203 int i, j;
Radek Krejci1574a8d2015-08-03 14:16:52 +02001204 struct lys_tpdf *tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001205 int tpdf_size;
1206
Michal Vasko1dca6882015-10-22 14:29:42 +02001207 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001208 /* no prefix, try built-in types */
1209 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
1210 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001211 if (ret) {
1212 *ret = ly_types[i].def;
1213 }
1214 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001215 }
1216 }
1217 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02001218 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001219 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02001220 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001221 }
1222 }
1223
Michal Vasko1dca6882015-10-22 14:29:42 +02001224 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001225 /* search in local typedefs */
1226 while (parent) {
1227 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02001228 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02001229 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
1230 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001231 break;
1232
Radek Krejci76512572015-08-04 09:47:08 +02001233 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02001234 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
1235 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001236 break;
1237
Radek Krejci76512572015-08-04 09:47:08 +02001238 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02001239 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
1240 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001241 break;
1242
Radek Krejci76512572015-08-04 09:47:08 +02001243 case LYS_RPC:
Radek Krejcib8048692015-08-05 13:36:34 +02001244 tpdf_size = ((struct lys_node_rpc *)parent)->tpdf_size;
1245 tpdf = ((struct lys_node_rpc *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001246 break;
1247
Radek Krejci76512572015-08-04 09:47:08 +02001248 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02001249 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
1250 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001251 break;
1252
Radek Krejci76512572015-08-04 09:47:08 +02001253 case LYS_INPUT:
1254 case LYS_OUTPUT:
Radek Krejci4608ada2015-08-05 16:04:37 +02001255 tpdf_size = ((struct lys_node_rpc_inout *)parent)->tpdf_size;
1256 tpdf = ((struct lys_node_rpc_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001257 break;
1258
1259 default:
1260 parent = parent->parent;
1261 continue;
1262 }
1263
1264 for (i = 0; i < tpdf_size; i++) {
1265 if (!strcmp(tpdf[i].name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001266 if (ret) {
1267 *ret = &tpdf[i];
1268 }
1269 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001270 }
1271 }
1272
1273 parent = parent->parent;
1274 }
Michal Vasko1dca6882015-10-22 14:29:42 +02001275 } else if (mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001276 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02001277 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02001278 if (!module) {
1279 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001280 }
1281 }
1282
1283 /* search in top level typedefs */
1284 for (i = 0; i < module->tpdf_size; i++) {
1285 if (!strcmp(module->tpdf[i].name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001286 if (ret) {
1287 *ret = &module->tpdf[i];
1288 }
1289 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001290 }
1291 }
1292
1293 /* search in submodules */
1294 for (i = 0; i < module->inc_size; i++) {
1295 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
1296 if (!strcmp(module->inc[i].submodule->tpdf[j].name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001297 if (ret) {
1298 *ret = &module->inc[i].submodule->tpdf[j];
1299 }
1300 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001301 }
1302 }
1303 }
1304
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001305 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001306}
1307
Michal Vasko1dca6882015-10-22 14:29:42 +02001308/**
1309 * @brief Check the default \p value of the \p type. Logs directly.
1310 *
1311 * @param[in] type Type definition to use.
1312 * @param[in] value Default value to check.
1313 * @param[in] first Whether this is the first resolution try. Affects logging.
1314 * @param[in] line Line in the input file.
1315 *
1316 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
1317 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001318static int
Michal Vasko1dca6882015-10-22 14:29:42 +02001319check_default(struct lys_type *type, const char *value, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001320{
Michal Vasko1dca6882015-10-22 14:29:42 +02001321 struct lyd_node_leaf_list node;
1322 struct lys_type *iter;
1323 int ret = EXIT_SUCCESS, found;
1324
1325 /* dummy leaf */
1326 node.value_str = value;
1327 node.value_type = type->base;
1328 node.schema = calloc(1, sizeof *node.schema);
1329 node.schema->name = strdup("default");
1330
1331 if (type->base == LY_TYPE_UNION) {
1332 found = 0;
1333 iter = lyp_get_next_union_type(type, NULL, &found);
1334 while (iter) {
1335 node.value_type = iter->base;
1336
1337 /* special case with too much effort required and almost no added value */
1338 if ((iter->base == LY_TYPE_IDENT) || (iter->base == LY_TYPE_INST)) {
1339 LOGVAL(LYE_SPEC, line,
1340 "Union with \"instance-identifier\" or \"identityref\" and a default value is not supported!");
1341 ret = -1;
1342 goto finish;
1343 }
1344
1345 if (!lyp_parse_value(&node, iter, 1, NULL, UINT_MAX)) {
1346 break;
1347 }
1348
1349 found = 0;
1350 iter = lyp_get_next_union_type(type, iter, &found);
1351 }
1352
1353 if (!iter) {
1354 if (!first) {
1355 LOGVAL(LYE_INVAL, line, node.value_str, "default");
1356 }
1357 ret = EXIT_FAILURE;
1358 goto finish;
1359 }
1360
1361 } else if (type->base == LY_TYPE_LEAFREF) {
1362 if (!type->info.lref.target) {
1363 ret = EXIT_FAILURE;
1364 goto finish;
1365 }
1366 ret = check_default(&type->info.lref.target->type, value, first, line);
1367
1368 } else if ((type->base == LY_TYPE_INST) || (type->base == LY_TYPE_IDENT)) {
1369 /* it was converted to JSON format before, nothing else sensible we can do */
1370
1371 } else {
1372 ret = lyp_parse_value(&node, type, 1, NULL, (first ? UINT_MAX : line));
1373 }
1374
1375finish:
1376 if (node.value_type == LY_TYPE_BITS) {
1377 free(node.value.bit);
1378 }
1379 free((char *)node.schema->name);
1380 free(node.schema);
1381
1382 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001383}
1384
Michal Vasko730dfdf2015-08-11 14:48:05 +02001385/**
1386 * @brief Check a key for mandatory attributes. Logs directly.
1387 *
1388 * @param[in] key The key to check.
1389 * @param[in] flags What flags to check.
1390 * @param[in] list The list of all the keys.
1391 * @param[in] index Index of the key in the key list.
1392 * @param[in] name The name of the keys.
1393 * @param[in] len The name length.
1394 * @param[in] line The line in the input file.
1395 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001396 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001397 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001398static int
Michal Vaskof02e3742015-08-05 16:27:02 +02001399check_key(struct lys_node_leaf *key, uint8_t flags, struct lys_node_leaf **list, int index, const char *name, int len,
1400 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001401{
1402 char *dup = NULL;
1403 int j;
1404
1405 /* existence */
1406 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02001407 if (name[len] != '\0') {
1408 dup = strdup(name);
1409 dup[len] = '\0';
1410 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001411 }
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001412 LOGVAL(LYE_KEY_MISS, line, name);
1413 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001414 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001415 }
1416
1417 /* uniqueness */
1418 for (j = index - 1; j >= 0; j--) {
1419 if (list[index] == list[j]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001420 LOGVAL(LYE_KEY_DUP, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001421 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001422 }
1423 }
1424
1425 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02001426 if (key->nodetype != LYS_LEAF) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001427 LOGVAL(LYE_KEY_NLEAF, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001428 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001429 }
1430
1431 /* type of the leaf is not built-in empty */
1432 if (key->type.base == LY_TYPE_EMPTY) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001433 LOGVAL(LYE_KEY_TYPE, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001434 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001435 }
1436
1437 /* config attribute is the same as of the list */
Radek Krejci1574a8d2015-08-03 14:16:52 +02001438 if ((flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001439 LOGVAL(LYE_KEY_CONFIG, line, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001440 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001441 }
1442
1443 return EXIT_SUCCESS;
1444}
1445
Michal Vasko730dfdf2015-08-11 14:48:05 +02001446/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02001447 * @brief Resolve (fill) a unique. Logs directly.
1448 *
1449 * @param[in] parent The parent node of the unique structure.
1450 * @param[in] uniq_str The value of the unique node.
Michal Vaskobb211122015-08-19 14:03:11 +02001451 * @param[in] uniq_s The unique structure to use.
Michal Vasko184521f2015-09-24 13:14:26 +02001452 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001453 * @param[in] line The line in the input file.
1454 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001455 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001456 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001457int
Michal Vasko184521f2015-09-24 13:14:26 +02001458resolve_unique(struct lys_node *parent, const char *uniq_str, struct lys_unique *uniq_s, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001459{
1460 char *uniq_val, *uniq_begin, *start;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001461 int i, j, rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001462
1463 /* count the number of unique values */
1464 uniq_val = uniq_begin = strdup(uniq_str);
1465 uniq_s->leafs_size = 0;
1466 while ((uniq_val = strpbrk(uniq_val, " \t\n"))) {
1467 uniq_s->leafs_size++;
1468 while (isspace(*uniq_val)) {
1469 uniq_val++;
1470 }
1471 }
1472 uniq_s->leafs_size++;
1473 uniq_s->leafs = calloc(uniq_s->leafs_size, sizeof *uniq_s->leafs);
1474
1475 /* interconnect unique values with the leafs */
1476 uniq_val = uniq_begin;
1477 for (i = 0; uniq_val && i < uniq_s->leafs_size; i++) {
1478 start = uniq_val;
1479 if ((uniq_val = strpbrk(start, " \t\n"))) {
1480 *uniq_val = '\0'; /* add terminating NULL byte */
1481 uniq_val++;
1482 while (isspace(*uniq_val)) {
1483 uniq_val++;
1484 }
1485 } /* else only one nodeid present/left already NULL byte terminated */
1486
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001487 rc = resolve_schema_nodeid(start, parent->child, parent->module, LYS_LEAF,
1488 (struct lys_node **)&uniq_s->leafs[i]);
1489 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02001490 if ((rc == -1) || !first) {
1491 LOGVAL(LYE_INARG, line, start, "unique");
1492 if (rc == EXIT_FAILURE) {
1493 LOGVAL(LYE_SPEC, 0, "Target leaf not found.");
1494 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001495 }
1496 goto error;
1497 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001498 if (uniq_s->leafs[i]->nodetype != LYS_LEAF) {
1499 LOGVAL(LYE_INARG, line, start, "unique");
1500 LOGVAL(LYE_SPEC, 0, "Target is not a leaf.");
1501 rc = -1;
1502 goto error;
1503 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001504
1505 for (j = 0; j < i; j++) {
1506 if (uniq_s->leafs[j] == uniq_s->leafs[i]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001507 LOGVAL(LYE_INARG, line, start, "unique");
1508 LOGVAL(LYE_SPEC, 0, "The identifier is not unique");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001509 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001510 goto error;
1511 }
1512 }
1513 }
1514
1515 free(uniq_begin);
1516 return EXIT_SUCCESS;
1517
1518error:
1519
1520 free(uniq_s->leafs);
1521 free(uniq_begin);
1522
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001523 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001524}
1525
Michal Vasko730dfdf2015-08-11 14:48:05 +02001526/**
1527 * @brief Resolve (fill) a grouping in an uses. Logs directly.
1528 *
Michal Vaskobb211122015-08-19 14:03:11 +02001529 * @param[in] uses The uses to use.
Michal Vasko184521f2015-09-24 13:14:26 +02001530 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001531 * @param[in] line The line in the input file.
1532 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001533 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001534 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001535static int
Michal Vasko184521f2015-09-24 13:14:26 +02001536resolve_grouping(struct lys_node_uses *uses, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001537{
Michal Vasko563ef092015-09-04 13:17:23 +02001538 struct lys_module *module;
Michal Vasko2d851a92015-10-20 16:16:36 +02001539 const char *mod_name, *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02001540 int i, mod_name_len, nam_len;
Radek Krejci10c760e2015-08-14 14:45:43 +02001541 struct lys_node *start;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001542
Michal Vasko58090902015-08-13 14:04:15 +02001543 /* parse the identifier, it must be parsed on one call */
Michal Vasko2d851a92015-10-20 16:16:36 +02001544 if ((i = parse_node_identifier(uses->name, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
Michal Vasko58090902015-08-13 14:04:15 +02001545 LOGVAL(LYE_INCHAR, line, uses->name[-i], &uses->name[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001546 return -1;
Michal Vasko58090902015-08-13 14:04:15 +02001547 } else if (uses->name[i]) {
1548 LOGVAL(LYE_INCHAR, line, uses->name[i], &uses->name[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001549 return -1;
Michal Vasko58090902015-08-13 14:04:15 +02001550 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001551
Michal Vasko2d851a92015-10-20 16:16:36 +02001552 if (mod_name) {
Michal Vaskob6729c62015-10-21 12:09:47 +02001553 module = lys_get_import_module(uses->module, NULL, 0, mod_name, mod_name_len);
Michal Vasko563ef092015-09-04 13:17:23 +02001554 if (!module) {
Michal Vasko2d851a92015-10-20 16:16:36 +02001555 LOGVAL(LYE_INMOD_LEN, line, mod_name_len, mod_name);
Michal Vasko563ef092015-09-04 13:17:23 +02001556 return -1;
1557 }
Michal Vasko2bdcca92015-08-17 16:00:45 +02001558 start = module->data;
1559 } else {
Michal Vasko563ef092015-09-04 13:17:23 +02001560 start = (struct lys_node *)uses;
Michal Vasko2bdcca92015-08-17 16:00:45 +02001561 }
1562
Michal Vasko563ef092015-09-04 13:17:23 +02001563 uses->grp = lys_find_grouping_up(name, start, 1);
1564 if (uses->grp) {
1565 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001566 }
1567
Michal Vasko2d851a92015-10-20 16:16:36 +02001568 if (mod_name || !first) {
Michal Vasko184521f2015-09-24 13:14:26 +02001569 LOGVAL(LYE_INRESOLV, line, "grouping", uses->name);
1570 }
Michal Vasko563ef092015-09-04 13:17:23 +02001571 /* import must now be fully resolved */
Michal Vasko2d851a92015-10-20 16:16:36 +02001572 if (mod_name) {
Michal Vasko563ef092015-09-04 13:17:23 +02001573 return -1;
1574 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001575 return EXIT_FAILURE;
1576}
1577
Michal Vasko730dfdf2015-08-11 14:48:05 +02001578/**
1579 * @brief Resolve (find) a feature definition. Logs directly.
1580 *
1581 * @param[in] name Feature name.
1582 * @param[in] module Module to search in.
Michal Vasko184521f2015-09-24 13:14:26 +02001583 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001584 * @param[in] line The line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001585 * @param[out] ret Pointer to the resolved feature. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001586 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001587 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001588 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001589static int
Michal Vasko184521f2015-09-24 13:14:26 +02001590resolve_feature(const char *id, struct lys_module *module, int first, uint32_t line, struct lys_feature **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001591{
Michal Vasko2d851a92015-10-20 16:16:36 +02001592 const char *mod_name, *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02001593 int mod_name_len, nam_len, i, j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001594
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001595 assert(id);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001596 assert(module);
1597
1598 /* check prefix */
Michal Vasko2d851a92015-10-20 16:16:36 +02001599 if ((i = parse_node_identifier(id, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001600 LOGVAL(LYE_INCHAR, line, id[-i], &id[-i]);
1601 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001602 }
1603
Michal Vasko2d851a92015-10-20 16:16:36 +02001604 if (mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001605 /* search in imported modules */
Michal Vaskob6729c62015-10-21 12:09:47 +02001606 module = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskof02e3742015-08-05 16:27:02 +02001607 if (!module) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001608 /* identity refers unknown data model */
Michal Vasko2d851a92015-10-20 16:16:36 +02001609 LOGVAL(LYE_INMOD_LEN, line, mod_name_len, mod_name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001610 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001611 }
1612 } else {
1613 /* search in submodules */
1614 for (i = 0; i < module->inc_size; i++) {
1615 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
1616 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001617 if (ret) {
1618 *ret = &(module->inc[i].submodule->features[j]);
1619 }
1620 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001621 }
1622 }
1623 }
1624 }
1625
1626 /* search in the identified module */
1627 for (j = 0; j < module->features_size; j++) {
1628 if (!strcmp(name, module->features[j].name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001629 if (ret) {
1630 *ret = &module->features[j];
1631 }
1632 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001633 }
1634 }
1635
1636 /* not found */
Michal Vasko184521f2015-09-24 13:14:26 +02001637 if (!first) {
1638 LOGVAL(LYE_INRESOLV, line, "feature", id);
1639 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001640 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001641}
1642
Michal Vasko730dfdf2015-08-11 14:48:05 +02001643/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02001644 * @brief Resolve (find) a schema node based on a schema-nodeid. Does not log.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001645 *
Michal Vasko1be88302015-10-22 16:07:47 +02001646 * node_type - LYS_AUGMENT (searches also RPCs and notifications, augmented nodes are fine, too)
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001647 * - LYS_USES (only descendant-schema-nodeid allowed, ".." not allowed, always return a grouping)
Michal Vaskocc9e12e2015-08-04 16:14:37 +02001648 * - LYS_CHOICE (search only start->child, only descendant-schema-nodeid allowed)
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001649 * - LYS_LEAF (like LYS_USES, but always returns a data node)
1650 *
Michal Vasko1be88302015-10-22 16:07:47 +02001651 * If \p id is absolute, \p start is ignored. If \p id is relative, \p start must be the first child to be searched
1652 * continuing with its siblings. Normally skips augments except \p node_type LYS_AUGMENT (augmenting an augment node).
Michal Vasko730dfdf2015-08-11 14:48:05 +02001653 *
1654 * @param[in] id Schema-nodeid string.
1655 * @param[in] start Start of the relative search.
Michal Vaskobb211122015-08-19 14:03:11 +02001656 * @param[in] mod Module to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001657 * @param[in] node_type Decides how to modify the search.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001658 * @param[out] ret Pointer to the matching node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001659 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001660 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001661 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001662int
1663resolve_schema_nodeid(const char *id, struct lys_node *start, struct lys_module *mod, LYS_NODE node_type,
1664 struct lys_node **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001665{
Michal Vasko723e50c2015-10-20 15:20:29 +02001666 const char *name, *mod_name;
Radek Krejci76512572015-08-04 09:47:08 +02001667 struct lys_node *sibling;
Michal Vasko1be88302015-10-22 16:07:47 +02001668 int i, opts, nam_len, mod_name_len, is_relative = -1;
1669 struct lys_module *prev_mod, *prefix_mod, *start_mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001670 /* 0 - in module, 1 - in 1st submodule, 2 - in 2nd submodule, ... */
1671 uint8_t in_submod = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001672
1673 assert(mod);
1674 assert(id);
1675
Michal Vasko723e50c2015-10-20 15:20:29 +02001676 if ((i = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001677 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001678 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001679 id += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001680
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001681 if (!is_relative && (node_type & (LYS_USES | LYS_CHOICE | LYS_LEAF))) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001682 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001683 }
1684
Michal Vasko1be88302015-10-22 16:07:47 +02001685 /* set options for lys_getnext() */
1686 opts = LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT;
1687 if (node_type == LYS_USES) {
1688 opts |= LYS_GETNEXT_WITHGROUPING;
1689 }
1690
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001691 /* absolute-schema-nodeid */
1692 if (!is_relative) {
Michal Vasko723e50c2015-10-20 15:20:29 +02001693 if (mod_name) {
Michal Vaskob6729c62015-10-21 12:09:47 +02001694 start_mod = lys_get_import_module(mod, NULL, 0, mod_name, mod_name_len);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001695 if (!start_mod) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001696 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001697 }
1698 start = start_mod->data;
1699 } else {
1700 start = mod->data;
1701 start_mod = mod;
1702 }
1703 /* descendant-schema-nodeid */
1704 } else {
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001705 if (start) {
1706 start_mod = start->module;
1707 } else {
1708 start_mod = mod;
1709 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001710 }
1711
Michal Vasko1be88302015-10-22 16:07:47 +02001712 prev_mod = start_mod;
1713
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001714 while (1) {
Michal Vasko1be88302015-10-22 16:07:47 +02001715 sibling = lys_getnext(NULL, start->parent, start_mod, opts);
1716 while (sibling) {
Michal Vasko1e989c02015-08-04 12:33:00 +02001717 /* name match */
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001718 if (((sibling->nodetype != LYS_GROUPING) || (node_type == LYS_USES))
Michal Vaskoa4b5d322015-10-09 12:12:37 +02001719 && (!(sibling->nodetype & (LYS_RPC | LYS_NOTIF)) || (node_type == LYS_AUGMENT))
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001720 && ((sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len])
Michal Vasko1e989c02015-08-04 12:33:00 +02001721 || (!strncmp(name, "input", 5) && (nam_len == 5) && (sibling->nodetype == LYS_INPUT))
Michal Vaskodcc7a802015-08-06 11:59:47 +02001722 || (!strncmp(name, "output", 6) && (nam_len == 6) && (sibling->nodetype == LYS_OUTPUT)))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001723
Michal Vasko1be88302015-10-22 16:07:47 +02001724 /* module name match check */
Michal Vasko723e50c2015-10-20 15:20:29 +02001725 if (mod_name) {
Michal Vasko1be88302015-10-22 16:07:47 +02001726 prefix_mod = lys_get_import_module(prev_mod, NULL, 0, mod_name, mod_name_len);
1727 if (!prefix_mod && (node_type == LYS_AUGMENT)) {
1728 /* we want augment nodes in this case */
1729 prefix_mod = sibling->module;
1730 if (prefix_mod->type) {
1731 prefix_mod = ((struct lys_submodule *)prefix_mod)->belongsto;
1732 }
1733 if (strncmp(prefix_mod->name, mod_name, mod_name_len) || prefix_mod->name[mod_name_len]) {
1734 prefix_mod = NULL;
1735 }
1736 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001737 if (!prefix_mod) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001738 return -1;
Michal Vasko1e989c02015-08-04 12:33:00 +02001739 }
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001740 } else {
Michal Vasko1be88302015-10-22 16:07:47 +02001741 prefix_mod = prev_mod;
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001742 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001743
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001744 /* modules need to always be checked, we want to skip augments */
1745 if (!sibling->module->type) {
1746 if (prefix_mod != sibling->module) {
Michal Vasko1be88302015-10-22 16:07:47 +02001747 goto next;
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001748 }
1749 } else {
1750 if (prefix_mod != ((struct lys_submodule *)sibling->module)->belongsto) {
Michal Vasko1be88302015-10-22 16:07:47 +02001751 goto next;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001752 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001753 }
Michal Vasko1e989c02015-08-04 12:33:00 +02001754
Michal Vasko1e989c02015-08-04 12:33:00 +02001755 /* the result node? */
1756 if (!id[0]) {
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001757 /* we're looking only for groupings, this is a data node */
1758 if ((node_type == LYS_USES) && (sibling->nodetype != LYS_GROUPING)) {
Michal Vasko1be88302015-10-22 16:07:47 +02001759 goto next;
Michal Vasko2e1a7e42015-08-06 15:08:32 +02001760 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001761 if (ret) {
1762 *ret = sibling;
1763 }
1764 return EXIT_SUCCESS;
Michal Vasko1e989c02015-08-04 12:33:00 +02001765 }
1766
Michal Vaskodcc7a802015-08-06 11:59:47 +02001767 /* we're looking for a grouping (node_type == LYS_USES),
1768 * but this isn't it, we cannot search inside
1769 */
1770 if (sibling->nodetype == LYS_GROUPING) {
Michal Vasko1be88302015-10-22 16:07:47 +02001771 goto next;
Michal Vaskodcc7a802015-08-06 11:59:47 +02001772 }
1773
Michal Vasko1be88302015-10-22 16:07:47 +02001774 /* remember the module */
1775 prev_mod = prefix_mod;
1776
Michal Vasko1e989c02015-08-04 12:33:00 +02001777 /* check for shorthand cases - then 'start' does not change */
1778 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1779 || (sibling->nodetype == LYS_CASE)) {
1780 start = sibling->child;
1781 }
1782 break;
1783 }
Michal Vasko1be88302015-10-22 16:07:47 +02001784
1785next:
1786 sibling = lys_getnext(sibling, start->parent, NULL, opts);
Michal Vasko1e989c02015-08-04 12:33:00 +02001787 }
1788
1789 /* we did not find the case in direct siblings */
1790 if (node_type == LYS_CHOICE) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001791 return -1;
Michal Vasko1e989c02015-08-04 12:33:00 +02001792 }
1793
1794 /* no match */
1795 if (!sibling) {
Michal Vasko1e989c02015-08-04 12:33:00 +02001796 /* are we done with the included submodules as well? */
1797 if (in_submod == start_mod->inc_size) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001798 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001799 }
1800
Michal Vasko1e989c02015-08-04 12:33:00 +02001801 /* we aren't, check the next one */
1802 ++in_submod;
Michal Vasko1e989c02015-08-04 12:33:00 +02001803 start = start_mod->inc[in_submod-1].submodule->data;
1804 continue;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001805 }
1806
1807 /* we found our submodule */
1808 if (in_submod) {
Radek Krejcib8048692015-08-05 13:36:34 +02001809 start_mod = (struct lys_module *)start_mod->inc[in_submod-1].submodule;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001810 in_submod = 0;
1811 }
1812
Michal Vasko723e50c2015-10-20 15:20:29 +02001813 if ((i = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001814 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001815 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001816 id += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001817 }
1818
1819 /* cannot get here */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001820 LOGINT;
1821 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001822}
1823
Michal Vasko23b61ec2015-08-19 11:19:50 +02001824/* ignores line */
1825static void
1826unres_data_del(struct unres_data *unres, uint32_t i)
1827{
1828 /* there are items after the one deleted */
1829 if (i+1 < unres->count) {
1830 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02001831 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02001832
1833 /* deleting the last item */
1834 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02001835 free(unres->node);
1836 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02001837 }
1838
1839 /* if there are no items after and it is not the last one, just move the counter */
1840 --unres->count;
1841}
1842
Michal Vasko0491ab32015-08-19 14:28:29 +02001843/**
1844 * @brief Resolve (find) a data node from a specific module. Does not log.
1845 *
1846 * @param[in] mod Module to search in.
1847 * @param[in] name Name of the data node.
1848 * @param[in] nam_len Length of the name.
1849 * @param[in] start Data node to start the search from.
1850 * @param[in,out] parents Resolved nodes. If there are some parents,
1851 * they are replaced (!!) with the resolvents.
1852 *
1853 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
1854 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001855static int
Michal Vasko23b61ec2015-08-19 11:19:50 +02001856resolve_data(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 +02001857{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001858 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02001859 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02001860 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001861
Michal Vasko23b61ec2015-08-19 11:19:50 +02001862 if (!parents->count) {
1863 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02001864 parents->node = malloc(sizeof *parents->node);
1865 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001866 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02001867 for (i = 0; i < parents->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02001868 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001869 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02001870 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001871 continue;
1872 }
1873 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02001874 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001875 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
1876 && node->schema->name[nam_len] == '\0') {
1877 /* matching target */
1878 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02001879 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02001880 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001881 flag = 1;
1882 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02001883 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02001884 ++parents->count;
Michal Vaskocf024702015-10-08 15:01:42 +02001885 parents->node = realloc(parents->node, parents->count * sizeof *parents->node);
1886 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02001887 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001888 }
1889 }
1890 }
Radek Krejcic5090c32015-08-12 09:46:19 +02001891
1892 if (!flag) {
1893 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02001894 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02001895 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02001896 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02001897 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001898 }
1899
Michal Vasko0491ab32015-08-19 14:28:29 +02001900 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02001901}
1902
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001903/**
1904 * @brief Resolve (find) a data node. Does not log.
1905 *
1906 * @param[in] prefix Prefix of the data node.
1907 * @param[in] pref_len Length of the prefix.
1908 * @param[in] name Name of the data node.
1909 * @param[in] nam_len Length of the name.
1910 * @param[in] start Data node to start the search from.
1911 * @param[in,out] parents Resolved nodes. If there are some parents,
1912 * they are replaced (!!) with the resolvents.
1913 *
Michal Vasko0491ab32015-08-19 14:28:29 +02001914 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001915 */
Radek Krejcic5090c32015-08-12 09:46:19 +02001916static int
Michal Vasko31fc3672015-10-21 12:08:13 +02001917resolve_data_nodeid(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 +02001918 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02001919{
1920 struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02001921 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02001922
Michal Vasko23b61ec2015-08-19 11:19:50 +02001923 assert(start);
1924
Michal Vasko31fc3672015-10-21 12:08:13 +02001925 if (mod_name) {
1926 /* we have mod_name, find appropriate module */
1927 str = strndup(mod_name, mod_name_len);
1928 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
1929 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02001930 if (!mod) {
1931 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001932 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02001933 }
1934 } else {
1935 /* no prefix, module is the same as of current node */
1936 mod = start->schema->module;
1937 }
1938
1939 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001940}
1941
Michal Vasko730dfdf2015-08-11 14:48:05 +02001942/**
Michal Vaskof39142b2015-10-21 11:40:05 +02001943 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Michal Vaskod9173342015-08-17 14:35:36 +02001944 * only specific errors, general no-resolvent error is left to the caller,
1945 * but line fail is always displayed.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001946 *
Michal Vaskobb211122015-08-19 14:03:11 +02001947 * @param[in] pred Predicate to use.
Michal Vasko184521f2015-09-24 13:14:26 +02001948 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko0491ab32015-08-19 14:28:29 +02001949 * @param[in] line Line in the input file.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001950 * @param[in,out] node_match Nodes satisfying the restriction
1951 * without the predicate. Nodes not
1952 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02001953 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001954 *
Michal Vasko0491ab32015-08-19 14:28:29 +02001955 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001956 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001957static int
Michal Vasko184521f2015-09-24 13:14:26 +02001958resolve_path_predicate_data(const char *pred, int first, uint32_t line, struct unres_data *node_match, int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001959{
Michal Vasko730dfdf2015-08-11 14:48:05 +02001960 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02001961 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001962 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02001963 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
1964 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02001965 uint32_t j;
1966
1967 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02001968 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02001969 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02001970 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001971
1972 do {
1973 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
1974 &pke_len, &has_predicate)) < 1) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02001975 LOGVAL(LYE_INCHAR, line, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02001976 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02001977 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001978 }
Michal Vasko0491ab32015-08-19 14:28:29 +02001979 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001980 pred += i;
1981
Michal Vasko23b61ec2015-08-19 11:19:50 +02001982 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001983 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02001984 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02001985
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001986 /* must be leaf (key of a list) */
Michal Vaskocf024702015-10-08 15:01:42 +02001987 if ((rc = resolve_data_nodeid(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
1988 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001989 /* general error, the one written later will suffice */
Michal Vasko184521f2015-09-24 13:14:26 +02001990 if ((rc == -1) || !first) {
1991 LOGVAL(LYE_LINE, line);
1992 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02001993 i = 0;
1994 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001995 }
1996
1997 /* destination */
Michal Vaskocf024702015-10-08 15:01:42 +02001998 dest_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02001999 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002000 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2001 &dest_parent_times)) < 1) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002002 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002003 rc = -1;
2004 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002005 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002006 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002007 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02002008 dest_match.node[0] = dest_match.node[0]->parent;
2009 if (!dest_match.node[0]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002010 /* general error, the one written later will suffice */
Michal Vasko184521f2015-09-24 13:14:26 +02002011 if (!first) {
2012 LOGVAL(LYE_LINE, line);
2013 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002014 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02002015 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002016 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002017 }
2018 }
2019 while (1) {
Michal Vaskocf024702015-10-08 15:01:42 +02002020 if ((rc = resolve_data_nodeid(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02002021 &dest_match)) || (dest_match.count != 1)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002022 /* general error, the one written later will suffice */
Michal Vasko184521f2015-09-24 13:14:26 +02002023 if ((rc == -1) || !first) {
2024 LOGVAL(LYE_LINE, line);
2025 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002026 i = 0;
2027 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002028 }
2029
2030 if (pke_len == pke_parsed) {
2031 break;
2032 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002033 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 +02002034 &dest_parent_times)) < 1) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002035 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002036 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002037 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002038 }
2039 pke_parsed += i;
2040 }
2041
2042 /* check match between source and destination nodes */
Michal Vaskocf024702015-10-08 15:01:42 +02002043 if (((struct lys_node_leaf *)source_match.node[0]->schema)->type.base
2044 != ((struct lys_node_leaf *)dest_match.node[0]->schema)->type.base) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002045 goto remove_leafref;
2046 }
2047
Michal Vasko83a6c462015-10-08 16:43:53 +02002048 if (((struct lyd_node_leaf_list *)source_match.node[0])->value_str
2049 != ((struct lyd_node_leaf_list *)dest_match.node[0])->value_str) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002050 goto remove_leafref;
2051 }
2052
2053 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002054 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002055 continue;
2056
2057remove_leafref:
2058 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002059 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002060 }
2061 } while (has_predicate);
2062
Michal Vaskocf024702015-10-08 15:01:42 +02002063 free(source_match.node);
2064 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02002065 if (parsed) {
2066 *parsed = parsed_loc;
2067 }
2068 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002069
2070error:
2071
2072 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002073 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002074 }
2075 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002076 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002077 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002078 if (parsed) {
2079 *parsed = -parsed_loc+i;
2080 }
2081 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002082}
2083
Michal Vasko730dfdf2015-08-11 14:48:05 +02002084/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002085 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002086 *
Michal Vaskocf024702015-10-08 15:01:42 +02002087 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02002088 * @param[in] path Path of the leafref.
Michal Vasko184521f2015-09-24 13:14:26 +02002089 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko23b61ec2015-08-19 11:19:50 +02002090 * @param[in] line Line in the input file.
Michal Vaskobb211122015-08-19 14:03:11 +02002091 * @param[out] ret Matching nodes. Expects an empty, but allocated structure. Lines left untouched.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002092 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002093 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002094 */
Michal Vasko184521f2015-09-24 13:14:26 +02002095static int
Michal Vaskocf024702015-10-08 15:01:42 +02002096resolve_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 +02002097{
Radek Krejci71b795b2015-08-10 16:20:39 +02002098 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002099 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02002100 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002101 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002102
Michal Vaskocf024702015-10-08 15:01:42 +02002103 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002104
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002105 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02002106 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002107
2108 /* searching for nodeset */
2109 do {
2110 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002111 LOGVAL(LYE_INCHAR, line, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002112 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002113 goto error;
2114 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002115 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002116 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002117
Michal Vasko23b61ec2015-08-19 11:19:50 +02002118 if (!ret->count) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02002119 if (parent_times != -1) {
2120 ret->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002121 ret->node = calloc(1, sizeof *ret->node);
Michal Vasko8bcdf292015-08-19 14:04:43 +02002122 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002123 for (i = 0; i < parent_times; ++i) {
2124 /* relative path */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002125 if (!ret->count) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002126 /* error, too many .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002127 LOGVAL(LYE_INVAL, line, path, node->schema->name);
Michal Vasko0491ab32015-08-19 14:28:29 +02002128 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002129 goto error;
Michal Vaskocf024702015-10-08 15:01:42 +02002130 } else if (!ret->node[0]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002131 /* first .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002132 data = ret->node[0] = node->parent;
2133 } else if (!ret->node[0]->parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002134 /* we are in root */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002135 ret->count = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02002136 free(ret->node);
2137 ret->node = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002138 } else {
2139 /* multiple .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002140 data = ret->node[0] = ret->node[0]->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002141 }
2142 }
2143
2144 /* absolute path */
2145 if (parent_times == -1) {
Michal Vaskocf024702015-10-08 15:01:42 +02002146 for (data = node; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02002147 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko8bcdf292015-08-19 14:04:43 +02002148 if (data->prev) {
2149 for (; data->prev->next; data = data->prev);
2150 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002151 }
2152 }
2153
2154 /* node identifier */
Michal Vasko0491ab32015-08-19 14:28:29 +02002155 if ((rc = resolve_data_nodeid(prefix, pref_len, name, nam_len, data, ret))) {
Michal Vasko184521f2015-09-24 13:14:26 +02002156 if ((rc == -1) || !first) {
2157 LOGVAL(LYE_INELEM_LEN, line, nam_len, name);
2158 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002159 goto error;
2160 }
2161
2162 if (has_predicate) {
2163 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002164 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002165 if (ret->node[j]->schema->nodetype == LYS_LIST &&
2166 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002167 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002168 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002169 continue;
2170 }
2171
2172 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002173 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002174 }
Michal Vasko184521f2015-09-24 13:14:26 +02002175 if ((rc = resolve_path_predicate_data(path, first, line, ret, &i))) {
Michal Vaskod9173342015-08-17 14:35:36 +02002176 /* line was already displayed */
Michal Vasko184521f2015-09-24 13:14:26 +02002177 if ((rc == -1) || !first) {
2178 LOGVAL(LYE_NORESOLV, 0, path);
2179 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002180 goto error;
2181 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002182 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002183 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002184
Michal Vasko23b61ec2015-08-19 11:19:50 +02002185 if (!ret->count) {
Michal Vasko184521f2015-09-24 13:14:26 +02002186 if (!first) {
2187 LOGVAL(LYE_NORESOLV, line, path-parsed);
2188 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002189 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002190 goto error;
2191 }
2192 }
2193 } while (path[0] != '\0');
2194
Michal Vaskof02e3742015-08-05 16:27:02 +02002195 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002196
2197error:
2198
Michal Vaskocf024702015-10-08 15:01:42 +02002199 free(ret->node);
2200 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002201 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002202
Michal Vasko0491ab32015-08-19 14:28:29 +02002203 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002204}
2205
Michal Vasko730dfdf2015-08-11 14:48:05 +02002206/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002207 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002208 *
Michal Vaskobb211122015-08-19 14:03:11 +02002209 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002210 * @param[in] mod Schema module.
2211 * @param[in] source_node Left operand node.
2212 * @param[in] dest_node Right ooperand node.
Michal Vasko184521f2015-09-24 13:14:26 +02002213 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002214 * @param[in] line Line in the input file.
2215 *
Michal Vasko184521f2015-09-24 13:14:26 +02002216 * @return 0 on forward reference, otherwise the number
2217 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002218 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002219 */
Michal Vasko1f76a282015-08-04 16:16:53 +02002220static int
Michal Vasko730dfdf2015-08-11 14:48:05 +02002221resolve_path_predicate_schema(const char *path, struct lys_module *mod, struct lys_node *source_node,
Michal Vasko184521f2015-09-24 13:14:26 +02002222 struct lys_node *dest_node, int first, uint32_t line)
Michal Vasko1f76a282015-08-04 16:16:53 +02002223{
2224 struct lys_node *src_node, *dst_node;
2225 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
2226 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 +02002227 int has_predicate, dest_parent_times = 0, i, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002228
2229 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002230 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02002231 &pke_len, &has_predicate)) < 1) {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002232 LOGVAL(LYE_INCHAR, line, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002233 return -parsed+i;
2234 }
2235 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02002236 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02002237
Michal Vasko58090902015-08-13 14:04:15 +02002238 /* source (must be leaf) */
Michal Vasko1dca6882015-10-22 14:29:42 +02002239 rc = lys_getsibling(mod, source_node->child, sour_pref, sour_pref_len, source, sour_len, LYS_LEAF, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002240 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02002241 if ((rc == -1) || !first) {
2242 LOGVAL(LYE_NORESOLV, line, path-parsed);
2243 }
2244 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002245 }
2246
2247 /* destination */
2248 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2249 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002250 LOGVAL(LYE_INCHAR, line, path_key_expr[-i], path_key_expr-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002251 return -parsed;
2252 }
2253 pke_parsed += i;
2254
2255 /* dest_node is actually the parent of this leaf, so skip the first ".." */
2256 dst_node = dest_node;
2257 for (i = 1; i < dest_parent_times; ++i) {
2258 dst_node = dst_node->parent;
2259 if (!dst_node) {
Michal Vasko184521f2015-09-24 13:14:26 +02002260 if (!first) {
2261 LOGVAL(LYE_NORESOLV, line, path_key_expr);
2262 }
2263 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002264 }
2265 }
2266 while (1) {
Michal Vasko1dca6882015-10-22 14:29:42 +02002267 rc = lys_getsibling(mod, dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002268 LYS_CONTAINER | LYS_LIST | LYS_LEAF, &dst_node);
2269 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02002270 if ((rc == -1) || !first) {
2271 LOGVAL(LYE_NORESOLV, line, path_key_expr);
2272 }
2273 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002274 }
2275
2276 if (pke_len == pke_parsed) {
2277 break;
2278 }
2279
2280 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
2281 &dest_parent_times)) < 1) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002282 LOGVAL(LYE_INCHAR, line, (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002283 return -parsed;
2284 }
2285 pke_parsed += i;
2286 }
2287
2288 /* check source - dest match */
Michal Vasko184521f2015-09-24 13:14:26 +02002289 if (dst_node->nodetype != LYS_LEAF) {
Michal Vaskod9173342015-08-17 14:35:36 +02002290 LOGVAL(LYE_NORESOLV, line, path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02002291 LOGVAL(LYE_SPEC, 0, "Destination node not a leaf, but %s.", strnodetype(dst_node->nodetype));
2292 return -parsed;
2293 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002294 } while (has_predicate);
2295
2296 return parsed;
2297}
2298
Michal Vasko730dfdf2015-08-11 14:48:05 +02002299/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002300 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002301 *
Michal Vaskobb211122015-08-19 14:03:11 +02002302 * @param[in] mod Module to use.
2303 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002304 * @param[in] parent_node Parent of the leafref.
Michal Vasko184521f2015-09-24 13:14:26 +02002305 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002306 * @param[in] line Line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002307 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002308 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002309 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002310 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002311static int
Michal Vasko184521f2015-09-24 13:14:26 +02002312resolve_path_arg_schema(struct lys_module *mod, const char *path, struct lys_node *parent_node, int first,
2313 uint32_t line, struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02002314{
Michal Vasko58090902015-08-13 14:04:15 +02002315 struct lys_node *node;
Michal Vasko1f76a282015-08-04 16:16:53 +02002316 const char *id, *prefix, *name;
2317 int pref_len, nam_len, parent_times, has_predicate;
Michal Vasko184521f2015-09-24 13:14:26 +02002318 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002319
Michal Vasko184521f2015-09-24 13:14:26 +02002320 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002321 parent_times = 0;
2322 id = path;
2323
2324 do {
2325 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vasko58090902015-08-13 14:04:15 +02002326 LOGVAL(LYE_INCHAR, line, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002327 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002328 }
2329 id += i;
2330
Michal Vasko184521f2015-09-24 13:14:26 +02002331 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002332 if (parent_times == -1) {
2333 node = mod->data;
Michal Vasko58090902015-08-13 14:04:15 +02002334 if (!node) {
Michal Vasko184521f2015-09-24 13:14:26 +02002335 if (!first) {
2336 LOGVAL(LYE_NORESOLV, line, path);
2337 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002338 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02002339 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002340 } else if (parent_times > 0) {
Michal Vasko73ae2562015-08-06 11:58:13 +02002341 /* node is the parent already, skip one ".." */
Michal Vasko58090902015-08-13 14:04:15 +02002342 node = parent_node;
2343 i = 0;
2344 while (1) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002345 if (!node) {
Michal Vasko184521f2015-09-24 13:14:26 +02002346 if (!first) {
2347 LOGVAL(LYE_NORESOLV, line, path);
2348 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002349 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02002350 }
Michal Vasko58090902015-08-13 14:04:15 +02002351
2352 /* this node is a wrong node, we actually need the augment target */
2353 if (node->nodetype == LYS_AUGMENT) {
2354 node = ((struct lys_node_augment *)node)->target;
2355 if (!node) {
2356 continue;
2357 }
2358 }
2359
2360 ++i;
2361 if (i == parent_times) {
2362 break;
2363 }
2364 node = node->parent;
Michal Vasko1f76a282015-08-04 16:16:53 +02002365 }
2366 node = node->child;
Michal Vaskoe01eca52015-08-13 14:42:02 +02002367 } else {
2368 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002369 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002370 }
Michal Vasko184521f2015-09-24 13:14:26 +02002371 first_iter = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002372 } else {
2373 node = node->child;
2374 }
2375
Michal Vasko1dca6882015-10-22 14:29:42 +02002376 rc = lys_getsibling(mod, node, prefix, pref_len, name, nam_len, 0, &node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002377 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02002378 if ((rc == -1) || !first) {
2379 LOGVAL(LYE_NORESOLV, line, path);
2380 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002381 return rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002382 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002383
2384 if (has_predicate) {
2385 /* we have predicate, so the current result must be list */
2386 if (node->nodetype != LYS_LIST) {
Michal Vaskod9173342015-08-17 14:35:36 +02002387 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002388 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002389 }
2390
Michal Vasko184521f2015-09-24 13:14:26 +02002391 i = resolve_path_predicate_schema(id, mod, node, parent_node, first, line);
2392 if (!i) {
Michal Vaskof9664da2015-08-24 15:03:30 +02002393 return EXIT_FAILURE;
Michal Vasko184521f2015-09-24 13:14:26 +02002394 } else if (i < 0) {
2395 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002396 }
2397 id += i;
2398 }
2399 } while (id[0]);
2400
Radek Krejcib1c12512015-08-11 11:22:04 +02002401 /* the target must be leaf or leaf-list */
2402 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vaskod9173342015-08-17 14:35:36 +02002403 LOGVAL(LYE_NORESOLV, line, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002404 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02002405 }
2406
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002407 if (ret) {
2408 *ret = node;
2409 }
2410 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02002411}
2412
Michal Vasko730dfdf2015-08-11 14:48:05 +02002413/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002414 * @brief Resolve instance-identifier predicate in JSON data format.
2415 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002416 *
Michal Vaskobb211122015-08-19 14:03:11 +02002417 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002418 * @param[in,out] node_match Nodes matching the restriction without
2419 * the predicate. Nodes not satisfying
2420 * the predicate are removed.
2421 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002422 * @return Number of characters successfully parsed,
2423 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002424 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002425static int
Michal Vaskof39142b2015-10-21 11:40:05 +02002426resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002427{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002428 /* ... /node[target = value] ... */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002429 struct unres_data target_match;
2430 struct ly_ctx *ctx;
2431 struct lys_module *mod;
2432 const char *model, *name, *value;
2433 char *str;
2434 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed;
2435 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002436
Michal Vasko1f2cc332015-08-19 11:18:32 +02002437 assert(pred && node_match->count);
2438
Michal Vaskocf024702015-10-08 15:01:42 +02002439 ctx = node_match->node[0]->schema->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002440 idx = -1;
2441 parsed = 0;
2442
2443 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02002444 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002445 return -parsed+i;
2446 }
2447 parsed += i;
2448 pred += i;
2449
Michal Vasko1f2cc332015-08-19 11:18:32 +02002450 /* pos */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002451 if (isdigit(name[0])) {
2452 idx = atoi(name);
2453 }
2454
Michal Vasko1f2cc332015-08-19 11:18:32 +02002455 for (cur_idx = 0, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002456 /* target */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002457 memset(&target_match, 0, sizeof target_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002458 if ((name[0] == '.') || !value) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002459 target_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002460 target_match.node = malloc(sizeof *target_match.node);
2461 target_match.node[0] = node_match->node[j];
Michal Vasko1f2cc332015-08-19 11:18:32 +02002462 } else {
2463 str = strndup(model, mod_len);
2464 mod = ly_ctx_get_module(ctx, str, NULL);
2465 free(str);
2466
Michal Vaskocf024702015-10-08 15:01:42 +02002467 if (resolve_data(mod, name, nam_len, node_match->node[j], &target_match)) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002468 goto remove_instid;
2469 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002470 }
2471
2472 /* check that we have the correct type */
2473 if (name[0] == '.') {
Michal Vaskocf024702015-10-08 15:01:42 +02002474 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002475 goto remove_instid;
2476 }
2477 } else if (value) {
Michal Vaskocf024702015-10-08 15:01:42 +02002478 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002479 goto remove_instid;
2480 }
2481 }
2482
Michal Vasko83a6c462015-10-08 16:43:53 +02002483 if ((value && (strncmp(((struct lyd_node_leaf_list *)target_match.node[0])->value_str, value, val_len)
2484 || ((struct lyd_node_leaf_list *)target_match.node[0])->value_str[val_len]))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002485 || (!value && (idx != cur_idx))) {
2486 goto remove_instid;
2487 }
2488
Michal Vaskocf024702015-10-08 15:01:42 +02002489 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002490
2491 /* leafref is ok, continue check with next leafref */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002492 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002493 continue;
2494
2495remove_instid:
Michal Vaskocf024702015-10-08 15:01:42 +02002496 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002497
2498 /* does not fulfill conditions, remove leafref record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002499 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002500 }
2501 } while (has_predicate);
2502
2503 return parsed;
2504}
2505
Michal Vasko730dfdf2015-08-11 14:48:05 +02002506/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002507 * @brief Resolve instance-identifier in JSON data format. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002508 *
Radek Krejcic5090c32015-08-12 09:46:19 +02002509 * @param[in] data Any node in the data tree, used to get a data tree root and context
Michal Vasko730dfdf2015-08-11 14:48:05 +02002510 * @param[in] path Instance-identifier node value.
Radek Krejcic5090c32015-08-12 09:46:19 +02002511 * @param[in] line Source line for error messages.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002512 *
Radek Krejcic5090c32015-08-12 09:46:19 +02002513 * @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 +02002514 */
Michal Vasko184521f2015-09-24 13:14:26 +02002515static struct lyd_node *
Michal Vaskof39142b2015-10-21 11:40:05 +02002516resolve_instid(struct lyd_node *data, const char *path, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002517{
Radek Krejcic5090c32015-08-12 09:46:19 +02002518 int i = 0, j;
2519 struct lyd_node *result = NULL;
2520 struct lys_module *mod = NULL;
2521 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002522 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02002523 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002524 int mod_len, name_len, has_predicate;
2525 struct unres_data node_match;
2526 uint32_t k;
2527
2528 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002529
Radek Krejcic5090c32015-08-12 09:46:19 +02002530 /* we need root to resolve absolute path */
2531 for (; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02002532 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko0491ab32015-08-19 14:28:29 +02002533 if (data->prev) {
2534 for (; data->prev->next; data = data->prev);
2535 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002536
Radek Krejcic5090c32015-08-12 09:46:19 +02002537 /* search for the instance node */
2538 while (path[i]) {
Michal Vaskof39142b2015-10-21 11:40:05 +02002539 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02002540 if (j <= 0) {
2541 LOGVAL(LYE_INCHAR, line, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002542 goto error;
2543 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002544 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02002545
Michal Vasko1f2cc332015-08-19 11:18:32 +02002546 str = strndup(model, mod_len);
2547 mod = ly_ctx_get_module(ctx, str, NULL);
2548 free(str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002549
Radek Krejcic5090c32015-08-12 09:46:19 +02002550 if (!mod) {
2551 /* no instance exists */
2552 return NULL;
2553 }
2554
Michal Vasko1f2cc332015-08-19 11:18:32 +02002555 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002556 /* no instance exists */
2557 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002558 }
2559
2560 if (has_predicate) {
2561 /* we have predicate, so the current results must be list or leaf-list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002562 for (k = 0; k < node_match.count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002563 if ((node_match.node[k]->schema->nodetype == LYS_LIST &&
2564 ((struct lys_node_list *)node_match.node[k]->schema)->keys)
2565 || (node_match.node[k]->schema->nodetype == LYS_LEAFLIST)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002566 /* instid is ok, continue check with next instid */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002567 ++k;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002568 continue;
2569 }
2570
2571 /* does not fulfill conditions, remove inst record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002572 unres_data_del(&node_match, k);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002573 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002574
Michal Vaskof39142b2015-10-21 11:40:05 +02002575 j = resolve_predicate(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02002576 if (j < 1) {
2577 LOGVAL(LYE_INPRED, line, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002578 goto error;
2579 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02002580 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02002581
Michal Vasko1f2cc332015-08-19 11:18:32 +02002582 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002583 /* no instance exists */
2584 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002585 }
2586 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002587 }
2588
Michal Vasko1f2cc332015-08-19 11:18:32 +02002589 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002590 /* no instance exists */
2591 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002592 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002593 /* instance identifier must resolve to a single node */
2594 LOGVAL(LYE_TOOMANY, line, path, "data tree");
2595
2596 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02002597 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02002598
2599 return NULL;
2600 } else {
2601 /* we have required result, remember it and cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02002602 result = node_match.node[0];
2603 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02002604
2605 return result;
2606 }
2607
2608error:
2609
2610 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02002611 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02002612
2613 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002614}
2615
Michal Vasko730dfdf2015-08-11 14:48:05 +02002616/**
2617 * @brief Passes config flag down to children. Does not log.
2618 *
2619 * @param[in] node Parent node.
2620 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002621static void
Radek Krejci1d82ef62015-08-07 14:44:40 +02002622inherit_config_flag(struct lys_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002623{
Radek Krejci1d82ef62015-08-07 14:44:40 +02002624 LY_TREE_FOR(node, node) {
2625 node->flags |= node->parent->flags & LYS_CONFIG_MASK;
2626 inherit_config_flag(node->child);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002627 }
2628}
2629
Michal Vasko730dfdf2015-08-11 14:48:05 +02002630/**
Michal Vaskod9173342015-08-17 14:35:36 +02002631 * @brief Resolve augment target. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002632 *
Michal Vaskobb211122015-08-19 14:03:11 +02002633 * @param[in] aug Augment to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002634 * @param[in] siblings Nodes where to start the search in.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002635 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002636 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002637 */
Michal Vasko4adc10f2015-08-11 15:26:17 +02002638int
Michal Vasko1d87a922015-08-21 12:57:16 +02002639resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002640{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002641 int rc;
Michal Vasko1d87a922015-08-21 12:57:16 +02002642 struct lys_node *sub;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002643
Michal Vasko1d87a922015-08-21 12:57:16 +02002644 assert(aug);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002645
2646 /* resolve target node */
Michal Vasko1d87a922015-08-21 12:57:16 +02002647 rc = resolve_schema_nodeid(aug->target_name, siblings, aug->module, LYS_AUGMENT, &aug->target);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002648 if (rc) {
2649 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002650 }
2651
2652 if (!aug->child) {
2653 /* nothing to do */
Michal Vasko1d87a922015-08-21 12:57:16 +02002654 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002655 return EXIT_SUCCESS;
2656 }
2657
2658 /* inherit config information from parent, augment does not have
2659 * config property, but we need to keep the information for subelements
2660 */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002661 aug->flags |= aug->target->flags & LYS_CONFIG_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002662 LY_TREE_FOR(aug->child, sub) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002663 inherit_config_flag(sub);
2664 }
2665
Radek Krejci07911992015-08-14 15:13:31 +02002666 /* check identifier uniquness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02002667 LY_TREE_FOR(aug->child, sub) {
2668 if (lys_check_id(sub, aug->parent, aug->module)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02002669 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02002670 }
2671 }
Radek Krejci0acbe1b2015-08-04 09:33:49 +02002672 /* reconnect augmenting data into the target - add them to the target child list */
2673 if (aug->target->child) {
Michal Vasko1d87a922015-08-21 12:57:16 +02002674 sub = aug->target->child->prev; /* remember current target's last node */
2675 sub->next = aug->child; /* connect augmenting data after target's last node */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02002676 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
Michal Vasko1d87a922015-08-21 12:57:16 +02002677 aug->child->prev = sub; /* finish connecting of both child lists */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02002678 } else {
2679 aug->target->child = aug->child;
2680 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002681
2682 return EXIT_SUCCESS;
2683}
2684
Michal Vasko730dfdf2015-08-11 14:48:05 +02002685/**
2686 * @brief Resolve uses, apply augments, refines. Logs directly.
2687 *
Michal Vaskobb211122015-08-19 14:03:11 +02002688 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002689 * @param[in,out] unres List of unresolved items.
2690 * @param[in] line Line in the input file.
2691 *
Michal Vaskodef0db12015-10-07 13:22:48 +02002692 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002693 */
Michal Vasko184521f2015-09-24 13:14:26 +02002694static int
Michal Vaskodef0db12015-10-07 13:22:48 +02002695resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002696{
2697 struct ly_ctx *ctx;
Radek Krejci1d82ef62015-08-07 14:44:40 +02002698 struct lys_node *node = NULL, *node_aux;
Radek Krejci76512572015-08-04 09:47:08 +02002699 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002700 struct lys_restr *must, **old_must;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002701 int i, j, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002702 uint8_t size, *old_size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002703
Michal Vasko71e1aa82015-08-12 12:17:51 +02002704 assert(uses->grp);
Michal Vaskodef0db12015-10-07 13:22:48 +02002705 /* HACK just check that the grouing is resolved */
2706 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02002707
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002708 /* copy the data nodes from grouping into the uses context */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002709 LY_TREE_FOR(uses->grp->child, node) {
Michal Vasko71e1aa82015-08-12 12:17:51 +02002710 node_aux = lys_node_dup(uses->module, node, uses->flags, uses->nacm, 1, unres);
Radek Krejci1d82ef62015-08-07 14:44:40 +02002711 if (!node_aux) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002712 LOGVAL(LYE_SPEC, line, "Copying data from grouping failed.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002713 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002714 }
Radek Krejci10c760e2015-08-14 14:45:43 +02002715 if (lys_node_addchild((struct lys_node *)uses, NULL, node_aux)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002716 /* error logged */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002717 lys_node_free(node_aux);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002718 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002719 }
2720 }
2721 ctx = uses->module->ctx;
2722
Michal Vaskodef0db12015-10-07 13:22:48 +02002723 /* we managed to copy the grouping, the rest must be possible to resolve */
2724
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002725 /* apply refines */
2726 for (i = 0; i < uses->refine_size; i++) {
2727 rfn = &uses->refine[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002728 rc = resolve_schema_nodeid(rfn->target_name, uses->child, uses->module, LYS_LEAF, &node);
2729 if (rc) {
Michal Vaskodef0db12015-10-07 13:22:48 +02002730 LOGVAL(LYE_INARG, line, rfn->target_name, "refine");
2731 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002732 }
2733
Radek Krejci1d82ef62015-08-07 14:44:40 +02002734 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002735 LOGVAL(LYE_SPEC, line, "Refine substatements not applicable to the target-node.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002736 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002737 }
2738
2739 /* description on any nodetype */
2740 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002741 lydict_remove(ctx, node->dsc);
2742 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002743 }
2744
2745 /* reference on any nodetype */
2746 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002747 lydict_remove(ctx, node->ref);
2748 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002749 }
2750
2751 /* config on any nodetype */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002752 if (rfn->flags & LYS_CONFIG_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002753 node->flags &= ~LYS_CONFIG_MASK;
2754 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002755 }
2756
2757 /* default value ... */
2758 if (rfn->mod.dflt) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002759 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002760 /* leaf */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002761 lydict_remove(ctx, ((struct lys_node_leaf *)node)->dflt);
2762 ((struct lys_node_leaf *)node)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
2763 } else if (node->nodetype == LYS_CHOICE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002764 /* choice */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002765 rc = resolve_schema_nodeid(rfn->mod.dflt, node->child, node->module, LYS_CHOICE, &((struct lys_node_choice *)node)->dflt);
2766 if (rc) {
Michal Vaskodef0db12015-10-07 13:22:48 +02002767 LOGVAL(LYE_INARG, line, rfn->mod.dflt, "default");
2768 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002769 }
2770 }
2771 }
2772
2773 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002774 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002775 if (node->nodetype & (LYS_LEAF | LYS_ANYXML | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002776 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002777 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002778
2779 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002780 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002781 }
2782 }
2783
2784 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002785 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
2786 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
2787 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002788 }
2789
2790 /* min/max-elements on list or leaf-list */
2791 /* magic - bit 3 in flags means min set, bit 4 says max set */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002792 if (node->nodetype == LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002793 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002794 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002795 }
2796 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002797 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002798 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02002799 } else if (node->nodetype == LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002800 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002801 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002802 }
2803 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002804 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002805 }
2806 }
2807
2808 /* must in leaf, leaf-list, list, container or anyxml */
2809 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002810 switch (node->nodetype) {
2811 case LYS_LEAF:
2812 old_size = &((struct lys_node_leaf *)node)->must_size;
2813 old_must = &((struct lys_node_leaf *)node)->must;
2814 break;
2815 case LYS_LEAFLIST:
2816 old_size = &((struct lys_node_leaflist *)node)->must_size;
2817 old_must = &((struct lys_node_leaflist *)node)->must;
2818 break;
2819 case LYS_LIST:
2820 old_size = &((struct lys_node_list *)node)->must_size;
2821 old_must = &((struct lys_node_list *)node)->must;
2822 break;
2823 case LYS_CONTAINER:
2824 old_size = &((struct lys_node_container *)node)->must_size;
2825 old_must = &((struct lys_node_container *)node)->must;
2826 break;
2827 case LYS_ANYXML:
2828 old_size = &((struct lys_node_anyxml *)node)->must_size;
2829 old_must = &((struct lys_node_anyxml *)node)->must;
2830 break;
2831 default:
2832 LOGINT;
Radek Krejcie4e4d722015-10-05 16:53:50 +02002833 return -1;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002834 }
2835
2836 size = *old_size + rfn->must_size;
2837 must = realloc(*old_must, size * sizeof *rfn->must);
2838 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002839 LOGMEM;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002840 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002841 }
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002842 for (i = 0, j = *old_size; i < rfn->must_size; i++, j++) {
2843 must[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
2844 must[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
2845 must[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
2846 must[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
2847 must[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002848 }
2849
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002850 *old_must = must;
2851 *old_size = size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002852 }
2853 }
2854
2855 /* apply augments */
2856 for (i = 0; i < uses->augment_size; i++) {
Michal Vasko1d87a922015-08-21 12:57:16 +02002857 rc = resolve_augment(&uses->augment[i], uses->child);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002858 if (rc) {
Michal Vaskodef0db12015-10-07 13:22:48 +02002859 LOGVAL(LYE_INRESOLV, line, "augment", uses->augment[i].target_name);
2860 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002861 }
2862 }
2863
2864 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002865}
2866
Michal Vasko730dfdf2015-08-11 14:48:05 +02002867/**
2868 * @brief Resolve base identity recursively. Does not log.
2869 *
2870 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02002871 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002872 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002873 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002874 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002875 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002876 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002877static int
2878resolve_base_ident_sub(struct lys_module *module, struct lys_ident *ident, const char *basename,
2879 struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002880{
Michal Vaskof02e3742015-08-05 16:27:02 +02002881 uint32_t i, j;
Radek Krejcia52656e2015-08-05 13:41:50 +02002882 struct lys_ident *base_iter = NULL;
2883 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002884
2885 /* search module */
2886 for (i = 0; i < module->ident_size; i++) {
2887 if (!strcmp(basename, module->ident[i].name)) {
2888
2889 if (!ident) {
2890 /* just search for type, so do not modify anything, just return
2891 * the base identity pointer
2892 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002893 if (ret) {
2894 *ret = &module->ident[i];
2895 }
2896 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002897 }
2898
2899 /* we are resolving identity definition, so now update structures */
2900 ident->base = base_iter = &module->ident[i];
2901
2902 break;
2903 }
2904 }
2905
2906 /* search submodules */
2907 if (!base_iter) {
2908 for (j = 0; j < module->inc_size; j++) {
2909 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
2910 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
2911
2912 if (!ident) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002913 if (ret) {
2914 *ret = &module->inc[j].submodule->ident[i];
2915 }
2916 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002917 }
2918
2919 ident->base = base_iter = &module->inc[j].submodule->ident[i];
2920 break;
2921 }
2922 }
2923 }
2924 }
2925
2926 /* we found it somewhere */
2927 if (base_iter) {
2928 while (base_iter) {
2929 for (der = base_iter->der; der && der->next; der = der->next);
2930 if (der) {
2931 der->next = malloc(sizeof *der);
2932 der = der->next;
2933 } else {
2934 ident->base->der = der = malloc(sizeof *der);
2935 }
2936 der->next = NULL;
2937 der->ident = ident;
2938
2939 base_iter = base_iter->base;
2940 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002941 if (ret) {
2942 *ret = ident->base;
2943 }
2944 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002945 }
2946
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002947 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002948}
2949
Michal Vasko730dfdf2015-08-11 14:48:05 +02002950/**
2951 * @brief Resolve base identity. Logs directly.
2952 *
2953 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02002954 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002955 * @param[in] basename Base name of the identity.
2956 * @param[in] parent Either "type" or "ident".
Michal Vasko184521f2015-09-24 13:14:26 +02002957 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002958 * @param[in] line Line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002959 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002960 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002961 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002962 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002963static int
Michal Vaskof02e3742015-08-05 16:27:02 +02002964resolve_base_ident(struct lys_module *module, struct lys_ident *ident, const char *basename, const char* parent,
Michal Vasko184521f2015-09-24 13:14:26 +02002965 int first, uint32_t line, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002966{
2967 const char *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02002968 int i, mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002969
2970 /* search for the base identity */
2971 name = strchr(basename, ':');
2972 if (name) {
2973 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02002974 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002975 name++;
2976
Michal Vasko2d851a92015-10-20 16:16:36 +02002977 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002978 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02002979 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002980 }
2981 } else {
2982 name = basename;
2983 }
2984
Michal Vasko2d851a92015-10-20 16:16:36 +02002985 if (mod_name_len) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002986 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002987 module = lys_get_import_module(module, NULL, 0, basename, mod_name_len);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002988 if (!module) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002989 /* identity refers unknown data model */
Michal Vasko1dca6882015-10-22 14:29:42 +02002990 LOGVAL(LYE_INMOD, line, basename);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002991 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002992 }
2993 } else {
2994 /* search in submodules */
2995 for (i = 0; i < module->inc_size; i++) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002996 if (!resolve_base_ident_sub((struct lys_module *)module->inc[i].submodule, ident, name, ret)) {
2997 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002998 }
2999 }
3000 }
3001
3002 /* search in the identified module */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003003 if (!resolve_base_ident_sub(module, ident, name, ret)) {
3004 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003005 }
3006
Michal Vasko184521f2015-09-24 13:14:26 +02003007 if (!first) {
3008 LOGVAL(LYE_INARG, line, basename, parent);
3009 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003010 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003011}
3012
Michal Vasko730dfdf2015-08-11 14:48:05 +02003013/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003014 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003015 *
3016 * @param[in] base Base identity.
Michal Vaskofb0873c2015-08-21 09:00:07 +02003017 * @param[in] ident_name Identityref name.
3018 * @param[in] line Line from the input file.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003019 *
3020 * @return Pointer to the identity resolvent, NULL on error.
3021 */
Radek Krejcia52656e2015-08-05 13:41:50 +02003022struct lys_ident *
Michal Vaskof39142b2015-10-21 11:40:05 +02003023resolve_identref(struct lys_ident *base, const char *ident_name, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003024{
Michal Vaskoc633ca02015-08-21 14:03:51 +02003025 const char *mod_name, *name;
3026 int mod_name_len, rc;
Radek Krejcia52656e2015-08-05 13:41:50 +02003027 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003028
Michal Vaskofb0873c2015-08-21 09:00:07 +02003029 if (!base || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003030 return NULL;
3031 }
3032
Michal Vaskoc633ca02015-08-21 14:03:51 +02003033 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskofb0873c2015-08-21 09:00:07 +02003034 if (rc < (signed)strlen(ident_name)) {
3035 LOGVAL(LYE_INCHAR, line, ident_name[-rc], &ident_name[-rc]);
3036 return NULL;
3037 }
3038
Michal Vaskoc633ca02015-08-21 14:03:51 +02003039 if (!strcmp(base->name, name) && (!mod_name
3040 || (!strncmp(base->module->name, mod_name, mod_name_len) && !base->module->name[mod_name_len]))) {
Michal Vaskofb0873c2015-08-21 09:00:07 +02003041 return base;
3042 }
3043
3044 for (der = base->der; der; der = der->next) {
Michal Vaskoc633ca02015-08-21 14:03:51 +02003045 if (!strcmp(der->ident->name, name) && (!mod_name
3046 || (!strncmp(der->ident->module->name, mod_name, mod_name_len)
3047 && !der->ident->module->name[mod_name_len]))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003048 /* we have match */
3049 return der->ident;
3050 }
3051 }
3052
Michal Vaskofb0873c2015-08-21 09:00:07 +02003053 LOGVAL(LYE_INRESOLV, line, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003054 return NULL;
3055}
3056
Michal Vasko730dfdf2015-08-11 14:48:05 +02003057/**
Michal Vasko7955b362015-09-04 14:18:15 +02003058 * @brief Resolve (find) choice default case. Does not log.
3059 *
3060 * @param[in] choic Choice to use.
3061 * @param[in] dflt Name of the default case.
3062 *
3063 * @return Pointer to the default node or NULL.
3064 */
3065static struct lys_node *
3066resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
3067{
3068 struct lys_node *child, *ret;
3069
3070 LY_TREE_FOR(choic->child, child) {
3071 if (child->nodetype == LYS_USES) {
3072 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
3073 if (ret) {
3074 return ret;
3075 }
3076 }
3077
3078 if ((child->name == dflt) && (child->nodetype & (LYS_ANYXML | LYS_CASE
3079 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST))) {
3080 return child;
3081 }
3082 }
3083
3084 return NULL;
3085}
3086
3087/**
Michal Vaskobb211122015-08-19 14:03:11 +02003088 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003089 *
Michal Vaskobb211122015-08-19 14:03:11 +02003090 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003091 * @param[in] unres Specific unres item.
Michal Vasko407f1bb2015-09-23 15:51:07 +02003092 * @param[in] first Whether this is the first resolution try.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003093 * @param[in] line Line in the input file.
3094 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003095 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003096 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003097static int
Michal Vasko407f1bb2015-09-23 15:51:07 +02003098resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003099{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003100 int rc;
Michal Vaskoe91afce2015-08-12 12:21:00 +02003101 struct lys_node *parent;
3102
3103 /* HACK change unres uses count if it's in a grouping (nacm field used for it) */
3104 for (parent = uses->parent; parent && (parent->nodetype != LYS_GROUPING); parent = parent->parent);
3105
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003106 if (!uses->grp) {
Michal Vasko184521f2015-09-24 13:14:26 +02003107 rc = resolve_grouping(uses, first, line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003108 if (rc) {
Michal Vasko407f1bb2015-09-23 15:51:07 +02003109 if (parent && first && (rc == EXIT_FAILURE)) {
3110 ++parent->nacm;
3111 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003112 return rc;
Michal Vasko12e30842015-08-04 11:54:00 +02003113 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003114 }
3115
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003116 if (uses->grp->nacm) {
Michal Vasko407f1bb2015-09-23 15:51:07 +02003117 if (parent && first) {
3118 ++parent->nacm;
3119 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003120 return EXIT_FAILURE;
3121 }
3122
Michal Vaskodef0db12015-10-07 13:22:48 +02003123 rc = resolve_uses(uses, unres, line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003124 if (!rc) {
3125 /* decrease unres count only if not first try */
Michal Vasko407f1bb2015-09-23 15:51:07 +02003126 if (parent && !first) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003127 if (!parent->nacm) {
3128 LOGINT;
3129 return -1;
3130 }
3131 --parent->nacm;
3132 }
3133 return EXIT_SUCCESS;
3134 }
3135
Michal Vasko407f1bb2015-09-23 15:51:07 +02003136 if (parent && first && (rc == EXIT_FAILURE)) {
Michal Vaskoe91afce2015-08-12 12:21:00 +02003137 ++parent->nacm;
3138 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003139 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003140}
3141
Michal Vasko730dfdf2015-08-11 14:48:05 +02003142/**
Michal Vasko9957e592015-08-17 15:04:09 +02003143 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003144 *
Michal Vaskobb211122015-08-19 14:03:11 +02003145 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003146 * @param[in] keys_str Keys node value.
Michal Vasko184521f2015-09-24 13:14:26 +02003147 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003148 * @param[in] line Line in the input file.
3149 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003150 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003151 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003152static int
Michal Vasko184521f2015-09-24 13:14:26 +02003153resolve_list_keys(struct lys_module *mod, struct lys_node_list *list, const char *keys_str, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003154{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003155 int i, len, rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003156 const char *value;
3157
3158 for (i = 0; i < list->keys_size; ++i) {
3159 /* get the key name */
3160 if ((value = strpbrk(keys_str, " \t\n"))) {
3161 len = value - keys_str;
3162 while (isspace(value[0])) {
3163 value++;
3164 }
3165 } else {
3166 len = strlen(keys_str);
3167 }
3168
Michal Vasko1dca6882015-10-22 14:29:42 +02003169 rc = lys_getsibling(mod, list->child, NULL, 0, keys_str, len, LYS_LEAF, (struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003170 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02003171 if ((rc == -1) || !first) {
3172 LOGVAL(LYE_INRESOLV, line, "list keys", keys_str);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003173 }
3174 return rc;
3175 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003176
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003177 if (check_key(list->keys[i], list->flags, list->keys, i, keys_str, len, line)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003178 /* check_key logs */
3179 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003180 }
3181
3182 /* prepare for next iteration */
3183 while (value && isspace(value[0])) {
3184 value++;
3185 }
3186 keys_str = value;
3187 }
3188
Michal Vaskof02e3742015-08-05 16:27:02 +02003189 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003190}
3191
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003192/**
Michal Vaskobf19d252015-10-08 15:39:17 +02003193 * @brief Resolve (check) all must conditions of \p node.
3194 * Logs directly.
3195 *
3196 * @param[in] node Data node with optional must statements.
3197 * @param[in] first Whether this is the first resolution to try.
3198 * @param[in] line Line in the input file.
3199 *
3200 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
3201 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003202static int
Michal Vaskobf19d252015-10-08 15:39:17 +02003203resolve_must(struct lyd_node *node, int first, uint32_t line)
Michal Vaskof02e3742015-08-05 16:27:02 +02003204{
Michal Vaskobf19d252015-10-08 15:39:17 +02003205 uint8_t i, must_size;
3206 struct lys_restr *must;
3207 struct lyxp_set set;
3208
3209 assert(node);
3210 memset(&set, 0, sizeof set);
3211
3212 switch (node->schema->nodetype) {
3213 case LYS_CONTAINER:
3214 must_size = ((struct lys_node_container *)node->schema)->must_size;
3215 must = ((struct lys_node_container *)node->schema)->must;
3216 break;
3217 case LYS_LEAF:
3218 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
3219 must = ((struct lys_node_leaf *)node->schema)->must;
3220 break;
3221 case LYS_LEAFLIST:
3222 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
3223 must = ((struct lys_node_leaflist *)node->schema)->must;
3224 break;
3225 case LYS_LIST:
3226 must_size = ((struct lys_node_list *)node->schema)->must_size;
3227 must = ((struct lys_node_list *)node->schema)->must;
3228 break;
3229 case LYS_ANYXML:
3230 must_size = ((struct lys_node_anyxml *)node->schema)->must_size;
3231 must = ((struct lys_node_anyxml *)node->schema)->must;
3232 break;
3233 default:
3234 must_size = 0;
3235 break;
3236 }
3237
3238 for (i = 0; i < must_size; ++i) {
3239 if (lyxp_eval(must[i].expr, node, &set, line)) {
3240 return -1;
3241 }
3242
3243 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node);
3244
3245 if (!set.value.bool) {
3246 if (!first) {
3247 LOGVAL(LYE_NOCOND, line, "Must", must[i].expr);
3248 }
3249 return 1;
3250 }
3251 }
3252
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003253 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02003254}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003255
Michal Vaskobf19d252015-10-08 15:39:17 +02003256/**
Michal Vaskocf024702015-10-08 15:01:42 +02003257 * @brief Resolve (find) when condition context node. Does not log.
3258 *
3259 * @param[in] node Data node, whose conditional definition is being decided.
3260 * @param[in] schema Schema node with a when condition.
3261 *
3262 * @return Context node.
3263 */
3264static struct lyd_node *
3265resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003266{
Michal Vaskocf024702015-10-08 15:01:42 +02003267 struct lyd_node *parent;
3268 struct lys_node *sparent;
3269 uint16_t i, data_depth, schema_depth;
3270
3271 /* find a not schema-only node */
3272 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
3273 schema = lys_parent(schema);
3274 if (!schema) {
3275 return NULL;
3276 }
3277 }
3278
3279 /* get node depths */
3280 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
3281 for (sparent = lys_parent(schema), schema_depth = 1; sparent; sparent = lys_parent(sparent)) {
3282 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYXML | LYS_NOTIF | LYS_RPC)) {
3283 ++schema_depth;
3284 }
3285 }
3286 if (data_depth < schema_depth) {
3287 return NULL;
3288 }
3289
3290 /* find the corresponding data node */
3291 for (i = 0; i < data_depth - schema_depth; ++i) {
3292 node = node->parent;
3293 }
3294 if (node->schema != schema) {
3295 return NULL;
3296 }
3297
3298 return node;
3299}
3300
3301/**
3302 * @brief Resolve (check) all when conditions relevant for \p node.
3303 * Logs directly.
3304 *
3305 * @param[in] node Data node, whose conditional reference, if such, is being decided.
3306 * @param[in] first Whether this is the first resolution to try.
3307 * @param[in] line Line in the input file.
3308 *
3309 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
3310 */
3311static int
3312resolve_when(struct lyd_node *node, int first, uint32_t line)
3313{
3314 struct lyd_node *ctx_node = NULL;
3315 struct lys_node *parent;
3316 struct lyxp_set set;
3317
3318 assert(node);
3319 memset(&set, 0, sizeof set);
3320
3321 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
3322 if (lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, &set, line)) {
3323 return -1;
3324 }
3325
3326 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node);
3327
3328 if (!set.value.bool) {
3329 if (!first) {
Michal Vaskobf19d252015-10-08 15:39:17 +02003330 LOGVAL(LYE_NOCOND, line, "When", ((struct lys_node_container *)node->schema)->when->cond);
Michal Vaskocf024702015-10-08 15:01:42 +02003331 }
3332 return 1;
3333 }
3334 }
3335
3336 parent = node->schema;
3337 goto check_augment;
3338
3339 /* check when in every schema node that affects node */
3340 while (parent && (parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
3341 if (((struct lys_node_uses *)parent)->when) {
3342 if (!ctx_node) {
3343 ctx_node = resolve_when_ctx_node(node, parent);
3344 if (!ctx_node) {
3345 LOGINT;
3346 return -1;
3347 }
3348 }
3349 if (lyxp_eval(((struct lys_node_uses *)parent)->when->cond, ctx_node, &set, line)) {
3350 return -1;
3351 }
3352
3353 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node);
3354
3355 if (!set.value.bool) {
3356 if (!first) {
Michal Vaskobf19d252015-10-08 15:39:17 +02003357 LOGVAL(LYE_NOCOND, line, "When", ((struct lys_node_uses *)parent)->when->cond);
Michal Vaskocf024702015-10-08 15:01:42 +02003358 }
3359 return 1;
3360 }
3361 }
3362
3363check_augment:
3364 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)parent->parent)->when))) {
3365 if (!ctx_node) {
3366 ctx_node = resolve_when_ctx_node(node, parent->parent);
3367 if (!ctx_node) {
3368 LOGINT;
3369 return -1;
3370 }
3371 }
3372 if (lyxp_eval(((struct lys_node_augment *)parent->parent)->when->cond, ctx_node, &set, line)) {
3373 return -1;
3374 }
3375
3376 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node);
3377
3378 if (!set.value.bool) {
3379 if (!first) {
Michal Vaskobf19d252015-10-08 15:39:17 +02003380 LOGVAL(LYE_NOCOND, line, "When", ((struct lys_node_augment *)parent->parent)->when->cond);
Michal Vaskocf024702015-10-08 15:01:42 +02003381 }
3382 return 1;
3383 }
3384 }
3385
3386 parent = lys_parent(parent);
3387 }
3388
3389 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003390}
3391
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003392/**
Michal Vaskobb211122015-08-19 14:03:11 +02003393 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003394 *
3395 * @param[in] mod Main module.
3396 * @param[in] item Item to resolve. Type determined by \p type.
3397 * @param[in] type Type of the unresolved item.
3398 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02003399 * @param[in] unres Unres schema structure to use.
Michal Vasko407f1bb2015-09-23 15:51:07 +02003400 * @param[in] first Whether this is the first resolution try.
Michal Vasko184521f2015-09-24 13:14:26 +02003401 * @param[in] line Line in the input file. 0 skips line print.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003402 *
3403 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3404 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003405static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003406resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Michal Vasko407f1bb2015-09-23 15:51:07 +02003407 struct unres_schema *unres, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003408{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003409 int rc = -1, has_str = 0;
Michal Vasko563ef092015-09-04 13:17:23 +02003410 struct lys_node *node;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003411 const char *base_name;
3412
3413 struct lys_ident *ident;
3414 struct lys_type *stype;
3415 struct lys_feature **feat_ptr;
3416 struct lys_node_choice *choic;
3417 struct lys_unique *uniq;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003418
3419 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003420 case UNRES_IDENT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003421 base_name = str_snode;
3422 ident = item;
3423
Michal Vasko184521f2015-09-24 13:14:26 +02003424 rc = resolve_base_ident(mod, ident, base_name, "ident", first, line, NULL);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003425 has_str = 1;
3426 break;
3427 case UNRES_TYPE_IDENTREF:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003428 base_name = str_snode;
3429 stype = item;
3430
Michal Vasko184521f2015-09-24 13:14:26 +02003431 rc = resolve_base_ident(mod, NULL, base_name, "type", first, line, &stype->info.ident.ref);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003432 has_str = 1;
3433 break;
3434 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02003435 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003436 stype = item;
3437
Michal Vasko184521f2015-09-24 13:14:26 +02003438 rc = resolve_path_arg_schema(mod, stype->info.lref.path, node, first, line,
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003439 (struct lys_node **)&stype->info.lref.target);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003440 has_str = 0;
3441 break;
3442 case UNRES_TYPE_DER:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003443 base_name = str_snode;
3444 stype = item;
3445
3446 /* HACK type->der is temporarily its parent */
Michal Vasko1dca6882015-10-22 14:29:42 +02003447 rc = resolve_superior_type(base_name, stype->module_name, mod, (struct lys_node *)stype->der, &stype->der);
Michal Vasko0d343d12015-08-24 14:57:36 +02003448 if (rc == -1) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003449 LOGVAL(LYE_INMOD, line, stype->module_name);
Michal Vasko0d343d12015-08-24 14:57:36 +02003450 } else if (!rc) {
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003451 stype->base = stype->der->type.base;
3452 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003453 has_str = 1;
3454 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003455 case UNRES_IFFEAT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003456 base_name = str_snode;
3457 feat_ptr = item;
3458
Michal Vasko184521f2015-09-24 13:14:26 +02003459 rc = resolve_feature(base_name, mod, first, line, feat_ptr);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003460 has_str = 1;
3461 break;
3462 case UNRES_USES:
Michal Vasko407f1bb2015-09-23 15:51:07 +02003463 rc = resolve_unres_schema_uses(item, unres, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003464 has_str = 0;
3465 break;
3466 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003467 base_name = str_snode;
3468 stype = item;
3469
Michal Vasko1dca6882015-10-22 14:29:42 +02003470 rc = check_default(stype, base_name, first, line);
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003471 /* do not remove base_name (dflt), it's in a typedef */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003472 has_str = 0;
3473 break;
3474 case UNRES_CHOICE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003475 base_name = str_snode;
3476 choic = item;
3477
Michal Vasko7955b362015-09-04 14:18:15 +02003478 choic->dflt = resolve_choice_dflt(choic, base_name);
3479 if (choic->dflt) {
3480 rc = EXIT_SUCCESS;
3481 } else {
3482 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003483 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003484 has_str = 1;
3485 break;
3486 case UNRES_LIST_KEYS:
Michal Vasko184521f2015-09-24 13:14:26 +02003487 rc = resolve_list_keys(mod, item, str_snode, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003488 has_str = 1;
3489 break;
3490 case UNRES_LIST_UNIQ:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003491 /* actually the unique string */
3492 base_name = str_snode;
3493 uniq = item;
3494
Michal Vasko184521f2015-09-24 13:14:26 +02003495 rc = resolve_unique((struct lys_node *)uniq->leafs, base_name, uniq, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003496 has_str = 1;
3497 break;
Michal Vaskocf024702015-10-08 15:01:42 +02003498 default:
3499 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003500 break;
3501 }
3502
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003503 if (has_str && !rc) {
3504 lydict_remove(mod->ctx, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003505 }
3506
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003507 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003508}
3509
Michal Vaskof02e3742015-08-05 16:27:02 +02003510/* logs directly */
3511static void
Michal Vasko0bd29d12015-08-19 11:45:49 +02003512print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003513{
Michal Vaskof02e3742015-08-05 16:27:02 +02003514 char line_str[18];
3515
3516 if (line) {
3517 sprintf(line_str, " (line %u)", line);
3518 } else {
3519 line_str[0] = '\0';
3520 }
3521
3522 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003523 case UNRES_IDENT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003524 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identity", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003525 break;
3526 case UNRES_TYPE_IDENTREF:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003527 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identityref", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003528 break;
3529 case UNRES_TYPE_LEAFREF:
3530 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "leafref", ((struct lys_type *)item)->info.lref.path, line_str);
3531 break;
3532 case UNRES_TYPE_DER:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003533 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "derived type", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003534 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02003535 case UNRES_IFFEAT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003536 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 +02003537 break;
3538 case UNRES_USES:
3539 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "uses", ((struct lys_node_uses *)item)->name, line_str);
3540 break;
3541 case UNRES_TYPE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003542 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 +02003543 break;
3544 case UNRES_CHOICE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003545 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 +02003546 break;
3547 case UNRES_LIST_KEYS:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003548 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 +02003549 break;
3550 case UNRES_LIST_UNIQ:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003551 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 +02003552 break;
Michal Vaskocf024702015-10-08 15:01:42 +02003553 default:
3554 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02003555 break;
3556 }
3557}
3558
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003559/**
Michal Vaskobb211122015-08-19 14:03:11 +02003560 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003561 *
3562 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003563 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003564 *
Michal Vasko92b8a382015-08-19 14:03:49 +02003565 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003566 */
Michal Vaskof02e3742015-08-05 16:27:02 +02003567int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003568resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02003569{
Michal Vasko1c4e0ef2015-08-19 11:19:28 +02003570 uint32_t i, resolved, unres_uses, res_uses;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003571 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003572
3573 assert(unres);
3574
Michal Vasko51054ca2015-08-12 12:20:00 +02003575 resolved = 0;
3576
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003577 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02003578 do {
3579 unres_uses = 0;
3580 res_uses = 0;
3581
3582 for (i = 0; i < unres->count; ++i) {
3583 if (unres->type[i] != UNRES_USES) {
3584 continue;
3585 }
3586
3587 ++unres_uses;
Michal Vasko407f1bb2015-09-23 15:51:07 +02003588 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0,
3589 LOGLINE_IDX(unres, i));
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003590 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02003591 unres->type[i] = UNRES_RESOLVED;
3592 ++resolved;
3593 ++res_uses;
Michal Vasko89e15322015-08-17 15:46:55 +02003594 } else if (rc == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003595 return -1;
Michal Vasko51054ca2015-08-12 12:20:00 +02003596 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003597 }
Michal Vasko51054ca2015-08-12 12:20:00 +02003598 } while (res_uses && (res_uses < unres_uses));
3599
3600 if (res_uses < unres_uses) {
3601 LOGVAL(LYE_SPEC, 0, "There are unresolved uses left.");
Michal Vasko92b8a382015-08-19 14:03:49 +02003602 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003603 }
3604
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003605 /* the rest */
3606 for (i = 0; i < unres->count; ++i) {
3607 if (unres->type[i] == UNRES_RESOLVED) {
3608 continue;
3609 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02003610
Michal Vasko407f1bb2015-09-23 15:51:07 +02003611 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0,
3612 LOGLINE_IDX(unres, i));
Michal Vasko184521f2015-09-24 13:14:26 +02003613 if (rc) {
3614 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003615 }
Michal Vasko184521f2015-09-24 13:14:26 +02003616
3617 unres->type[i] = UNRES_RESOLVED;
3618 ++resolved;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003619 }
3620
3621 if (resolved < unres->count) {
Michal Vasko92b8a382015-08-19 14:03:49 +02003622 LOGVAL(LYE_SPEC, 0, "There are unresolved schema items left.");
3623 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003624 }
3625
3626 return EXIT_SUCCESS;
3627}
3628
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003629/**
Michal Vaskobb211122015-08-19 14:03:11 +02003630 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003631 *
3632 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003633 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003634 * @param[in] item Item to resolve. Type determined by \p type.
3635 * @param[in] type Type of the unresolved item.
3636 * @param[in] str String argument.
3637 * @param[in] line Line in the input file.
3638 *
3639 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3640 */
3641int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003642unres_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 +02003643 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003644{
3645 str = lydict_insert(mod->ctx, str, 0);
Michal Vasko0bd29d12015-08-19 11:45:49 +02003646 return unres_schema_add_node(mod, unres, item, type, (struct lys_node *)str, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003647}
3648
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003649/**
Michal Vaskobb211122015-08-19 14:03:11 +02003650 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003651 *
3652 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003653 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003654 * @param[in] item Item to resolve. Type determined by \p type.
3655 * @param[in] type Type of the unresolved item.
3656 * @param[in] snode Schema node argument.
3657 * @param[in] line Line in the input file.
3658 *
3659 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3660 */
3661int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003662unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Michal Vasko7955b362015-09-04 14:18:15 +02003663 struct lys_node *snode, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003664{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003665 int rc;
3666
Michal Vasko9bf425b2015-10-22 11:42:03 +02003667 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
3668 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003669
Michal Vasko184521f2015-09-24 13:14:26 +02003670 rc = resolve_unres_schema_item(mod, item, type, snode, unres, 1, line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003671 if (rc != EXIT_FAILURE) {
3672 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003673 }
3674
Michal Vasko0bd29d12015-08-19 11:45:49 +02003675 print_unres_schema_item_fail(item, type, snode, line);
Michal Vaskof02e3742015-08-05 16:27:02 +02003676
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003677 unres->count++;
3678 unres->item = realloc(unres->item, unres->count*sizeof *unres->item);
3679 unres->item[unres->count-1] = item;
3680 unres->type = realloc(unres->type, unres->count*sizeof *unres->type);
3681 unres->type[unres->count-1] = type;
Radek Krejci1d82ef62015-08-07 14:44:40 +02003682 unres->str_snode = realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003683 unres->str_snode[unres->count-1] = snode;
Michal Vaskoc07187d2015-08-13 15:20:57 +02003684#ifndef NDEBUG
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003685 unres->line = realloc(unres->line, unres->count*sizeof *unres->line);
3686 unres->line[unres->count-1] = line;
Michal Vaskoc07187d2015-08-13 15:20:57 +02003687#endif
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003688
3689 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003690}
3691
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003692/**
Michal Vaskobb211122015-08-19 14:03:11 +02003693 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003694 *
3695 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003696 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003697 * @param[in] item Old item to be resolved.
3698 * @param[in] type Type of the old unresolved item.
3699 * @param[in] new_item New item to use in the duplicate.
3700 *
3701 * @return EXIT_SUCCESS on success, -1 on error.
3702 */
Michal Vaskodad19402015-08-06 09:51:53 +02003703int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003704unres_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 +02003705{
3706 int i;
3707
Michal Vaskocf024702015-10-08 15:01:42 +02003708 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003709
Michal Vasko0bd29d12015-08-19 11:45:49 +02003710 i = unres_schema_find(unres, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003711
3712 if (i == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003713 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003714 }
3715
Michal Vasko0d204592015-10-07 09:50:04 +02003716 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT)) {
Michal Vasko0bd29d12015-08-19 11:45:49 +02003717 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003718 LOGINT;
3719 return -1;
3720 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003721 } else {
Michal Vasko0bd29d12015-08-19 11:45:49 +02003722 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003723 LOGINT;
3724 return -1;
3725 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003726 }
Michal Vaskodad19402015-08-06 09:51:53 +02003727
3728 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003729}
3730
Michal Vaskof02e3742015-08-05 16:27:02 +02003731/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003732int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003733unres_schema_find(struct unres_schema *unres, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003734{
3735 uint32_t ret = -1, i;
3736
3737 for (i = 0; i < unres->count; ++i) {
3738 if ((unres->item[i] == item) && (unres->type[i] == type)) {
3739 ret = i;
3740 break;
3741 }
3742 }
3743
3744 return ret;
3745}
Michal Vasko8bcdf292015-08-19 14:04:43 +02003746
3747/* logs directly */
3748static void
Michal Vaskocf024702015-10-08 15:01:42 +02003749print_unres_data_item_fail(struct lyd_node *node, enum UNRES_ITEM type, uint32_t line)
Michal Vasko8bcdf292015-08-19 14:04:43 +02003750{
3751 struct lys_node_leaf *sleaf;
3752 char line_str[18];
3753
3754 if (line) {
3755 sprintf(line_str, " (line %u)", line);
3756 } else {
3757 line_str[0] = '\0';
3758 }
3759
Michal Vaskocf024702015-10-08 15:01:42 +02003760 sleaf = (struct lys_node_leaf *)node->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003761
Michal Vaskocf024702015-10-08 15:01:42 +02003762 switch (type) {
3763 case UNRES_LEAFREF:
Michal Vasko8bcdf292015-08-19 14:04:43 +02003764 LOGVRB("Leafref \"%s\" could not be resolved, it will be attempted later%s.",
3765 sleaf->type.info.lref.path, line_str);
Michal Vaskocf024702015-10-08 15:01:42 +02003766 break;
3767 case UNRES_INSTID:
Michal Vasko8bcdf292015-08-19 14:04:43 +02003768 LOGVRB("Instance-identifier \"%s\" could not be resolved, it will be attempted later%s.",
Michal Vasko83a6c462015-10-08 16:43:53 +02003769 ((struct lyd_node_leaf_list *)node)->value_str, line_str);
Michal Vaskocf024702015-10-08 15:01:42 +02003770 break;
3771 case UNRES_WHEN:
3772 LOGVRB("There was an unsatisfied when condition, evaluation will be attempted later%s.", line_str);
3773 break;
Michal Vaskobf19d252015-10-08 15:39:17 +02003774 case UNRES_MUST:
3775 LOGVRB("There was an unsatisfied must condition, evaluation will be attempted later%s.", line_str);
3776 break;
Michal Vaskocf024702015-10-08 15:01:42 +02003777 default:
3778 LOGINT;
3779 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003780 }
3781}
3782
3783/**
3784 * @brief Resolve a single unres data item. Logs directly.
3785 *
Michal Vaskocf024702015-10-08 15:01:42 +02003786 * @param[in] node Data node to resolve.
Michal Vasko184521f2015-09-24 13:14:26 +02003787 * @param[in] first Whether this is the first resolution try.
Michal Vaskocf024702015-10-08 15:01:42 +02003788 * @param[in] type Type of the unresolved item.
Michal Vasko184521f2015-09-24 13:14:26 +02003789 * @param[in] line Line in the input file. 0 skips line print.
Michal Vasko8bcdf292015-08-19 14:04:43 +02003790 *
3791 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3792 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02003793int
Michal Vaskocf024702015-10-08 15:01:42 +02003794resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int first, uint32_t line)
Michal Vasko8bcdf292015-08-19 14:04:43 +02003795{
3796 uint32_t i;
Michal Vasko0491ab32015-08-19 14:28:29 +02003797 int rc;
Michal Vasko83a6c462015-10-08 16:43:53 +02003798 struct lyd_node_leaf_list *leaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003799 struct lys_node_leaf *sleaf;
3800 struct unres_data matches;
3801
3802 memset(&matches, 0, sizeof matches);
Michal Vasko83a6c462015-10-08 16:43:53 +02003803 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02003804 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003805
Michal Vaskocf024702015-10-08 15:01:42 +02003806 switch (type) {
3807 case UNRES_LEAFREF:
3808 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vaskof7677612015-10-16 14:27:23 +02003809 if ((rc = resolve_path_arg_data(node, sleaf->type.info.lref.path, first, line, &matches))) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003810 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003811 }
3812
3813 /* check that value matches */
3814 for (i = 0; i < matches.count; ++i) {
Michal Vasko83a6c462015-10-08 16:43:53 +02003815 if (leaf->value_str == ((struct lyd_node_leaf_list *)matches.node[i])->value_str) {
Michal Vaskocf024702015-10-08 15:01:42 +02003816 leaf->value.leafref = matches.node[i];
Michal Vasko8bcdf292015-08-19 14:04:43 +02003817 break;
3818 }
3819 }
3820
Michal Vaskocf024702015-10-08 15:01:42 +02003821 free(matches.node);
Michal Vasko8bcdf292015-08-19 14:04:43 +02003822 memset(&matches, 0, sizeof matches);
3823
Michal Vaskocf024702015-10-08 15:01:42 +02003824 if (!leaf->value.leafref) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02003825 /* reference not found */
Michal Vasko184521f2015-09-24 13:14:26 +02003826 if (!first) {
3827 LOGVAL(LYE_SPEC, line, "Leafref \"%s\" value \"%s\" did not match any node value.",
Michal Vaskocf024702015-10-08 15:01:42 +02003828 sleaf->type.info.lref.path, leaf->value_str);
Michal Vasko184521f2015-09-24 13:14:26 +02003829 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02003830 return EXIT_FAILURE;
3831 }
Michal Vaskocf024702015-10-08 15:01:42 +02003832 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003833
Michal Vaskocf024702015-10-08 15:01:42 +02003834 case UNRES_INSTID:
3835 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko8bcdf292015-08-19 14:04:43 +02003836 ly_errno = 0;
Michal Vaskof39142b2015-10-21 11:40:05 +02003837 if (!resolve_instid(node, leaf->value_str, line)) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02003838 if (ly_errno) {
3839 return -1;
3840 } else if (sleaf->type.info.inst.req > -1) {
Michal Vasko184521f2015-09-24 13:14:26 +02003841 if (!first) {
Michal Vaskocf024702015-10-08 15:01:42 +02003842 LOGVAL(LYE_SPEC, line, "There is no instance of \"%s\".", leaf->value_str);
Michal Vasko184521f2015-09-24 13:14:26 +02003843 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02003844 return EXIT_FAILURE;
3845 } else {
Michal Vaskocf024702015-10-08 15:01:42 +02003846 LOGVRB("There is no instance of \"%s\", but is not required.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02003847 }
3848 }
Michal Vaskocf024702015-10-08 15:01:42 +02003849 break;
3850
3851 case UNRES_WHEN:
3852 if ((rc = resolve_when(node, first, line))) {
3853 return rc;
3854 }
3855 break;
3856
Michal Vaskobf19d252015-10-08 15:39:17 +02003857 case UNRES_MUST:
3858 if ((rc = resolve_must(node, first, line))) {
3859 return rc;
3860 }
3861 break;
3862
Michal Vaskocf024702015-10-08 15:01:42 +02003863 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02003864 LOGINT;
3865 return -1;
3866 }
3867
3868 return EXIT_SUCCESS;
3869}
3870
3871/**
3872 * @brief Try to resolve an unres data item. Logs indirectly.
3873 *
3874 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02003875 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02003876 * @param[in] line Line in the input file.
3877 *
3878 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3879 */
3880int
Michal Vaskocf024702015-10-08 15:01:42 +02003881unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type, uint32_t line)
Michal Vasko8bcdf292015-08-19 14:04:43 +02003882{
3883 int rc;
3884
Michal Vaskobf19d252015-10-08 15:39:17 +02003885 assert(unres && node && ((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)));
Michal Vasko8bcdf292015-08-19 14:04:43 +02003886
Michal Vaskocf024702015-10-08 15:01:42 +02003887 rc = resolve_unres_data_item(node, type, 1, line);
Michal Vasko8bcdf292015-08-19 14:04:43 +02003888 if (rc != EXIT_FAILURE) {
3889 return rc;
3890 }
3891
Michal Vaskocf024702015-10-08 15:01:42 +02003892 print_unres_data_item_fail(node, type, line);
Michal Vasko8bcdf292015-08-19 14:04:43 +02003893
3894 ++unres->count;
Michal Vaskocf024702015-10-08 15:01:42 +02003895 unres->node = realloc(unres->node, unres->count * sizeof *unres->node);
3896 unres->node[unres->count - 1] = node;
3897 unres->type = realloc(unres->type, unres->count * sizeof *unres->type);
3898 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003899#ifndef NDEBUG
Michal Vaskocf024702015-10-08 15:01:42 +02003900 unres->line = realloc(unres->line, unres->count * sizeof *unres->line);
3901 unres->line[unres->count - 1] = line;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003902#endif
3903
3904 return EXIT_SUCCESS;
3905}
3906
3907/**
3908 * @brief Resolve every unres data item in the structure. Logs directly.
3909 *
3910 * @param[in] unres Unres data structure to use.
3911 *
3912 * @return EXIT_SUCCESS on success, -1 on error.
3913 */
3914int
3915resolve_unres_data(struct unres_data *unres)
3916{
3917 uint32_t i;
3918 int rc;
3919
3920 for (i = 0; i < unres->count; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02003921 rc = resolve_unres_data_item(unres->node[i], unres->type[i], 0, LOGLINE_IDX(unres, i));
Michal Vasko8bcdf292015-08-19 14:04:43 +02003922 if (rc) {
3923 LOGVAL(LYE_SPEC, 0, "There are unresolved data items left.");
3924 return -1;
3925 }
3926 }
3927
3928 return EXIT_SUCCESS;
3929}