blob: 2d986e75e94e7607ded4a8a3490ef153d3621516 [file] [log] [blame]
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001#define _GNU_SOURCE
2
3#include <stdlib.h>
4#include <assert.h>
5#include <string.h>
6#include <ctype.h>
7
8#include "libyang.h"
9#include "resolve.h"
10#include "common.h"
11#include "parse.h"
12#include "dict.h"
13#include "tree_internal.h"
14
15struct ly_tpdf *
16resolve_superior_type(const char *name, const char *prefix, struct ly_module *module, struct ly_mnode *parent)
17{
18 int i, j, found = 0;
19 struct ly_tpdf *tpdf;
20 int tpdf_size;
21
22 if (!prefix) {
23 /* no prefix, try built-in types */
24 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
25 if (!strcmp(ly_types[i].def->name, name)) {
26 return ly_types[i].def;
27 }
28 }
29 } else {
30 if (!strcmp(prefix, module->prefix)) {
31 /* prefix refers to the current module, ignore it */
32 prefix = NULL;
33 }
34 }
35
36 if (!prefix && parent) {
37 /* search in local typedefs */
38 while (parent) {
39 switch (parent->nodetype) {
40 case LY_NODE_CONTAINER:
41 tpdf_size = ((struct ly_mnode_container *)parent)->tpdf_size;
42 tpdf = ((struct ly_mnode_container *)parent)->tpdf;
43 break;
44
45 case LY_NODE_LIST:
46 tpdf_size = ((struct ly_mnode_list *)parent)->tpdf_size;
47 tpdf = ((struct ly_mnode_list *)parent)->tpdf;
48 break;
49
50 case LY_NODE_GROUPING:
51 tpdf_size = ((struct ly_mnode_grp *)parent)->tpdf_size;
52 tpdf = ((struct ly_mnode_grp *)parent)->tpdf;
53 break;
54
55 case LY_NODE_RPC:
56 tpdf_size = ((struct ly_mnode_rpc *)parent)->tpdf_size;
57 tpdf = ((struct ly_mnode_rpc *)parent)->tpdf;
58 break;
59
60 case LY_NODE_NOTIF:
61 tpdf_size = ((struct ly_mnode_notif *)parent)->tpdf_size;
62 tpdf = ((struct ly_mnode_notif *)parent)->tpdf;
63 break;
64
65 case LY_NODE_INPUT:
66 case LY_NODE_OUTPUT:
67 tpdf_size = ((struct ly_mnode_input_output *)parent)->tpdf_size;
68 tpdf = ((struct ly_mnode_input_output *)parent)->tpdf;
69 break;
70
71 default:
72 parent = parent->parent;
73 continue;
74 }
75
76 for (i = 0; i < tpdf_size; i++) {
77 if (!strcmp(tpdf[i].name, name)) {
78 return &tpdf[i];
79 }
80 }
81
82 parent = parent->parent;
83 }
84 } else if (prefix) {
85 /* get module where to search */
86 for (i = 0; i < module->imp_size; i++) {
87 if (!strcmp(module->imp[i].prefix, prefix)) {
88 module = module->imp[i].module;
89 found = 1;
90 break;
91 }
92 }
93 if (!found) {
94 return NULL;
95 }
96 }
97
98 /* search in top level typedefs */
99 for (i = 0; i < module->tpdf_size; i++) {
100 if (!strcmp(module->tpdf[i].name, name)) {
101 return &module->tpdf[i];
102 }
103 }
104
105 /* search in submodules */
106 for (i = 0; i < module->inc_size; i++) {
107 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
108 if (!strcmp(module->inc[i].submodule->tpdf[j].name, name)) {
109 return &module->inc[i].submodule->tpdf[j];
110 }
111 }
112 }
113
114 return NULL;
115}
116
117static int
118check_default(struct ly_type *type, const char *value)
119{
120 /* TODO - RFC 6020, sec. 7.3.4 */
121 (void)type;
122 (void)value;
123 return EXIT_SUCCESS;
124}
125
126static int
127check_key(struct ly_mnode_leaf *key, uint8_t flags, struct ly_mnode_leaf **list, int index, unsigned int line,
128 const char *name, int len)
129{
130 char *dup = NULL;
131 int j;
132
133 /* existence */
134 if (!key) {
135 if (name[len] != '\0') {
136 dup = strdup(name);
137 dup[len] = '\0';
138 name = dup;
139 }
140 LOGVAL(VE_KEY_MISS, line, name);
141 free(dup);
142 return EXIT_FAILURE;
143 }
144
145 /* uniqueness */
146 for (j = index - 1; j >= 0; j--) {
147 if (list[index] == list[j]) {
148 LOGVAL(VE_KEY_DUP, line, key->name);
149 return EXIT_FAILURE;
150 }
151 }
152
153 /* key is a leaf */
154 if (key->nodetype != LY_NODE_LEAF) {
155 LOGVAL(VE_KEY_NLEAF, line, key->name);
156 return EXIT_FAILURE;
157 }
158
159 /* type of the leaf is not built-in empty */
160 if (key->type.base == LY_TYPE_EMPTY) {
161 LOGVAL(VE_KEY_TYPE, line, key->name);
162 return EXIT_FAILURE;
163 }
164
165 /* config attribute is the same as of the list */
166 if ((flags & LY_NODE_CONFIG_MASK) != (key->flags & LY_NODE_CONFIG_MASK)) {
167 LOGVAL(VE_KEY_CONFIG, line, key->name);
168 return EXIT_FAILURE;
169 }
170
171 return EXIT_SUCCESS;
172}
173
174int
175resolve_unique(struct ly_mnode *parent, const char *uniq_str, struct ly_unique *uniq_s, int line)
176{
177 char *uniq_val, *uniq_begin, *start;
178 int i, j;
179
180 /* count the number of unique values */
181 uniq_val = uniq_begin = strdup(uniq_str);
182 uniq_s->leafs_size = 0;
183 while ((uniq_val = strpbrk(uniq_val, " \t\n"))) {
184 uniq_s->leafs_size++;
185 while (isspace(*uniq_val)) {
186 uniq_val++;
187 }
188 }
189 uniq_s->leafs_size++;
190 uniq_s->leafs = calloc(uniq_s->leafs_size, sizeof *uniq_s->leafs);
191
192 /* interconnect unique values with the leafs */
193 uniq_val = uniq_begin;
194 for (i = 0; uniq_val && i < uniq_s->leafs_size; i++) {
195 start = uniq_val;
196 if ((uniq_val = strpbrk(start, " \t\n"))) {
197 *uniq_val = '\0'; /* add terminating NULL byte */
198 uniq_val++;
199 while (isspace(*uniq_val)) {
200 uniq_val++;
201 }
202 } /* else only one nodeid present/left already NULL byte terminated */
203
204 uniq_s->leafs[i] = (struct ly_mnode_leaf *)resolve_schema_nodeid(start, parent, parent->module, LY_NODE_USES);
205 if (!uniq_s->leafs[i] || uniq_s->leafs[i]->nodetype != LY_NODE_LEAF) {
206 LOGVAL(VE_INARG, line, start, "unique");
207 if (!uniq_s->leafs[i]) {
208 LOGVAL(VE_SPEC, 0, "Target leaf not found.");
209 } else {
210 LOGVAL(VE_SPEC, 0, "Target is not a leaf.");
211 }
212 goto error;
213 }
214
215 for (j = 0; j < i; j++) {
216 if (uniq_s->leafs[j] == uniq_s->leafs[i]) {
217 LOGVAL(VE_INARG, line, start, "unique");
218 LOGVAL(VE_SPEC, 0, "The identifier is not unique");
219 goto error;
220 }
221 }
222 }
223
224 free(uniq_begin);
225 return EXIT_SUCCESS;
226
227error:
228
229 free(uniq_s->leafs);
230 free(uniq_begin);
231
232 return EXIT_FAILURE;
233}
234
235static int
236resolve_grouping(struct ly_mnode *parent, struct ly_mnode_uses *uses, int line)
237{
238 struct ly_module *searchmod = NULL, *module = uses->module;
239 struct ly_mnode *mnode, *mnode_aux;
240 const char *name;
241 int prefix_len = 0;
242 int i;
243
244 /* get referenced grouping */
245 name = strchr(uses->name, ':');
246 if (!name) {
247 /* no prefix, search in local tree */
248 name = uses->name;
249 } else {
250 /* there is some prefix, check if it refer the same data model */
251
252 /* set name to correct position after colon */
253 prefix_len = name - uses->name;
254 name++;
255
256 if (!strncmp(uses->name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
257 /* prefix refers to the current module, ignore it */
258 prefix_len = 0;
259 }
260 }
261
262 /* search */
263 if (prefix_len) {
264 /* in top-level groupings of some other module */
265 for (i = 0; i < module->imp_size; i++) {
266 if (!strncmp(module->imp[i].prefix, uses->name, prefix_len)
267 && !module->imp[i].prefix[prefix_len]) {
268 searchmod = module->imp[i].module;
269 break;
270 }
271 }
272 if (!searchmod) {
273 /* uses refers unknown data model */
274 LOGVAL(VE_INPREFIX, line, name);
275 return EXIT_FAILURE;
276 }
277
278 LY_TREE_FOR(searchmod->data, mnode) {
279 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
280 uses->grp = (struct ly_mnode_grp *)mnode;
281 return EXIT_SUCCESS;
282 }
283 }
284 } else {
285 /* in local tree hierarchy */
286 for (mnode_aux = parent; mnode_aux; mnode_aux = mnode_aux->parent) {
287 LY_TREE_FOR(mnode_aux->child, mnode) {
288 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
289 uses->grp = (struct ly_mnode_grp *)mnode;
290 return EXIT_SUCCESS;
291 }
292 }
293 }
294
295 /* search in top level of the current module */
296 LY_TREE_FOR(module->data, mnode) {
297 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
298 uses->grp = (struct ly_mnode_grp *)mnode;
299 return EXIT_SUCCESS;
300 }
301 }
302
303 /* search in top-level of included modules */
304 for (i = 0; i < module->inc_size; i++) {
305 LY_TREE_FOR(module->inc[i].submodule->data, mnode) {
306 if (mnode->nodetype == LY_NODE_GROUPING && !strcmp(mnode->name, name)) {
307 uses->grp = (struct ly_mnode_grp *)mnode;
308 return EXIT_SUCCESS;
309 }
310 }
311 }
312 }
313
314 return EXIT_FAILURE;
315}
316
317static struct ly_feature *
318resolve_feature(const char *name, struct ly_module *module, unsigned int line)
319{
320 const char *prefix;
321 unsigned int prefix_len = 0;
322 int i, j, found = 0;
323
324 assert(name);
325 assert(module);
326
327 /* check prefix */
328 prefix = name;
329 name = strchr(prefix, ':');
330 if (name) {
331 /* there is prefix */
332 prefix_len = name - prefix;
333 name++;
334
335 /* check whether the prefix points to the current module */
336 if (!strncmp(prefix, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
337 /* then ignore prefix and works as there is no prefix */
338 prefix_len = 0;
339 }
340 } else {
341 /* no prefix, set pointers correctly */
342 name = prefix;
343 }
344
345 if (prefix_len) {
346 /* search in imported modules */
347 for (i = 0; i < module->imp_size; i++) {
348 if (!strncmp(module->imp[i].prefix, prefix, prefix_len) && !module->imp[i].prefix[prefix_len]) {
349 module = module->imp[i].module;
350 found = 1;
351 break;
352 }
353 }
354 if (!found) {
355 /* identity refers unknown data model */
356 LOGVAL(VE_INPREFIX, line, prefix);
357 return NULL;
358 }
359 } else {
360 /* search in submodules */
361 for (i = 0; i < module->inc_size; i++) {
362 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
363 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
364 return &(module->inc[i].submodule->features[j]);
365 }
366 }
367 }
368 }
369
370 /* search in the identified module */
371 for (j = 0; j < module->features_size; j++) {
372 if (!strcmp(name, module->features[j].name)) {
373 return &module->features[j];
374 }
375 }
376
377 /* not found */
378 return NULL;
379}
380
381static struct ly_module *
382resolve_import_in_includes_recursive(struct ly_module *mod, const char *prefix, uint32_t pref_len)
383{
384 int i, j;
385 struct ly_submodule *sub_mod;
386 struct ly_module *ret;
387
388 for (i = 0; i < mod->inc_size; i++) {
389 sub_mod = mod->inc[i].submodule;
390 for (j = 0; j < sub_mod->imp_size; j++) {
391 if ((pref_len == strlen(sub_mod->imp[j].prefix))
392 && !strncmp(sub_mod->imp[j].prefix, prefix, pref_len)) {
393 return sub_mod->imp[j].module;
394 }
395 }
396 }
397
398 for (i = 0; i < mod->inc_size; i++) {
399 ret = resolve_import_in_includes_recursive((struct ly_module *)mod->inc[i].submodule, prefix, pref_len);
400 if (ret) {
401 return ret;
402 }
403 }
404
405 return NULL;
406}
407
408static struct ly_module *
409resolve_prefixed_module(struct ly_module *mod, const char *prefix, uint32_t pref_len)
410{
411 int i;
412
413 /* module itself */
414 if (!strncmp(mod->prefix, prefix, pref_len) && mod->prefix[pref_len] == '\0') {
415 return mod;
416 }
417
418 /* imported modules */
419 for (i = 0; i < mod->imp_size; i++) {
420 if (!strncmp(mod->imp[i].prefix, prefix, pref_len) && mod->imp[i].prefix[pref_len] == '\0') {
421 return mod->imp[i].module;
422 }
423 }
424
425 /* imports in includes */
426 return resolve_import_in_includes_recursive(mod, prefix, pref_len);
427}
428
429struct ly_mnode *
430resolve_child(struct ly_mnode *parent, const char *name, int len, LY_NODE_TYPE type)
431{
432 struct ly_mnode *child, *result;
433
434 if (!len) {
435 len = strlen(name);
436 }
437
438 LY_TREE_FOR(parent->child, child) {
439 if (child->nodetype == LY_NODE_USES) {
440 /* search recursively */
441 result = resolve_child(child, name, len, type);
442 if (result) {
443 return result;
444 }
445 }
446
447 if (child->nodetype & type) {
448 /* direct check */
449 if (child->name == name || (!strncmp(child->name, name, len) && !child->name[len])) {
450 return child;
451 }
452 }
453 }
454
455 return NULL;
456}
457
458/*
459 * id - schema-nodeid
460 *
461 * node_type - LY_NODE_AUGMENT (searches also RPCs and notifications)
462 * - LY_NODE_USES (only descendant-schema-nodeid allowed, ".." not allowed)
463 * - LY_NODE_CHOICE (search only start->child, only descendant-schema-nodeid allowed)
464 * - LY_NODE_LEAF (resolves path of a leafref - predicates allowed and skipped)
465 */
466struct ly_mnode *
467resolve_schema_nodeid(const char *id, struct ly_mnode *start, struct ly_module *mod, LY_NODE_TYPE node_type)
468{
469 const char *name, *prefix, *ptr;
470 struct ly_mnode *sibling;
471 int ret, nam_len, pref_len, is_relative = -1;
472 struct ly_module *prefix_mod, *start_mod;
473 /* 0 - in module, 1 - in 1st submodule, 2 - in 2nd submodule, ... */
474 uint8_t in_submod = 0;
475 /* 0 - in data, 1 - in RPCs, 2 - in notifications (relevant only with LY_NODE_AUGMENT) */
476 uint8_t in_mod_part = 0;
477
478 assert(mod);
479 assert(id);
480
481 if ((ret = parse_schema_nodeid(id, &prefix, &pref_len, &name, &nam_len, &is_relative)) < 1) {
482 return NULL;
483 }
484 id += ret;
485
486 if (!is_relative && (node_type & (LY_NODE_USES | LY_NODE_CHOICE))) {
487 return NULL;
488 }
489
490 /* absolute-schema-nodeid */
491 if (!is_relative) {
492 if (prefix) {
493 start_mod = resolve_prefixed_module(mod, prefix, pref_len);
494 if (!start_mod) {
495 return NULL;
496 }
497 start = start_mod->data;
498 } else {
499 start = mod->data;
500 start_mod = mod;
501 }
502 /* descendant-schema-nodeid */
503 } else {
504 assert(start);
505 start = start->child;
506 start_mod = start->module;
507 }
508
509 while (1) {
510 if (!strncmp(name, "..", 2)) {
511 /* ".." is not allowed in refines and augments in uses, there is no need for it there */
512 if (!start || (node_type == LY_NODE_USES)) {
513 return NULL;
514 }
515 start = start->parent;
516 } else if (name[0] == '.') {
517 /* this node - start does not change */
518 } else {
519 sibling = NULL;
520 LY_TREE_FOR(start, sibling) {
521 /* name match */
522 if ((sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len])
523 || (!strncmp(name, "input", 5) && (nam_len == 5) && (sibling->nodetype == LY_NODE_INPUT))
524 || (!strncmp(name, "output", 6) && (nam_len == 6) && (sibling->nodetype == LY_NODE_OUTPUT))) {
525
526 /* prefix match check */
527 if (prefix) {
528
529 prefix_mod = resolve_prefixed_module(mod, prefix, pref_len);
530 if (!prefix_mod) {
531 return NULL;
532 }
533
534 if (!sibling->module->type) {
535 if (prefix_mod != sibling->module) {
536 continue;
537 }
538 } else {
539 if (prefix_mod != ((struct ly_submodule *)sibling->module)->belongsto) {
540 continue;
541 }
542 }
543 }
544
545 /* skip the predicate */
546 if ((node_type == LY_NODE_LEAF) && (id[0] == '[')) {
547 ptr = strchr(id, ']');
548 if (ptr) {
549 id = ptr+1;
550 }
551 }
552
553 /* the result node? */
554 if (!id[0]) {
555 return sibling;
556 }
557
558 /* check for shorthand cases - then 'start' does not change */
559 if (!sibling->parent || (sibling->parent->nodetype != LY_NODE_CHOICE)
560 || (sibling->nodetype == LY_NODE_CASE)) {
561 start = sibling->child;
562 }
563 break;
564 }
565 }
566
567 /* we did not find the case in direct siblings */
568 if (node_type == LY_NODE_CHOICE) {
569 return NULL;
570 }
571
572 /* no match */
573 if (!sibling) {
574 /* on augment search also RPCs and notifications, if we are in top-level */
575 if ((node_type == LY_NODE_AUGMENT) && (!start || !start->parent)) {
576 /* we have searched all the data nodes */
577 if (in_mod_part == 0) {
578 if (!in_submod) {
579 start = start_mod->rpc;
580 } else {
581 start = start_mod->inc[in_submod-1].submodule->rpc;
582 }
583 in_mod_part = 1;
584 continue;
585 }
586 /* we have searched all the RPCs */
587 if (in_mod_part == 1) {
588 if (!in_submod) {
589 start = start_mod->notif;
590 } else {
591 start = start_mod->inc[in_submod-1].submodule->notif;
592 }
593 in_mod_part = 2;
594 continue;
595 }
596 /* we have searched all the notifications, nothing else to search in this module */
597 }
598
599 /* are we done with the included submodules as well? */
600 if (in_submod == start_mod->inc_size) {
601 return NULL;
602 }
603
604 /* we aren't, check the next one */
605 ++in_submod;
606 in_mod_part = 0;
607 start = start_mod->inc[in_submod-1].submodule->data;
608 continue;
609 }
610 }
611
612 /* we found our submodule */
613 if (in_submod) {
614 start_mod = (struct ly_module *)start_mod->inc[in_submod-1].submodule;
615 in_submod = 0;
616 }
617
618 if ((ret = parse_schema_nodeid(id, &prefix, &pref_len, &name, &nam_len, &is_relative)) < 1) {
619 return NULL;
620 }
621 id += ret;
622 }
623
624 /* cannot get here */
625 return NULL;
626}
627
628static int
629resolve_data_nodeid(const char *prefix, int pref_len, const char *name, int nam_len, struct lyd_node *data_source,
630 struct leafref_instid **parents)
631{
632 int flag;
633 struct ly_module *mod;
634 struct leafref_instid *item, *par_iter;
635 struct lyd_node *node;
636
637 if (prefix) {
638 /* we have prefix, find appropriate module */
639 mod = resolve_prefixed_module(data_source->schema->module, prefix, pref_len);
640 if (!mod) {
641 /* invalid prefix */
642 return 1;
643 }
644 } else {
645 /* no prefix, module is the same as of current node */
646 mod = data_source->schema->module;
647 }
648
649 if (!*parents) {
650 *parents = malloc(sizeof **parents);
651 (*parents)->dnode = NULL;
652 (*parents)->next = NULL;
653 }
654 for (par_iter = *parents; par_iter; par_iter = par_iter->next) {
655 if (par_iter->dnode && (par_iter->dnode->schema->nodetype & (LY_NODE_LEAF | LY_NODE_LEAFLIST))) {
656 /* skip */
657 continue;
658 }
659 flag = 0;
660 LY_TREE_FOR(par_iter->dnode ? par_iter->dnode->child : data_source, node) {
661 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
662 && node->schema->name[nam_len] == '\0') {
663 /* matching target */
664 if (!flag) {
665 /* replace leafref instead of the current parent */
666 par_iter->dnode = node;
667 flag = 1;
668 } else {
669 /* multiple matching, so create new leafref structure */
670 item = malloc(sizeof *item);
671 item->dnode = node;
672 item->next = par_iter->next;
673 par_iter->next = item;
674 par_iter = par_iter->next;
675 }
676 }
677 }
678 }
679
680 return !flag;
681}
682
683/* ... /node[source = destination] ... */
684static int
685resolve_path_predicate(const char *pred, struct leafref_instid **node_match)
686{
687 struct leafref_instid *source_match, *dest_match, *node, *node_prev = NULL;
688 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
689 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed = 0, pke_parsed = 0;
690 int has_predicate, dest_parent_times, i;
691
692 do {
693 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
694 &pke_len, &has_predicate)) < 1) {
695 return -parsed+i;
696 }
697 parsed += i;
698 pred += i;
699
700 for (node = *node_match; node;) {
701 /* source */
702 source_match = NULL;
703 /* must be leaf (key of a list) */
704 if (resolve_data_nodeid(sour_pref, sour_pref_len, source, sour_len, node->dnode, &source_match)
705 || !source_match || source_match->next
706 || (source_match->dnode->schema->nodetype != LY_NODE_LEAF)) {
707 return -parsed;
708 }
709
710 /* destination */
711 dest_match = calloc(1, sizeof *dest_match);
712 dest_match->dnode = node->dnode;
713 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
714 &dest_parent_times)) < 1) {
715 return -parsed+i;
716 }
717 pke_parsed += i;
718 for (i = 0; i < dest_parent_times; ++i) {
719 dest_match->dnode = dest_match->dnode->parent;
720 if (!dest_match->dnode) {
721 free(dest_match);
722 return -parsed;
723 }
724 }
725 while (1) {
726 if (resolve_data_nodeid(dest_pref, dest_pref_len, dest, dest_len, dest_match->dnode, &dest_match)
727 || !dest_match->dnode || dest_match->next
728 || (dest_match->dnode->schema->nodetype != LY_NODE_LEAF)) {
729 free(dest_match);
730 return -parsed;
731 }
732
733 if (pke_len == pke_parsed) {
734 break;
735 }
736 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
737 &dest_parent_times)) < 1) {
738 return -parsed+i;
739 }
740 pke_parsed += i;
741 }
742
743 /* check match between source and destination nodes */
744 if (((struct ly_mnode_leaf *)source_match->dnode->schema)->type.base
745 != ((struct ly_mnode_leaf *)dest_match->dnode->schema)->type.base) {
746 goto remove_leafref;
747 }
748
749 if (((struct lyd_node_leaf *)source_match->dnode)->value_str
750 != ((struct lyd_node_leaf *)dest_match->dnode)->value_str) {
751 goto remove_leafref;
752 }
753
754 /* leafref is ok, continue check with next leafref */
755 node_prev = node;
756 node = node->next;
757 continue;
758
759remove_leafref:
760 /* does not fulfill conditions, remove leafref record */
761 if (node_prev) {
762 node_prev->next = node->next;
763 free(node);
764 node = node_prev->next;
765 } else {
766 node = (*node_match)->next;
767 free(*node_match);
768 *node_match = node;
769 }
770 }
771 } while (has_predicate);
772
773 return parsed;
774}
775
776int
777resolve_path_arg(struct leafref_instid *unres, const char *path, struct leafref_instid **ret)
778{
779 struct lyd_node *data;
780 struct leafref_instid *riter = NULL, *raux;
781 const char *prefix, *name;
782 int pref_len, nam_len, has_predicate, parsed, parent_times, i;
783
784 *ret = NULL;
785 parsed = 0;
786 parent_times = 0;
787
788 /* searching for nodeset */
789 do {
790 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
791 LOGVAL(DE_INCHAR, unres->line, path[-i], path-i);
792 goto error;
793 }
794 parsed += i;
795 path += i;
796
797 if (!*ret) {
798 *ret = calloc(1, sizeof **ret);
799 for (i = 0; i < parent_times; ++i) {
800 /* relative path */
801 if (!*ret) {
802 /* error, too many .. */
803 LOGVAL(DE_INVAL, unres->line, path, unres->dnode->schema->name);
804 goto error;
805 } else if (!(*ret)->dnode) {
806 /* first .. */
807 (*ret)->dnode = unres->dnode->parent;
808 } else if (!(*ret)->dnode->parent) {
809 /* we are in root */
810 free(*ret);
811 *ret = NULL;
812 } else {
813 /* multiple .. */
814 (*ret)->dnode = (*ret)->dnode->parent;
815 }
816 }
817
818 /* absolute path */
819 if (parent_times == -1) {
820 for (data = unres->dnode; data->parent; data = data->parent);
821 for (; data->prev->next; data = data->prev);
822 }
823 }
824
825 /* node identifier */
826 if (resolve_data_nodeid(prefix, pref_len, name, nam_len, data, ret)) {
827 LOGVAL(DE_INVAL, unres->line, nam_len, name);
828 goto error;
829 }
830
831 if (has_predicate) {
832 /* we have predicate, so the current results must be lists */
833 for (raux = NULL, riter = *ret; riter; ) {
834 if (riter->dnode->schema->nodetype == LY_NODE_LIST &&
835 ((struct ly_mnode_list *)riter->dnode->schema)->keys) {
836 /* leafref is ok, continue check with next leafref */
837 raux = riter;
838 riter = riter->next;
839 continue;
840 }
841
842 /* does not fulfill conditions, remove leafref record */
843 if (raux) {
844 raux->next = riter->next;
845 free(riter);
846 riter = raux->next;
847 } else {
848 *ret = riter->next;
849 free(riter);
850 riter = *ret;
851 }
852 }
853 if ((i = resolve_path_predicate(path, ret)) < 1) {
854 LOGVAL(DE_INPRED, unres->line, path-i);
855 goto error;
856 }
857 parsed += i;
858 path += i;
859
860 if (!*ret) {
861 LOGVAL(DE_NORESOLV, unres->line, name);
862 goto error;
863 }
864 }
865 } while (path[0] != '\0');
866
867 return 0;
868
869error:
870
871 while (*ret) {
872 raux = (*ret)->next;
873 free(*ret);
874 *ret = raux;
875 }
876
877 return 1;
878}
879
880/* ... /node[target = value] ... */
881static int
882resolve_predicate(const char *pred, struct leafref_instid **node_match)
883{
884 struct leafref_instid *target_match, *node, *node_prev = NULL, *tmp;
885 const char *prefix, *name, *value;
886 int pref_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed;
887
888 idx = -1;
889 parsed = 0;
890
891 do {
892 if ((i = parse_predicate(pred, &prefix, &pref_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
893 return -parsed+i;
894 }
895 parsed += i;
896 pred += i;
897
898 if (isdigit(name[0])) {
899 idx = atoi(name);
900 }
901
902 for (cur_idx = 0, node = *node_match; node; ++cur_idx) {
903 /* target */
904 target_match = NULL;
905 if ((name[0] == '.') || !value) {
906 target_match = calloc(1, sizeof *target_match);
907 target_match->dnode = node->dnode;
908 } else if (resolve_data_nodeid(prefix, pref_len, name, nam_len, node->dnode, &target_match)) {
909 return -parsed;
910 }
911
912 /* check that we have the correct type */
913 if (name[0] == '.') {
914 if (node->dnode->schema->nodetype != LY_NODE_LEAFLIST) {
915 goto remove_instid;
916 }
917 } else if (value) {
918 if (node->dnode->schema->nodetype != LY_NODE_LIST) {
919 goto remove_instid;
920 }
921 }
922
923 if ((value && (strncmp(((struct lyd_node_leaf *)target_match->dnode)->value_str, value, val_len)
924 || ((struct lyd_node_leaf *)target_match->dnode)->value_str[val_len]))
925 || (!value && (idx != cur_idx))) {
926 goto remove_instid;
927 }
928
929 while (target_match) {
930 tmp = target_match->next;
931 free(target_match);
932 target_match = tmp;
933 }
934
935 /* leafref is ok, continue check with next leafref */
936 node_prev = node;
937 node = node->next;
938 continue;
939
940remove_instid:
941 while (target_match) {
942 tmp = target_match->next;
943 free(target_match);
944 target_match = tmp;
945 }
946
947 /* does not fulfill conditions, remove leafref record */
948 if (node_prev) {
949 node_prev->next = node->next;
950 free(node);
951 node = node_prev->next;
952 } else {
953 node = (*node_match)->next;
954 free(*node_match);
955 *node_match = node;
956 }
957 }
958 } while (has_predicate);
959
960 return parsed;
961}
962
963int
964resolve_instid(struct leafref_instid *unres, const char *path, int path_len, struct leafref_instid **ret)
965{
966 struct lyd_node *data;
967 struct leafref_instid *riter = NULL, *raux;
968 const char *apath = strndupa(path, path_len);
969 const char *prefix, *name;
970 int i, parsed, pref_len, nam_len, has_predicate;
971
972 parsed = 0;
973
974 /* we need root, absolute path */
975 for (data = unres->dnode; data->parent; data = data->parent);
976 for (; data->prev->next; data = data->prev);
977
978 /* searching for nodeset */
979 do {
980 if ((i = parse_instance_identifier(apath, &prefix, &pref_len, &name, &nam_len, &has_predicate)) < 1) {
981 LOGVAL(DE_INCHAR, unres->line, apath[-i], apath-i);
982 goto error;
983 }
984 parsed += i;
985 apath += i;
986
987 if (resolve_data_nodeid(prefix, pref_len, name, nam_len, data, ret)) {
988 LOGVAL(DE_INELEMLEN, unres->line, nam_len, name);
989 goto error;
990 }
991
992 if (has_predicate) {
993 /* we have predicate, so the current results must be list or leaf-list */
994 for (raux = NULL, riter = *ret; riter; ) {
995 if ((riter->dnode->schema->nodetype == LY_NODE_LIST &&
996 ((struct ly_mnode_list *)riter->dnode->schema)->keys)
997 || (riter->dnode->schema->nodetype == LY_NODE_LEAFLIST)) {
998 /* instid is ok, continue check with next instid */
999 raux = riter;
1000 riter = riter->next;
1001 continue;
1002 }
1003
1004 /* does not fulfill conditions, remove inst record */
1005 if (raux) {
1006 raux->next = riter->next;
1007 free(riter);
1008 riter = raux->next;
1009 } else {
1010 *ret = riter->next;
1011 free(riter);
1012 riter = *ret;
1013 }
1014 }
1015 if ((i = resolve_predicate(apath, ret)) < 1) {
1016 LOGVAL(DE_INPRED, unres->line, apath-i);
1017 goto error;
1018 }
1019 parsed += i;
1020 apath += i;
1021
1022 if (!*ret) {
1023 LOGVAL(DE_NORESOLV, unres->line, name);
1024 goto error;
1025 }
1026 }
1027 } while (apath[0] != '\0');
1028
1029 return 0;
1030
1031error:
1032 while (*ret) {
1033 raux = (*ret)->next;
1034 free(*ret);
1035 *ret = raux;
1036 }
1037
1038 return 1;
1039}
1040
1041static void
1042inherit_config_flag(struct ly_mnode *mnode)
1043{
1044 LY_TREE_FOR(mnode, mnode) {
1045 mnode->flags |= mnode->parent->flags & LY_NODE_CONFIG_MASK;
1046 inherit_config_flag(mnode->child);
1047 }
1048}
1049
1050static int
1051resolve_augment(struct ly_augment *aug, struct ly_mnode *parent, struct ly_module *module, unsigned int line)
1052{
1053 struct ly_mnode *sub;
1054
1055 assert(module);
1056
1057 /* resolve target node */
1058 aug->target = resolve_schema_nodeid(aug->target_name, parent, module, LY_NODE_AUGMENT);
1059 if (!aug->target) {
1060 LOGVAL(VE_INARG, line, aug->target_name, "uses");
1061 return EXIT_FAILURE;
1062 }
1063
1064 if (!aug->child) {
1065 /* nothing to do */
1066 return EXIT_SUCCESS;
1067 }
1068
1069 /* inherit config information from parent, augment does not have
1070 * config property, but we need to keep the information for subelements
1071 */
1072 aug->flags |= aug->target->flags & LY_NODE_CONFIG_MASK;
1073
1074 LY_TREE_FOR(aug->child, sub) {
1075 sub->parent = (struct ly_mnode *)aug;
1076 inherit_config_flag(sub);
1077 }
1078
1079 ly_mnode_addchild(aug->target, aug->child);
1080 aug->child = NULL;
1081
1082 return EXIT_SUCCESS;
1083}
1084
1085int
1086resolve_uses(struct ly_mnode_uses *uses, unsigned int line, struct unres_item *unres)
1087{
1088 struct ly_ctx *ctx;
1089 struct ly_mnode *mnode = NULL, *mnode_aux;
1090 struct ly_refine *rfn;
1091 struct ly_restr *newmust;
1092 int i, j;
1093 uint8_t size;
1094
1095 /* copy the data nodes from grouping into the uses context */
1096 LY_TREE_FOR(uses->grp->child, mnode) {
1097 mnode_aux = ly_mnode_dup(uses->module, mnode, uses->flags, 1, line, unres);
1098 if (!mnode_aux) {
1099 LOGVAL(VE_SPEC, line, "Copying data from grouping failed");
1100 return EXIT_FAILURE;
1101 }
1102 if (ly_mnode_addchild((struct ly_mnode *)uses, mnode_aux)) {
1103 ly_mnode_free(mnode_aux);
1104 return EXIT_FAILURE;
1105 }
1106 }
1107 ctx = uses->module->ctx;
1108
1109 /* apply refines */
1110 for (i = 0; i < uses->refine_size; i++) {
1111 rfn = &uses->refine[i];
1112 mnode = resolve_schema_nodeid(rfn->target, (struct ly_mnode *)uses, uses->module, LY_NODE_USES);
1113 if (!mnode) {
1114 LOGVAL(VE_INARG, line, rfn->target, "uses");
1115 return EXIT_FAILURE;
1116 }
1117
1118 if (rfn->target_type && !(mnode->nodetype & rfn->target_type)) {
1119 LOGVAL(VE_SPEC, line, "refine substatements not applicable to the target-node");
1120 return EXIT_FAILURE;
1121 }
1122
1123 /* description on any nodetype */
1124 if (rfn->dsc) {
1125 lydict_remove(ctx, mnode->dsc);
1126 mnode->dsc = lydict_insert(ctx, rfn->dsc, 0);
1127 }
1128
1129 /* reference on any nodetype */
1130 if (rfn->ref) {
1131 lydict_remove(ctx, mnode->ref);
1132 mnode->ref = lydict_insert(ctx, rfn->ref, 0);
1133 }
1134
1135 /* config on any nodetype */
1136 if (rfn->flags & LY_NODE_CONFIG_MASK) {
1137 mnode->flags &= ~LY_NODE_CONFIG_MASK;
1138 mnode->flags |= (rfn->flags & LY_NODE_CONFIG_MASK);
1139 }
1140
1141 /* default value ... */
1142 if (rfn->mod.dflt) {
1143 if (mnode->nodetype == LY_NODE_LEAF) {
1144 /* leaf */
1145 lydict_remove(ctx, ((struct ly_mnode_leaf *)mnode)->dflt);
1146 ((struct ly_mnode_leaf *)mnode)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
1147 } else if (mnode->nodetype == LY_NODE_CHOICE) {
1148 /* choice */
1149 ((struct ly_mnode_choice *)mnode)->dflt = resolve_schema_nodeid(rfn->mod.dflt, mnode, mnode->module, LY_NODE_CHOICE);
1150 if (!((struct ly_mnode_choice *)mnode)->dflt) {
1151 LOGVAL(VE_INARG, line, rfn->mod.dflt, "default");
1152 return EXIT_FAILURE;
1153 }
1154 }
1155 }
1156
1157 /* mandatory on leaf, anyxml or choice */
1158 if (rfn->flags & LY_NODE_MAND_MASK) {
1159 if (mnode->nodetype & (LY_NODE_LEAF | LY_NODE_ANYXML | LY_NODE_CHOICE)) {
1160 /* remove current value */
1161 mnode->flags &= ~LY_NODE_MAND_MASK;
1162
1163 /* set new value */
1164 mnode->flags |= (rfn->flags & LY_NODE_MAND_MASK);
1165 }
1166 }
1167
1168 /* presence on container */
1169 if ((mnode->nodetype & LY_NODE_CONTAINER) && rfn->mod.presence) {
1170 lydict_remove(ctx, ((struct ly_mnode_container *)mnode)->presence);
1171 ((struct ly_mnode_container *)mnode)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
1172 }
1173
1174 /* min/max-elements on list or leaf-list */
1175 /* magic - bit 3 in flags means min set, bit 4 says max set */
1176 if (mnode->nodetype == LY_NODE_LIST) {
1177 if (rfn->flags & 0x04) {
1178 ((struct ly_mnode_list *)mnode)->min = rfn->mod.list.min;
1179 }
1180 if (rfn->flags & 0x08) {
1181 ((struct ly_mnode_list *)mnode)->max = rfn->mod.list.max;
1182 }
1183 } else if (mnode->nodetype == LY_NODE_LEAFLIST) {
1184 if (rfn->flags & 0x04) {
1185 ((struct ly_mnode_leaflist *)mnode)->min = rfn->mod.list.min;
1186 }
1187 if (rfn->flags & 0x08) {
1188 ((struct ly_mnode_leaflist *)mnode)->max = rfn->mod.list.max;
1189 }
1190 }
1191
1192 /* must in leaf, leaf-list, list, container or anyxml */
1193 if (rfn->must_size) {
1194 size = ((struct ly_mnode_leaf *)mnode)->must_size + rfn->must_size;
1195 newmust = realloc(((struct ly_mnode_leaf *)mnode)->must, size * sizeof *rfn->must);
1196 if (!newmust) {
1197 LOGMEM;
1198 return EXIT_FAILURE;
1199 }
1200 for (i = 0, j = ((struct ly_mnode_leaf *)mnode)->must_size; i < rfn->must_size; i++, j++) {
1201 newmust[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
1202 newmust[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
1203 newmust[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
1204 newmust[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
1205 newmust[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
1206 }
1207
1208 ((struct ly_mnode_leaf *)mnode)->must = newmust;
1209 ((struct ly_mnode_leaf *)mnode)->must_size = size;
1210 }
1211 }
1212
1213 /* apply augments */
1214 for (i = 0; i < uses->augment_size; i++) {
1215 if (resolve_augment(&uses->augment[i], (struct ly_mnode *)uses, uses->module, line)) {
1216 goto error;
1217 }
1218 }
1219
1220 return EXIT_SUCCESS;
1221
1222error:
1223
1224 return EXIT_FAILURE;
1225}
1226
1227static struct ly_ident *
1228resolve_base_ident_sub(struct ly_module *module, struct ly_ident *ident, const char *basename)
1229{
1230 unsigned int i, j;
1231 struct ly_ident *base_iter = NULL;
1232 struct ly_ident_der *der;
1233
1234 /* search module */
1235 for (i = 0; i < module->ident_size; i++) {
1236 if (!strcmp(basename, module->ident[i].name)) {
1237
1238 if (!ident) {
1239 /* just search for type, so do not modify anything, just return
1240 * the base identity pointer
1241 */
1242 return &module->ident[i];
1243 }
1244
1245 /* we are resolving identity definition, so now update structures */
1246 ident->base = base_iter = &module->ident[i];
1247
1248 break;
1249 }
1250 }
1251
1252 /* search submodules */
1253 if (!base_iter) {
1254 for (j = 0; j < module->inc_size; j++) {
1255 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
1256 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
1257
1258 if (!ident) {
1259 return &module->inc[j].submodule->ident[i];
1260 }
1261
1262 ident->base = base_iter = &module->inc[j].submodule->ident[i];
1263 break;
1264 }
1265 }
1266 }
1267 }
1268
1269 /* we found it somewhere */
1270 if (base_iter) {
1271 while (base_iter) {
1272 for (der = base_iter->der; der && der->next; der = der->next);
1273 if (der) {
1274 der->next = malloc(sizeof *der);
1275 der = der->next;
1276 } else {
1277 ident->base->der = der = malloc(sizeof *der);
1278 }
1279 der->next = NULL;
1280 der->ident = ident;
1281
1282 base_iter = base_iter->base;
1283 }
1284 return ident->base;
1285 }
1286
1287 return NULL;
1288}
1289
1290static struct ly_ident *
1291resolve_base_ident(struct ly_module *module, struct ly_ident *ident, const char *basename, int line,
1292 const char* parent)
1293{
1294 const char *name;
1295 int prefix_len = 0;
1296 int i, found = 0;
1297 struct ly_ident *result;
1298
1299 /* search for the base identity */
1300 name = strchr(basename, ':');
1301 if (name) {
1302 /* set name to correct position after colon */
1303 prefix_len = name - basename;
1304 name++;
1305
1306 if (!strncmp(basename, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
1307 /* prefix refers to the current module, ignore it */
1308 prefix_len = 0;
1309 }
1310 } else {
1311 name = basename;
1312 }
1313
1314 if (prefix_len) {
1315 /* get module where to search */
1316 for (i = 0; i < module->imp_size; i++) {
1317 if (!strncmp(module->imp[i].prefix, basename, prefix_len)
1318 && !module->imp[i].prefix[prefix_len]) {
1319 module = module->imp[i].module;
1320 found = 1;
1321 break;
1322 }
1323 }
1324 if (!found) {
1325 /* identity refers unknown data model */
1326 LOGVAL(VE_INPREFIX, line, basename);
1327 return NULL;
1328 }
1329 } else {
1330 /* search in submodules */
1331 for (i = 0; i < module->inc_size; i++) {
1332 result = resolve_base_ident_sub((struct ly_module *)module->inc[i].submodule, ident, name);
1333 if (result) {
1334 return result;
1335 }
1336 }
1337 }
1338
1339 /* search in the identified module */
1340 result = resolve_base_ident_sub(module, ident, name);
1341 if (!result) {
1342 LOGVAL(VE_INARG, line, basename, parent);
1343 }
1344
1345 return result;
1346}
1347
1348struct ly_ident *
1349resolve_identityref(struct ly_ident *base, const char *name, const char *ns)
1350{
1351 struct ly_ident_der *der;
1352
1353 if (!base || !name || !ns) {
1354 return NULL;
1355 }
1356
1357 for(der = base->der; der; der = der->next) {
1358 if (!strcmp(der->ident->name, name) && ns == der->ident->module->ns) {
1359 /* we have match */
1360 return der->ident;
1361 }
1362 }
1363
1364 /* not found */
1365 return NULL;
1366}
1367
1368static int
1369resolve_unres_ident(struct ly_module *mod, struct ly_ident *ident, const char *base_name, int line)
1370{
1371 if (resolve_base_ident(mod, ident, base_name, line, "ident")) {
1372 return 0;
1373 }
1374
1375 return 1;
1376}
1377
1378static int
1379resolve_unres_type_identref(struct ly_module *mod, struct ly_type *type, const char *base_name, int line)
1380{
1381 type->info.ident.ref = resolve_base_ident(mod, NULL, base_name, line, "type");
1382 if (type->info.ident.ref) {
1383 return 0;
1384 }
1385
1386 return 1;
1387}
1388
1389static int
1390resolve_unres_type_leafref(struct ly_module *mod, struct ly_type *type, struct ly_mnode *mnode, int line)
1391{
1392 if (resolve_schema_nodeid(type->info.lref.path, mnode, mod, LY_NODE_LEAF)) {
1393 return 0;
1394 }
1395
1396 return 1;
1397}
1398
1399static int
1400resolve_unres_type_der(struct ly_module *mod, struct ly_type *type, const char *type_name, int line)
1401{
1402 type->der = resolve_superior_type(type_name, type->prefix, mod, (struct ly_mnode *)type->der);
1403 if (type->der) {
1404 return 0;
1405 }
1406
1407 return 1;
1408}
1409
1410static int
1411resolve_unres_augment(struct ly_module *mod, struct ly_augment *aug, int line)
1412{
1413 if (aug->parent->nodetype == LY_NODE_USES) {
1414 if ((aug->target_name[0] != '/')
1415 && resolve_schema_nodeid(aug->target_name, aug->parent->child, mod, LY_NODE_AUGMENT)) {
1416 return 0;
1417 }
1418 } else {
1419 if ((aug->target_name[0] == '/')
1420 && resolve_schema_nodeid(aug->target_name, mod->data, mod, LY_NODE_AUGMENT)) {
1421 return 0;
1422 }
1423 }
1424
1425 return 1;
1426}
1427
1428static int
1429resolve_unres_iffeature(struct ly_module *mod, struct ly_feature **feat_ptr, const char *feat_name, int line)
1430{
1431 *feat_ptr = resolve_feature(feat_name, mod, line);
1432 if (*feat_ptr) {
1433 return 0;
1434 }
1435
1436 return 1;
1437}
1438
1439static int
1440resolve_unres_uses(struct ly_mnode_uses *uses, int line, struct unres_item *unres)
1441{
1442 if (uses->grp || !resolve_grouping(uses->parent, uses, line)) {
1443 return resolve_uses(uses, line, unres);
1444 }
1445
1446 return 1;
1447}
1448
1449static int
1450resolve_unres_type_dflt(struct ly_type *type, const char *dflt, int line)
1451{
1452 return check_default(type, dflt);
1453}
1454
1455static int
1456resolve_unres_choice_dflt(struct ly_module *mod, struct ly_mnode_choice *choice, const char *dflt, int line)
1457{
1458 choice->dflt = resolve_child((struct ly_mnode *)choice, dflt, 0, LY_NODE_ANYXML | LY_NODE_CASE
1459 | LY_NODE_CONTAINER | LY_NODE_LEAF | LY_NODE_LEAFLIST | LY_NODE_LIST);
1460 if (choice->dflt) {
1461 return 0;
1462 }
1463
1464 return 1;
1465}
1466
1467static int
1468resolve_unres_list_keys(struct ly_mnode_list *list, const char *keys_str, int line)
1469{
1470 int i, len;
1471 const char *value;
1472
1473 for (i = 0; i < list->keys_size; ++i) {
1474 /* get the key name */
1475 if ((value = strpbrk(keys_str, " \t\n"))) {
1476 len = value - keys_str;
1477 while (isspace(value[0])) {
1478 value++;
1479 }
1480 } else {
1481 len = strlen(keys_str);
1482 }
1483
1484 list->keys[i] = (struct ly_mnode_leaf *)resolve_child((struct ly_mnode *)list, keys_str, len, LY_NODE_LEAF);
1485
1486 if (check_key(list->keys[i], list->flags, list->keys, i, line, keys_str, len)) {
1487 return 1;
1488 }
1489
1490 /* prepare for next iteration */
1491 while (value && isspace(value[0])) {
1492 value++;
1493 }
1494 keys_str = value;
1495 }
1496
1497 return 0;
1498}
1499
1500static int
1501resolve_unres_list_uniq(struct ly_unique *uniq, const char *uniq_str, int line)
1502{
1503 return resolve_unique((struct ly_mnode *)uniq->leafs, uniq_str, uniq, line);
1504}
1505
1506static int
1507resolve_unres_when(struct ly_when *UNUSED(when), struct ly_mnode *UNUSED(start), int UNUSED(line))
1508{
1509 /* TODO */
1510 return 0;
1511}
1512
1513static int
1514resolve_unres_must(struct ly_restr *UNUSED(must), struct ly_mnode *UNUSED(start), int UNUSED(line))
1515{
1516 /* TODO */
1517 return 0;
1518}
1519
1520/* TODO line == -1 means do not log, 0 means unknown */
1521static int
1522resolve_unres_item(struct ly_module *mod, void *item, enum UNRES_ITEM type, void *str_mnode, int line,
1523 struct unres_item *unres)
1524{
1525 int ret = EXIT_FAILURE, has_str = 0;
1526
1527 switch (type) {
1528 case UNRES_RESOLVED:
1529 assert(0);
1530 case UNRES_IDENT:
1531 ret = resolve_unres_ident(mod, item, str_mnode, line);
1532 has_str = 1;
1533 break;
1534 case UNRES_TYPE_IDENTREF:
1535 ret = resolve_unres_type_identref(mod, item, str_mnode, line);
1536 has_str = 1;
1537 break;
1538 case UNRES_TYPE_LEAFREF:
1539 ret = resolve_unres_type_leafref(mod, item, str_mnode, line);
1540 has_str = 0;
1541 break;
1542 case UNRES_TYPE_DER:
1543 ret = resolve_unres_type_der(mod, item, str_mnode, line);
1544 has_str = 1;
1545 break;
1546 case UNRES_AUGMENT:
1547 ret = resolve_unres_augment(mod, item, line);
1548 has_str = 0;
1549 break;
1550 case UNRES_IFFEAT:
1551 ret = resolve_unres_iffeature(mod, item, str_mnode, line);
1552 has_str = 1;
1553 break;
1554 case UNRES_USES:
1555 ret = resolve_unres_uses(item, line, unres);
1556 has_str = 0;
1557 break;
1558 case UNRES_TYPE_DFLT:
1559 ret = resolve_unres_type_dflt(item, str_mnode, line);
1560 /* do not remove str_mnode (dflt), it's in a typedef */
1561 has_str = 0;
1562 break;
1563 case UNRES_CHOICE_DFLT:
1564 ret = resolve_unres_choice_dflt(mod, item, str_mnode, line);
1565 has_str = 1;
1566 break;
1567 case UNRES_LIST_KEYS:
1568 ret = resolve_unres_list_keys(item, str_mnode, line);
1569 has_str = 1;
1570 break;
1571 case UNRES_LIST_UNIQ:
1572 ret = resolve_unres_list_uniq(item, str_mnode, line);
1573 has_str = 1;
1574 break;
1575 case UNRES_WHEN:
1576 ret = resolve_unres_when(item, str_mnode, line);
1577 has_str = 0;
1578 break;
1579 case UNRES_MUST:
1580 ret = resolve_unres_must(item, str_mnode, line);
1581 has_str = 0;
1582 break;
1583 }
1584
1585 if (has_str && !ret) {
1586 lydict_remove(mod->ctx, str_mnode);
1587 }
1588
1589 return ret;
1590}
1591
1592int
1593resolve_unres(struct ly_module *mod, struct unres_item *unres)
1594{
1595 unsigned int i, resolved = 0;
1596
1597 assert(unres);
1598
1599 /* uses */
1600 for (i = 0; i < unres->count; ++i) {
1601 if (unres->type[i] != UNRES_USES) {
1602 continue;
1603 }
1604 if (!resolve_unres_item(mod, unres->item[i], unres->type[i], unres->str_mnode[i], unres->line[i], unres)) {
1605 unres->type[i] = UNRES_RESOLVED;
1606 ++resolved;
1607 }
1608 }
1609
1610 /* augment */
1611 for (i = 0; i < unres->count; ++i) {
1612 if (unres->type[i] != UNRES_AUGMENT) {
1613 continue;
1614 }
1615 if (!resolve_unres_item(mod, unres->item[i], unres->type[i], unres->str_mnode[i], unres->line[i], unres)) {
1616 unres->type[i] = UNRES_RESOLVED;
1617 ++resolved;
1618 }
1619 }
1620
1621 /* the rest */
1622 for (i = 0; i < unres->count; ++i) {
1623 if (unres->type[i] == UNRES_RESOLVED) {
1624 continue;
1625 }
1626 if (!resolve_unres_item(mod, unres->item[i], unres->type[i], unres->str_mnode[i], unres->line[i], unres)) {
1627 unres->type[i] = UNRES_RESOLVED;
1628 ++resolved;
1629 }
1630 }
1631
1632 if (resolved < unres->count) {
1633 return EXIT_FAILURE;
1634 }
1635
1636 return EXIT_SUCCESS;
1637}
1638
1639void
1640add_unres_str(struct ly_module *mod, struct unres_item *unres, void *item, enum UNRES_ITEM type, const char *str,
1641 int line)
1642{
1643 str = lydict_insert(mod->ctx, str, 0);
1644 add_unres_mnode(mod, unres, item, type, (struct ly_mnode *)str, line);
1645}
1646
1647void
1648add_unres_mnode(struct ly_module *mod, struct unres_item *unres, void *item, enum UNRES_ITEM type,
1649 struct ly_mnode *mnode, int line)
1650{
1651 assert(unres && item);
1652
1653 if (!resolve_unres_item(mod, item, type, mnode, 0, unres)) {
1654 return;
1655 }
1656
1657 unres->count++;
1658 unres->item = realloc(unres->item, unres->count*sizeof *unres->item);
1659 unres->item[unres->count-1] = item;
1660 unres->type = realloc(unres->type, unres->count*sizeof *unres->type);
1661 unres->type[unres->count-1] = type;
1662 unres->str_mnode = realloc(unres->str_mnode, unres->count*sizeof *unres->str_mnode);
1663 unres->str_mnode[unres->count-1] = mnode;
1664 unres->line = realloc(unres->line, unres->count*sizeof *unres->line);
1665 unres->line[unres->count-1] = line;
1666}
1667
1668void
1669dup_unres(struct ly_module *mod, struct unres_item *unres, void *item, enum UNRES_ITEM type, void *new_item)
1670{
1671 int i;
1672
1673 if (!item || !new_item) {
1674 return;
1675 }
1676
1677 i = find_unres(unres, item, type);
1678
1679 if (i == -1) {
1680 return;
1681 }
1682
1683 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_AUGMENT) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT)
1684 || (type == UNRES_WHEN) || (type == UNRES_MUST)) {
1685 add_unres_mnode(mod, unres, new_item, type, unres->str_mnode[i], 0);
1686 } else {
1687 add_unres_str(mod, unres, new_item, type, unres->str_mnode[i], 0);
1688 }
1689}
1690
1691int
1692find_unres(struct unres_item *unres, void *item, enum UNRES_ITEM type)
1693{
1694 uint32_t ret = -1, i;
1695
1696 for (i = 0; i < unres->count; ++i) {
1697 if ((unres->item[i] == item) && (unres->type[i] == type)) {
1698 ret = i;
1699 break;
1700 }
1701 }
1702
1703 return ret;
1704}