blob: 94de202a072fcf1cafb397418db3f754271c018b [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
Radek Krejci1574a8d2015-08-03 14:16:52 +020015struct lys_tpdf *
Radek Krejci76512572015-08-04 09:47:08 +020016resolve_superior_type(const char *name, const char *prefix, struct ly_module *module, struct lys_node *parent)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020017{
18 int i, j, found = 0;
Radek Krejci1574a8d2015-08-03 14:16:52 +020019 struct lys_tpdf *tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020020 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) {
Radek Krejci76512572015-08-04 09:47:08 +020040 case LYS_CONTAINER:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020041 tpdf_size = ((struct ly_mnode_container *)parent)->tpdf_size;
42 tpdf = ((struct ly_mnode_container *)parent)->tpdf;
43 break;
44
Radek Krejci76512572015-08-04 09:47:08 +020045 case LYS_LIST:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020046 tpdf_size = ((struct ly_mnode_list *)parent)->tpdf_size;
47 tpdf = ((struct ly_mnode_list *)parent)->tpdf;
48 break;
49
Radek Krejci76512572015-08-04 09:47:08 +020050 case LYS_GROUPING:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020051 tpdf_size = ((struct ly_mnode_grp *)parent)->tpdf_size;
52 tpdf = ((struct ly_mnode_grp *)parent)->tpdf;
53 break;
54
Radek Krejci76512572015-08-04 09:47:08 +020055 case LYS_RPC:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020056 tpdf_size = ((struct ly_mnode_rpc *)parent)->tpdf_size;
57 tpdf = ((struct ly_mnode_rpc *)parent)->tpdf;
58 break;
59
Radek Krejci76512572015-08-04 09:47:08 +020060 case LYS_NOTIF:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020061 tpdf_size = ((struct ly_mnode_notif *)parent)->tpdf_size;
62 tpdf = ((struct ly_mnode_notif *)parent)->tpdf;
63 break;
64
Radek Krejci76512572015-08-04 09:47:08 +020065 case LYS_INPUT:
66 case LYS_OUTPUT:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020067 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
Radek Krejci1574a8d2015-08-03 14:16:52 +0200118check_default(struct lys_type *type, const char *value)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200119{
120 /* TODO - RFC 6020, sec. 7.3.4 */
121 (void)type;
122 (void)value;
123 return EXIT_SUCCESS;
124}
125
126static int
Michal Vasko12e30842015-08-04 11:54:00 +0200127check_key(struct ly_mnode_leaf *key, uint8_t flags, struct ly_mnode_leaf **list, int index, int line,
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200128 const char *name, int len)
129{
130 char *dup = NULL;
131 int j;
132
133 /* existence */
134 if (!key) {
Michal Vasko12e30842015-08-04 11:54:00 +0200135 if (line > -1) {
136 if (name[len] != '\0') {
137 dup = strdup(name);
138 dup[len] = '\0';
139 name = dup;
140 }
141 LOGVAL(VE_KEY_MISS, line, name);
142 free(dup);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200143 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200144 return EXIT_FAILURE;
145 }
146
147 /* uniqueness */
148 for (j = index - 1; j >= 0; j--) {
149 if (list[index] == list[j]) {
Michal Vasko12e30842015-08-04 11:54:00 +0200150 if (line > -1) {
151 LOGVAL(VE_KEY_DUP, line, key->name);
152 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200153 return EXIT_FAILURE;
154 }
155 }
156
157 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +0200158 if (key->nodetype != LYS_LEAF) {
Michal Vasko12e30842015-08-04 11:54:00 +0200159 if (line > -1) {
160 LOGVAL(VE_KEY_NLEAF, line, key->name);
161 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200162 return EXIT_FAILURE;
163 }
164
165 /* type of the leaf is not built-in empty */
166 if (key->type.base == LY_TYPE_EMPTY) {
Michal Vasko12e30842015-08-04 11:54:00 +0200167 if (line > -1) {
168 LOGVAL(VE_KEY_TYPE, line, key->name);
169 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200170 return EXIT_FAILURE;
171 }
172
173 /* config attribute is the same as of the list */
Radek Krejci1574a8d2015-08-03 14:16:52 +0200174 if ((flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Michal Vasko12e30842015-08-04 11:54:00 +0200175 if (line > -1) {
176 LOGVAL(VE_KEY_CONFIG, line, key->name);
177 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200178 return EXIT_FAILURE;
179 }
180
181 return EXIT_SUCCESS;
182}
183
184int
Radek Krejci76512572015-08-04 09:47:08 +0200185resolve_unique(struct lys_node *parent, const char *uniq_str, struct lys_unique *uniq_s, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200186{
187 char *uniq_val, *uniq_begin, *start;
188 int i, j;
189
190 /* count the number of unique values */
191 uniq_val = uniq_begin = strdup(uniq_str);
192 uniq_s->leafs_size = 0;
193 while ((uniq_val = strpbrk(uniq_val, " \t\n"))) {
194 uniq_s->leafs_size++;
195 while (isspace(*uniq_val)) {
196 uniq_val++;
197 }
198 }
199 uniq_s->leafs_size++;
200 uniq_s->leafs = calloc(uniq_s->leafs_size, sizeof *uniq_s->leafs);
201
202 /* interconnect unique values with the leafs */
203 uniq_val = uniq_begin;
204 for (i = 0; uniq_val && i < uniq_s->leafs_size; i++) {
205 start = uniq_val;
206 if ((uniq_val = strpbrk(start, " \t\n"))) {
207 *uniq_val = '\0'; /* add terminating NULL byte */
208 uniq_val++;
209 while (isspace(*uniq_val)) {
210 uniq_val++;
211 }
212 } /* else only one nodeid present/left already NULL byte terminated */
213
Radek Krejci76512572015-08-04 09:47:08 +0200214 uniq_s->leafs[i] = (struct ly_mnode_leaf *)resolve_schema_nodeid(start, parent, parent->module, LYS_USES);
215 if (!uniq_s->leafs[i] || uniq_s->leafs[i]->nodetype != LYS_LEAF) {
Michal Vasko12e30842015-08-04 11:54:00 +0200216 if (line > -1) {
217 LOGVAL(VE_INARG, line, start, "unique");
218 if (!uniq_s->leafs[i]) {
219 LOGVAL(VE_SPEC, 0, "Target leaf not found.");
220 } else {
221 LOGVAL(VE_SPEC, 0, "Target is not a leaf.");
222 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200223 }
224 goto error;
225 }
226
227 for (j = 0; j < i; j++) {
228 if (uniq_s->leafs[j] == uniq_s->leafs[i]) {
Michal Vasko12e30842015-08-04 11:54:00 +0200229 if (line > -1) {
230 LOGVAL(VE_INARG, line, start, "unique");
231 LOGVAL(VE_SPEC, 0, "The identifier is not unique");
232 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200233 goto error;
234 }
235 }
236 }
237
238 free(uniq_begin);
239 return EXIT_SUCCESS;
240
241error:
242
243 free(uniq_s->leafs);
244 free(uniq_begin);
245
246 return EXIT_FAILURE;
247}
248
249static int
Radek Krejci76512572015-08-04 09:47:08 +0200250resolve_grouping(struct lys_node *parent, struct ly_mnode_uses *uses, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200251{
252 struct ly_module *searchmod = NULL, *module = uses->module;
Radek Krejci76512572015-08-04 09:47:08 +0200253 struct lys_node *mnode, *mnode_aux;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200254 const char *name;
255 int prefix_len = 0;
256 int i;
257
258 /* get referenced grouping */
259 name = strchr(uses->name, ':');
260 if (!name) {
261 /* no prefix, search in local tree */
262 name = uses->name;
263 } else {
264 /* there is some prefix, check if it refer the same data model */
265
266 /* set name to correct position after colon */
267 prefix_len = name - uses->name;
268 name++;
269
270 if (!strncmp(uses->name, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
271 /* prefix refers to the current module, ignore it */
272 prefix_len = 0;
273 }
274 }
275
276 /* search */
277 if (prefix_len) {
278 /* in top-level groupings of some other module */
279 for (i = 0; i < module->imp_size; i++) {
280 if (!strncmp(module->imp[i].prefix, uses->name, prefix_len)
281 && !module->imp[i].prefix[prefix_len]) {
282 searchmod = module->imp[i].module;
283 break;
284 }
285 }
286 if (!searchmod) {
287 /* uses refers unknown data model */
Michal Vasko12e30842015-08-04 11:54:00 +0200288 if (line > -1) {
289 LOGVAL(VE_INPREFIX, line, name);
290 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200291 return EXIT_FAILURE;
292 }
293
294 LY_TREE_FOR(searchmod->data, mnode) {
Radek Krejci76512572015-08-04 09:47:08 +0200295 if (mnode->nodetype == LYS_GROUPING && !strcmp(mnode->name, name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200296 uses->grp = (struct ly_mnode_grp *)mnode;
297 return EXIT_SUCCESS;
298 }
299 }
300 } else {
301 /* in local tree hierarchy */
302 for (mnode_aux = parent; mnode_aux; mnode_aux = mnode_aux->parent) {
303 LY_TREE_FOR(mnode_aux->child, mnode) {
Radek Krejci76512572015-08-04 09:47:08 +0200304 if (mnode->nodetype == LYS_GROUPING && !strcmp(mnode->name, name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200305 uses->grp = (struct ly_mnode_grp *)mnode;
306 return EXIT_SUCCESS;
307 }
308 }
309 }
310
311 /* search in top level of the current module */
312 LY_TREE_FOR(module->data, mnode) {
Radek Krejci76512572015-08-04 09:47:08 +0200313 if (mnode->nodetype == LYS_GROUPING && !strcmp(mnode->name, name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200314 uses->grp = (struct ly_mnode_grp *)mnode;
315 return EXIT_SUCCESS;
316 }
317 }
318
319 /* search in top-level of included modules */
320 for (i = 0; i < module->inc_size; i++) {
321 LY_TREE_FOR(module->inc[i].submodule->data, mnode) {
Radek Krejci76512572015-08-04 09:47:08 +0200322 if (mnode->nodetype == LYS_GROUPING && !strcmp(mnode->name, name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200323 uses->grp = (struct ly_mnode_grp *)mnode;
324 return EXIT_SUCCESS;
325 }
326 }
327 }
328 }
329
330 return EXIT_FAILURE;
331}
332
333static struct ly_feature *
Michal Vasko12e30842015-08-04 11:54:00 +0200334resolve_feature(const char *name, struct ly_module *module, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200335{
336 const char *prefix;
337 unsigned int prefix_len = 0;
338 int i, j, found = 0;
339
340 assert(name);
341 assert(module);
342
343 /* check prefix */
344 prefix = name;
345 name = strchr(prefix, ':');
346 if (name) {
347 /* there is prefix */
348 prefix_len = name - prefix;
349 name++;
350
351 /* check whether the prefix points to the current module */
352 if (!strncmp(prefix, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
353 /* then ignore prefix and works as there is no prefix */
354 prefix_len = 0;
355 }
356 } else {
357 /* no prefix, set pointers correctly */
358 name = prefix;
359 }
360
361 if (prefix_len) {
362 /* search in imported modules */
363 for (i = 0; i < module->imp_size; i++) {
364 if (!strncmp(module->imp[i].prefix, prefix, prefix_len) && !module->imp[i].prefix[prefix_len]) {
365 module = module->imp[i].module;
366 found = 1;
367 break;
368 }
369 }
370 if (!found) {
371 /* identity refers unknown data model */
Michal Vasko12e30842015-08-04 11:54:00 +0200372 if (line > -1) {
373 LOGVAL(VE_INPREFIX, line, prefix);
374 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200375 return NULL;
376 }
377 } else {
378 /* search in submodules */
379 for (i = 0; i < module->inc_size; i++) {
380 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
381 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
382 return &(module->inc[i].submodule->features[j]);
383 }
384 }
385 }
386 }
387
388 /* search in the identified module */
389 for (j = 0; j < module->features_size; j++) {
390 if (!strcmp(name, module->features[j].name)) {
391 return &module->features[j];
392 }
393 }
394
395 /* not found */
396 return NULL;
397}
398
399static struct ly_module *
400resolve_import_in_includes_recursive(struct ly_module *mod, const char *prefix, uint32_t pref_len)
401{
402 int i, j;
403 struct ly_submodule *sub_mod;
404 struct ly_module *ret;
405
406 for (i = 0; i < mod->inc_size; i++) {
407 sub_mod = mod->inc[i].submodule;
408 for (j = 0; j < sub_mod->imp_size; j++) {
409 if ((pref_len == strlen(sub_mod->imp[j].prefix))
410 && !strncmp(sub_mod->imp[j].prefix, prefix, pref_len)) {
411 return sub_mod->imp[j].module;
412 }
413 }
414 }
415
416 for (i = 0; i < mod->inc_size; i++) {
417 ret = resolve_import_in_includes_recursive((struct ly_module *)mod->inc[i].submodule, prefix, pref_len);
418 if (ret) {
419 return ret;
420 }
421 }
422
423 return NULL;
424}
425
426static struct ly_module *
427resolve_prefixed_module(struct ly_module *mod, const char *prefix, uint32_t pref_len)
428{
429 int i;
430
431 /* module itself */
432 if (!strncmp(mod->prefix, prefix, pref_len) && mod->prefix[pref_len] == '\0') {
433 return mod;
434 }
435
436 /* imported modules */
437 for (i = 0; i < mod->imp_size; i++) {
438 if (!strncmp(mod->imp[i].prefix, prefix, pref_len) && mod->imp[i].prefix[pref_len] == '\0') {
439 return mod->imp[i].module;
440 }
441 }
442
443 /* imports in includes */
444 return resolve_import_in_includes_recursive(mod, prefix, pref_len);
445}
446
Radek Krejci76512572015-08-04 09:47:08 +0200447struct lys_node *
448resolve_child(struct lys_node *parent, const char *name, int len, LYS_NODE type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200449{
Radek Krejci76512572015-08-04 09:47:08 +0200450 struct lys_node *child, *result;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200451
452 if (!len) {
453 len = strlen(name);
454 }
455
456 LY_TREE_FOR(parent->child, child) {
Radek Krejci76512572015-08-04 09:47:08 +0200457 if (child->nodetype == LYS_USES) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200458 /* search recursively */
459 result = resolve_child(child, name, len, type);
460 if (result) {
461 return result;
462 }
463 }
464
465 if (child->nodetype & type) {
466 /* direct check */
467 if (child->name == name || (!strncmp(child->name, name, len) && !child->name[len])) {
468 return child;
469 }
470 }
471 }
472
473 return NULL;
474}
475
476/*
477 * id - schema-nodeid
478 *
Michal Vaskocc9e12e2015-08-04 16:14:37 +0200479 * node_type - LYS_AUGMENT (searches also RPCs and notifications)
480 * - LYS_USES (only descendant-schema-nodeid allowed, ".." not allowed)
481 * - LYS_CHOICE (search only start->child, only descendant-schema-nodeid allowed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200482 */
Radek Krejci76512572015-08-04 09:47:08 +0200483struct lys_node *
484resolve_schema_nodeid(const char *id, struct lys_node *start, struct ly_module *mod, LYS_NODE node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200485{
Michal Vaskocc9e12e2015-08-04 16:14:37 +0200486 const char *name, *prefix;
Radek Krejci76512572015-08-04 09:47:08 +0200487 struct lys_node *sibling;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200488 int ret, nam_len, pref_len, is_relative = -1;
489 struct ly_module *prefix_mod, *start_mod;
490 /* 0 - in module, 1 - in 1st submodule, 2 - in 2nd submodule, ... */
491 uint8_t in_submod = 0;
Michal Vaskocc9e12e2015-08-04 16:14:37 +0200492 /* 0 - in data, 1 - in RPCs, 2 - in notifications (relevant only with LYS_AUGMENT) */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200493 uint8_t in_mod_part = 0;
494
495 assert(mod);
496 assert(id);
497
498 if ((ret = parse_schema_nodeid(id, &prefix, &pref_len, &name, &nam_len, &is_relative)) < 1) {
499 return NULL;
500 }
501 id += ret;
502
Radek Krejci76512572015-08-04 09:47:08 +0200503 if (!is_relative && (node_type & (LYS_USES | LYS_CHOICE))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200504 return NULL;
505 }
506
507 /* absolute-schema-nodeid */
508 if (!is_relative) {
509 if (prefix) {
510 start_mod = resolve_prefixed_module(mod, prefix, pref_len);
511 if (!start_mod) {
512 return NULL;
513 }
514 start = start_mod->data;
515 } else {
516 start = mod->data;
517 start_mod = mod;
518 }
519 /* descendant-schema-nodeid */
520 } else {
521 assert(start);
522 start = start->child;
523 start_mod = start->module;
524 }
525
526 while (1) {
Michal Vasko1e989c02015-08-04 12:33:00 +0200527 sibling = NULL;
528 LY_TREE_FOR(start, sibling) {
529 /* name match */
530 if ((sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len])
531 || (!strncmp(name, "input", 5) && (nam_len == 5) && (sibling->nodetype == LYS_INPUT))
532 || (!strncmp(name, "output", 6) && (nam_len == 6) && (sibling->nodetype == LYS_OUTPUT))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200533
Michal Vasko1e989c02015-08-04 12:33:00 +0200534 /* prefix match check */
535 if (prefix) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200536
Michal Vasko1e989c02015-08-04 12:33:00 +0200537 prefix_mod = resolve_prefixed_module(mod, prefix, pref_len);
538 if (!prefix_mod) {
539 return NULL;
540 }
541
542 if (!sibling->module->type) {
543 if (prefix_mod != sibling->module) {
544 continue;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200545 }
Michal Vasko1e989c02015-08-04 12:33:00 +0200546 } else {
547 if (prefix_mod != ((struct ly_submodule *)sibling->module)->belongsto) {
548 continue;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200549 }
550 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200551 }
Michal Vasko1e989c02015-08-04 12:33:00 +0200552
Michal Vasko1e989c02015-08-04 12:33:00 +0200553 /* 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 != LYS_CHOICE)
560 || (sibling->nodetype == LYS_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 == LYS_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 == LYS_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 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200597 }
598
Michal Vasko1e989c02015-08-04 12:33:00 +0200599 /* are we done with the included submodules as well? */
600 if (in_submod == start_mod->inc_size) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200601 return NULL;
602 }
603
Michal Vasko1e989c02015-08-04 12:33:00 +0200604 /* 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;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200609 }
610
611 /* we found our submodule */
612 if (in_submod) {
613 start_mod = (struct ly_module *)start_mod->inc[in_submod-1].submodule;
614 in_submod = 0;
615 }
616
617 if ((ret = parse_schema_nodeid(id, &prefix, &pref_len, &name, &nam_len, &is_relative)) < 1) {
618 return NULL;
619 }
620 id += ret;
621 }
622
623 /* cannot get here */
624 return NULL;
625}
626
627static int
628resolve_data_nodeid(const char *prefix, int pref_len, const char *name, int nam_len, struct lyd_node *data_source,
629 struct leafref_instid **parents)
630{
631 int flag;
632 struct ly_module *mod;
633 struct leafref_instid *item, *par_iter;
634 struct lyd_node *node;
635
636 if (prefix) {
637 /* we have prefix, find appropriate module */
638 mod = resolve_prefixed_module(data_source->schema->module, prefix, pref_len);
639 if (!mod) {
640 /* invalid prefix */
641 return 1;
642 }
643 } else {
644 /* no prefix, module is the same as of current node */
645 mod = data_source->schema->module;
646 }
647
648 if (!*parents) {
649 *parents = malloc(sizeof **parents);
650 (*parents)->dnode = NULL;
651 (*parents)->next = NULL;
652 }
653 for (par_iter = *parents; par_iter; par_iter = par_iter->next) {
Radek Krejci76512572015-08-04 09:47:08 +0200654 if (par_iter->dnode && (par_iter->dnode->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200655 /* skip */
656 continue;
657 }
658 flag = 0;
659 LY_TREE_FOR(par_iter->dnode ? par_iter->dnode->child : data_source, node) {
660 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
661 && node->schema->name[nam_len] == '\0') {
662 /* matching target */
663 if (!flag) {
664 /* replace leafref instead of the current parent */
665 par_iter->dnode = node;
666 flag = 1;
667 } else {
668 /* multiple matching, so create new leafref structure */
669 item = malloc(sizeof *item);
670 item->dnode = node;
671 item->next = par_iter->next;
672 par_iter->next = item;
673 par_iter = par_iter->next;
674 }
675 }
676 }
677 }
678
679 return !flag;
680}
681
682/* ... /node[source = destination] ... */
683static int
684resolve_path_predicate(const char *pred, struct leafref_instid **node_match)
685{
686 struct leafref_instid *source_match, *dest_match, *node, *node_prev = NULL;
687 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
688 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed = 0, pke_parsed = 0;
689 int has_predicate, dest_parent_times, i;
690
691 do {
692 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
693 &pke_len, &has_predicate)) < 1) {
694 return -parsed+i;
695 }
696 parsed += i;
697 pred += i;
698
699 for (node = *node_match; node;) {
700 /* source */
701 source_match = NULL;
702 /* must be leaf (key of a list) */
703 if (resolve_data_nodeid(sour_pref, sour_pref_len, source, sour_len, node->dnode, &source_match)
704 || !source_match || source_match->next
Radek Krejci76512572015-08-04 09:47:08 +0200705 || (source_match->dnode->schema->nodetype != LYS_LEAF)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200706 return -parsed;
707 }
708
709 /* destination */
710 dest_match = calloc(1, sizeof *dest_match);
711 dest_match->dnode = node->dnode;
712 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
713 &dest_parent_times)) < 1) {
714 return -parsed+i;
715 }
716 pke_parsed += i;
717 for (i = 0; i < dest_parent_times; ++i) {
718 dest_match->dnode = dest_match->dnode->parent;
719 if (!dest_match->dnode) {
720 free(dest_match);
721 return -parsed;
722 }
723 }
724 while (1) {
725 if (resolve_data_nodeid(dest_pref, dest_pref_len, dest, dest_len, dest_match->dnode, &dest_match)
726 || !dest_match->dnode || dest_match->next
Radek Krejci76512572015-08-04 09:47:08 +0200727 || (dest_match->dnode->schema->nodetype != LYS_LEAF)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200728 free(dest_match);
729 return -parsed;
730 }
731
732 if (pke_len == pke_parsed) {
733 break;
734 }
735 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
736 &dest_parent_times)) < 1) {
737 return -parsed+i;
738 }
739 pke_parsed += i;
740 }
741
742 /* check match between source and destination nodes */
743 if (((struct ly_mnode_leaf *)source_match->dnode->schema)->type.base
744 != ((struct ly_mnode_leaf *)dest_match->dnode->schema)->type.base) {
745 goto remove_leafref;
746 }
747
748 if (((struct lyd_node_leaf *)source_match->dnode)->value_str
749 != ((struct lyd_node_leaf *)dest_match->dnode)->value_str) {
750 goto remove_leafref;
751 }
752
753 /* leafref is ok, continue check with next leafref */
754 node_prev = node;
755 node = node->next;
756 continue;
757
758remove_leafref:
759 /* does not fulfill conditions, remove leafref record */
760 if (node_prev) {
761 node_prev->next = node->next;
762 free(node);
763 node = node_prev->next;
764 } else {
765 node = (*node_match)->next;
766 free(*node_match);
767 *node_match = node;
768 }
769 }
770 } while (has_predicate);
771
772 return parsed;
773}
774
775int
776resolve_path_arg(struct leafref_instid *unres, const char *path, struct leafref_instid **ret)
777{
778 struct lyd_node *data;
779 struct leafref_instid *riter = NULL, *raux;
780 const char *prefix, *name;
781 int pref_len, nam_len, has_predicate, parsed, parent_times, i;
782
783 *ret = NULL;
784 parsed = 0;
785 parent_times = 0;
786
787 /* searching for nodeset */
788 do {
789 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
790 LOGVAL(DE_INCHAR, unres->line, path[-i], path-i);
791 goto error;
792 }
793 parsed += i;
794 path += i;
795
796 if (!*ret) {
797 *ret = calloc(1, sizeof **ret);
798 for (i = 0; i < parent_times; ++i) {
799 /* relative path */
800 if (!*ret) {
801 /* error, too many .. */
802 LOGVAL(DE_INVAL, unres->line, path, unres->dnode->schema->name);
803 goto error;
804 } else if (!(*ret)->dnode) {
805 /* first .. */
806 (*ret)->dnode = unres->dnode->parent;
807 } else if (!(*ret)->dnode->parent) {
808 /* we are in root */
809 free(*ret);
810 *ret = NULL;
811 } else {
812 /* multiple .. */
813 (*ret)->dnode = (*ret)->dnode->parent;
814 }
815 }
816
817 /* absolute path */
818 if (parent_times == -1) {
819 for (data = unres->dnode; data->parent; data = data->parent);
820 for (; data->prev->next; data = data->prev);
821 }
822 }
823
824 /* node identifier */
825 if (resolve_data_nodeid(prefix, pref_len, name, nam_len, data, ret)) {
826 LOGVAL(DE_INVAL, unres->line, nam_len, name);
827 goto error;
828 }
829
830 if (has_predicate) {
831 /* we have predicate, so the current results must be lists */
832 for (raux = NULL, riter = *ret; riter; ) {
Radek Krejci76512572015-08-04 09:47:08 +0200833 if (riter->dnode->schema->nodetype == LYS_LIST &&
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200834 ((struct ly_mnode_list *)riter->dnode->schema)->keys) {
835 /* leafref is ok, continue check with next leafref */
836 raux = riter;
837 riter = riter->next;
838 continue;
839 }
840
841 /* does not fulfill conditions, remove leafref record */
842 if (raux) {
843 raux->next = riter->next;
844 free(riter);
845 riter = raux->next;
846 } else {
847 *ret = riter->next;
848 free(riter);
849 riter = *ret;
850 }
851 }
852 if ((i = resolve_path_predicate(path, ret)) < 1) {
853 LOGVAL(DE_INPRED, unres->line, path-i);
854 goto error;
855 }
856 parsed += i;
857 path += i;
858
859 if (!*ret) {
860 LOGVAL(DE_NORESOLV, unres->line, name);
861 goto error;
862 }
863 }
864 } while (path[0] != '\0');
865
866 return 0;
867
868error:
869
870 while (*ret) {
871 raux = (*ret)->next;
872 free(*ret);
873 *ret = raux;
874 }
875
876 return 1;
877}
878
879/* ... /node[target = value] ... */
880static int
881resolve_predicate(const char *pred, struct leafref_instid **node_match)
882{
883 struct leafref_instid *target_match, *node, *node_prev = NULL, *tmp;
884 const char *prefix, *name, *value;
885 int pref_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed;
886
887 idx = -1;
888 parsed = 0;
889
890 do {
891 if ((i = parse_predicate(pred, &prefix, &pref_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
892 return -parsed+i;
893 }
894 parsed += i;
895 pred += i;
896
897 if (isdigit(name[0])) {
898 idx = atoi(name);
899 }
900
901 for (cur_idx = 0, node = *node_match; node; ++cur_idx) {
902 /* target */
903 target_match = NULL;
904 if ((name[0] == '.') || !value) {
905 target_match = calloc(1, sizeof *target_match);
906 target_match->dnode = node->dnode;
907 } else if (resolve_data_nodeid(prefix, pref_len, name, nam_len, node->dnode, &target_match)) {
908 return -parsed;
909 }
910
911 /* check that we have the correct type */
912 if (name[0] == '.') {
Radek Krejci76512572015-08-04 09:47:08 +0200913 if (node->dnode->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200914 goto remove_instid;
915 }
916 } else if (value) {
Radek Krejci76512572015-08-04 09:47:08 +0200917 if (node->dnode->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200918 goto remove_instid;
919 }
920 }
921
922 if ((value && (strncmp(((struct lyd_node_leaf *)target_match->dnode)->value_str, value, val_len)
923 || ((struct lyd_node_leaf *)target_match->dnode)->value_str[val_len]))
924 || (!value && (idx != cur_idx))) {
925 goto remove_instid;
926 }
927
928 while (target_match) {
929 tmp = target_match->next;
930 free(target_match);
931 target_match = tmp;
932 }
933
934 /* leafref is ok, continue check with next leafref */
935 node_prev = node;
936 node = node->next;
937 continue;
938
939remove_instid:
940 while (target_match) {
941 tmp = target_match->next;
942 free(target_match);
943 target_match = tmp;
944 }
945
946 /* does not fulfill conditions, remove leafref record */
947 if (node_prev) {
948 node_prev->next = node->next;
949 free(node);
950 node = node_prev->next;
951 } else {
952 node = (*node_match)->next;
953 free(*node_match);
954 *node_match = node;
955 }
956 }
957 } while (has_predicate);
958
959 return parsed;
960}
961
962int
963resolve_instid(struct leafref_instid *unres, const char *path, int path_len, struct leafref_instid **ret)
964{
965 struct lyd_node *data;
966 struct leafref_instid *riter = NULL, *raux;
967 const char *apath = strndupa(path, path_len);
968 const char *prefix, *name;
969 int i, parsed, pref_len, nam_len, has_predicate;
970
971 parsed = 0;
972
973 /* we need root, absolute path */
974 for (data = unres->dnode; data->parent; data = data->parent);
975 for (; data->prev->next; data = data->prev);
976
977 /* searching for nodeset */
978 do {
979 if ((i = parse_instance_identifier(apath, &prefix, &pref_len, &name, &nam_len, &has_predicate)) < 1) {
980 LOGVAL(DE_INCHAR, unres->line, apath[-i], apath-i);
981 goto error;
982 }
983 parsed += i;
984 apath += i;
985
986 if (resolve_data_nodeid(prefix, pref_len, name, nam_len, data, ret)) {
987 LOGVAL(DE_INELEMLEN, unres->line, nam_len, name);
988 goto error;
989 }
990
991 if (has_predicate) {
992 /* we have predicate, so the current results must be list or leaf-list */
993 for (raux = NULL, riter = *ret; riter; ) {
Radek Krejci76512572015-08-04 09:47:08 +0200994 if ((riter->dnode->schema->nodetype == LYS_LIST &&
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200995 ((struct ly_mnode_list *)riter->dnode->schema)->keys)
Radek Krejci76512572015-08-04 09:47:08 +0200996 || (riter->dnode->schema->nodetype == LYS_LEAFLIST)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +0200997 /* instid is ok, continue check with next instid */
998 raux = riter;
999 riter = riter->next;
1000 continue;
1001 }
1002
1003 /* does not fulfill conditions, remove inst record */
1004 if (raux) {
1005 raux->next = riter->next;
1006 free(riter);
1007 riter = raux->next;
1008 } else {
1009 *ret = riter->next;
1010 free(riter);
1011 riter = *ret;
1012 }
1013 }
1014 if ((i = resolve_predicate(apath, ret)) < 1) {
1015 LOGVAL(DE_INPRED, unres->line, apath-i);
1016 goto error;
1017 }
1018 parsed += i;
1019 apath += i;
1020
1021 if (!*ret) {
1022 LOGVAL(DE_NORESOLV, unres->line, name);
1023 goto error;
1024 }
1025 }
1026 } while (apath[0] != '\0');
1027
1028 return 0;
1029
1030error:
1031 while (*ret) {
1032 raux = (*ret)->next;
1033 free(*ret);
1034 *ret = raux;
1035 }
1036
1037 return 1;
1038}
1039
1040static void
Radek Krejci76512572015-08-04 09:47:08 +02001041inherit_config_flag(struct lys_node *mnode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001042{
1043 LY_TREE_FOR(mnode, mnode) {
Radek Krejci1574a8d2015-08-03 14:16:52 +02001044 mnode->flags |= mnode->parent->flags & LYS_CONFIG_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001045 inherit_config_flag(mnode->child);
1046 }
1047}
1048
1049static int
Michal Vasko12e30842015-08-04 11:54:00 +02001050resolve_augment(struct lys_node_augment *aug, struct lys_node *parent, struct ly_module *module, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001051{
Radek Krejci76512572015-08-04 09:47:08 +02001052 struct lys_node *sub, *aux;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001053
1054 assert(module);
1055
1056 /* resolve target node */
Radek Krejci76512572015-08-04 09:47:08 +02001057 aug->target = resolve_schema_nodeid(aug->target_name, parent, module, LYS_AUGMENT);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001058 if (!aug->target) {
Michal Vasko12e30842015-08-04 11:54:00 +02001059 if (line > -1) {
1060 LOGVAL(VE_INARG, line, aug->target_name, "uses");
1061 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001062 return EXIT_FAILURE;
1063 }
1064
1065 if (!aug->child) {
1066 /* nothing to do */
1067 return EXIT_SUCCESS;
1068 }
1069
1070 /* inherit config information from parent, augment does not have
1071 * config property, but we need to keep the information for subelements
1072 */
Radek Krejci1574a8d2015-08-03 14:16:52 +02001073 aug->flags |= aug->target->flags & LYS_CONFIG_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001074 LY_TREE_FOR(aug->child, sub) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001075 inherit_config_flag(sub);
1076 }
1077
Radek Krejci0acbe1b2015-08-04 09:33:49 +02001078 /* reconnect augmenting data into the target - add them to the target child list */
1079 if (aug->target->child) {
1080 aux = aug->target->child->prev; /* remember current target's last node */
1081 aux->next = aug->child; /* connect augmenting data after target's last node */
1082 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
1083 aug->child->prev = aux; /* finish connecting of both child lists */
1084 } else {
1085 aug->target->child = aug->child;
1086 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001087
1088 return EXIT_SUCCESS;
1089}
1090
1091int
Michal Vasko12e30842015-08-04 11:54:00 +02001092resolve_uses(struct ly_mnode_uses *uses, int line, struct unres_item *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001093{
1094 struct ly_ctx *ctx;
Radek Krejci76512572015-08-04 09:47:08 +02001095 struct lys_node *mnode = NULL, *mnode_aux;
1096 struct lys_refine *rfn;
Radek Krejci1574a8d2015-08-03 14:16:52 +02001097 struct lys_restr *newmust;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001098 int i, j;
1099 uint8_t size;
1100
1101 /* copy the data nodes from grouping into the uses context */
1102 LY_TREE_FOR(uses->grp->child, mnode) {
1103 mnode_aux = ly_mnode_dup(uses->module, mnode, uses->flags, 1, line, unres);
1104 if (!mnode_aux) {
Michal Vasko12e30842015-08-04 11:54:00 +02001105 if (line > -1) {
1106 LOGVAL(VE_SPEC, line, "Copying data from grouping failed");
1107 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001108 return EXIT_FAILURE;
1109 }
Radek Krejci76512572015-08-04 09:47:08 +02001110 if (ly_mnode_addchild((struct lys_node *)uses, mnode_aux)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001111 ly_mnode_free(mnode_aux);
1112 return EXIT_FAILURE;
1113 }
1114 }
1115 ctx = uses->module->ctx;
1116
1117 /* apply refines */
1118 for (i = 0; i < uses->refine_size; i++) {
1119 rfn = &uses->refine[i];
Radek Krejci76512572015-08-04 09:47:08 +02001120 mnode = resolve_schema_nodeid(rfn->target_name, (struct lys_node *)uses, uses->module, LYS_USES);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001121 if (!mnode) {
Michal Vasko12e30842015-08-04 11:54:00 +02001122 if (line > -1) {
1123 LOGVAL(VE_INARG, line, rfn->target_name, "uses");
1124 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001125 return EXIT_FAILURE;
1126 }
1127
1128 if (rfn->target_type && !(mnode->nodetype & rfn->target_type)) {
Michal Vasko12e30842015-08-04 11:54:00 +02001129 if (line > -1) {
1130 LOGVAL(VE_SPEC, line, "refine substatements not applicable to the target-node");
1131 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001132 return EXIT_FAILURE;
1133 }
1134
1135 /* description on any nodetype */
1136 if (rfn->dsc) {
1137 lydict_remove(ctx, mnode->dsc);
1138 mnode->dsc = lydict_insert(ctx, rfn->dsc, 0);
1139 }
1140
1141 /* reference on any nodetype */
1142 if (rfn->ref) {
1143 lydict_remove(ctx, mnode->ref);
1144 mnode->ref = lydict_insert(ctx, rfn->ref, 0);
1145 }
1146
1147 /* config on any nodetype */
Radek Krejci1574a8d2015-08-03 14:16:52 +02001148 if (rfn->flags & LYS_CONFIG_MASK) {
1149 mnode->flags &= ~LYS_CONFIG_MASK;
1150 mnode->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001151 }
1152
1153 /* default value ... */
1154 if (rfn->mod.dflt) {
Radek Krejci76512572015-08-04 09:47:08 +02001155 if (mnode->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001156 /* leaf */
1157 lydict_remove(ctx, ((struct ly_mnode_leaf *)mnode)->dflt);
1158 ((struct ly_mnode_leaf *)mnode)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
Radek Krejci76512572015-08-04 09:47:08 +02001159 } else if (mnode->nodetype == LYS_CHOICE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001160 /* choice */
Radek Krejci76512572015-08-04 09:47:08 +02001161 ((struct ly_mnode_choice *)mnode)->dflt = resolve_schema_nodeid(rfn->mod.dflt, mnode, mnode->module, LYS_CHOICE);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001162 if (!((struct ly_mnode_choice *)mnode)->dflt) {
Michal Vasko12e30842015-08-04 11:54:00 +02001163 if (line > -1) {
1164 LOGVAL(VE_INARG, line, rfn->mod.dflt, "default");
1165 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001166 return EXIT_FAILURE;
1167 }
1168 }
1169 }
1170
1171 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02001172 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejci76512572015-08-04 09:47:08 +02001173 if (mnode->nodetype & (LYS_LEAF | LYS_ANYXML | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001174 /* remove current value */
Radek Krejci1574a8d2015-08-03 14:16:52 +02001175 mnode->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001176
1177 /* set new value */
Radek Krejci1574a8d2015-08-03 14:16:52 +02001178 mnode->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001179 }
1180 }
1181
1182 /* presence on container */
Radek Krejci76512572015-08-04 09:47:08 +02001183 if ((mnode->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001184 lydict_remove(ctx, ((struct ly_mnode_container *)mnode)->presence);
1185 ((struct ly_mnode_container *)mnode)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
1186 }
1187
1188 /* min/max-elements on list or leaf-list */
1189 /* magic - bit 3 in flags means min set, bit 4 says max set */
Radek Krejci76512572015-08-04 09:47:08 +02001190 if (mnode->nodetype == LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001191 if (rfn->flags & 0x04) {
1192 ((struct ly_mnode_list *)mnode)->min = rfn->mod.list.min;
1193 }
1194 if (rfn->flags & 0x08) {
1195 ((struct ly_mnode_list *)mnode)->max = rfn->mod.list.max;
1196 }
Radek Krejci76512572015-08-04 09:47:08 +02001197 } else if (mnode->nodetype == LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001198 if (rfn->flags & 0x04) {
1199 ((struct ly_mnode_leaflist *)mnode)->min = rfn->mod.list.min;
1200 }
1201 if (rfn->flags & 0x08) {
1202 ((struct ly_mnode_leaflist *)mnode)->max = rfn->mod.list.max;
1203 }
1204 }
1205
1206 /* must in leaf, leaf-list, list, container or anyxml */
1207 if (rfn->must_size) {
1208 size = ((struct ly_mnode_leaf *)mnode)->must_size + rfn->must_size;
1209 newmust = realloc(((struct ly_mnode_leaf *)mnode)->must, size * sizeof *rfn->must);
1210 if (!newmust) {
1211 LOGMEM;
1212 return EXIT_FAILURE;
1213 }
1214 for (i = 0, j = ((struct ly_mnode_leaf *)mnode)->must_size; i < rfn->must_size; i++, j++) {
1215 newmust[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
1216 newmust[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
1217 newmust[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
1218 newmust[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
1219 newmust[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
1220 }
1221
1222 ((struct ly_mnode_leaf *)mnode)->must = newmust;
1223 ((struct ly_mnode_leaf *)mnode)->must_size = size;
1224 }
1225 }
1226
1227 /* apply augments */
1228 for (i = 0; i < uses->augment_size; i++) {
Radek Krejci76512572015-08-04 09:47:08 +02001229 if (resolve_augment(&uses->augment[i], (struct lys_node *)uses, uses->module, line)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001230 goto error;
1231 }
1232 }
1233
1234 return EXIT_SUCCESS;
1235
1236error:
1237
1238 return EXIT_FAILURE;
1239}
1240
1241static struct ly_ident *
1242resolve_base_ident_sub(struct ly_module *module, struct ly_ident *ident, const char *basename)
1243{
1244 unsigned int i, j;
1245 struct ly_ident *base_iter = NULL;
1246 struct ly_ident_der *der;
1247
1248 /* search module */
1249 for (i = 0; i < module->ident_size; i++) {
1250 if (!strcmp(basename, module->ident[i].name)) {
1251
1252 if (!ident) {
1253 /* just search for type, so do not modify anything, just return
1254 * the base identity pointer
1255 */
1256 return &module->ident[i];
1257 }
1258
1259 /* we are resolving identity definition, so now update structures */
1260 ident->base = base_iter = &module->ident[i];
1261
1262 break;
1263 }
1264 }
1265
1266 /* search submodules */
1267 if (!base_iter) {
1268 for (j = 0; j < module->inc_size; j++) {
1269 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
1270 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
1271
1272 if (!ident) {
1273 return &module->inc[j].submodule->ident[i];
1274 }
1275
1276 ident->base = base_iter = &module->inc[j].submodule->ident[i];
1277 break;
1278 }
1279 }
1280 }
1281 }
1282
1283 /* we found it somewhere */
1284 if (base_iter) {
1285 while (base_iter) {
1286 for (der = base_iter->der; der && der->next; der = der->next);
1287 if (der) {
1288 der->next = malloc(sizeof *der);
1289 der = der->next;
1290 } else {
1291 ident->base->der = der = malloc(sizeof *der);
1292 }
1293 der->next = NULL;
1294 der->ident = ident;
1295
1296 base_iter = base_iter->base;
1297 }
1298 return ident->base;
1299 }
1300
1301 return NULL;
1302}
1303
1304static struct ly_ident *
1305resolve_base_ident(struct ly_module *module, struct ly_ident *ident, const char *basename, int line,
1306 const char* parent)
1307{
1308 const char *name;
1309 int prefix_len = 0;
1310 int i, found = 0;
1311 struct ly_ident *result;
1312
1313 /* search for the base identity */
1314 name = strchr(basename, ':');
1315 if (name) {
1316 /* set name to correct position after colon */
1317 prefix_len = name - basename;
1318 name++;
1319
1320 if (!strncmp(basename, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
1321 /* prefix refers to the current module, ignore it */
1322 prefix_len = 0;
1323 }
1324 } else {
1325 name = basename;
1326 }
1327
1328 if (prefix_len) {
1329 /* get module where to search */
1330 for (i = 0; i < module->imp_size; i++) {
1331 if (!strncmp(module->imp[i].prefix, basename, prefix_len)
1332 && !module->imp[i].prefix[prefix_len]) {
1333 module = module->imp[i].module;
1334 found = 1;
1335 break;
1336 }
1337 }
1338 if (!found) {
1339 /* identity refers unknown data model */
Michal Vasko12e30842015-08-04 11:54:00 +02001340 if (line > -1) {
1341 LOGVAL(VE_INPREFIX, line, basename);
1342 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001343 return NULL;
1344 }
1345 } else {
1346 /* search in submodules */
1347 for (i = 0; i < module->inc_size; i++) {
1348 result = resolve_base_ident_sub((struct ly_module *)module->inc[i].submodule, ident, name);
1349 if (result) {
1350 return result;
1351 }
1352 }
1353 }
1354
1355 /* search in the identified module */
1356 result = resolve_base_ident_sub(module, ident, name);
Michal Vasko12e30842015-08-04 11:54:00 +02001357 if (!result && (line > -1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001358 LOGVAL(VE_INARG, line, basename, parent);
1359 }
1360
1361 return result;
1362}
1363
1364struct ly_ident *
1365resolve_identityref(struct ly_ident *base, const char *name, const char *ns)
1366{
1367 struct ly_ident_der *der;
1368
1369 if (!base || !name || !ns) {
1370 return NULL;
1371 }
1372
1373 for(der = base->der; der; der = der->next) {
1374 if (!strcmp(der->ident->name, name) && ns == der->ident->module->ns) {
1375 /* we have match */
1376 return der->ident;
1377 }
1378 }
1379
1380 /* not found */
1381 return NULL;
1382}
1383
1384static int
1385resolve_unres_ident(struct ly_module *mod, struct ly_ident *ident, const char *base_name, int line)
1386{
1387 if (resolve_base_ident(mod, ident, base_name, line, "ident")) {
1388 return 0;
1389 }
1390
Michal Vasko12e30842015-08-04 11:54:00 +02001391 if (line > -1) {
1392 LOGVAL(VE_NORESOLV, line, "identity", base_name);
1393 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001394 return 1;
1395}
1396
1397static int
Radek Krejci1574a8d2015-08-03 14:16:52 +02001398resolve_unres_type_identref(struct ly_module *mod, struct lys_type *type, const char *base_name, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001399{
1400 type->info.ident.ref = resolve_base_ident(mod, NULL, base_name, line, "type");
1401 if (type->info.ident.ref) {
1402 return 0;
1403 }
1404
Michal Vasko12e30842015-08-04 11:54:00 +02001405 if (line > -1) {
1406 LOGVAL(VE_NORESOLV, line, "identityref", base_name);
1407 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001408 return 1;
1409}
1410
1411static int
Radek Krejci76512572015-08-04 09:47:08 +02001412resolve_unres_type_leafref(struct ly_module *mod, struct lys_type *type, struct lys_node *mnode, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001413{
Radek Krejci76512572015-08-04 09:47:08 +02001414 if (resolve_schema_nodeid(type->info.lref.path, mnode, mod, LYS_LEAF)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001415 return 0;
1416 }
1417
Michal Vasko12e30842015-08-04 11:54:00 +02001418 if (line > -1) {
1419 LOGVAL(VE_NORESOLV, line, "leafref", type->info.lref.path);
1420 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001421 return 1;
1422}
1423
1424static int
Radek Krejci1574a8d2015-08-03 14:16:52 +02001425resolve_unres_type_der(struct ly_module *mod, struct lys_type *type, const char *type_name, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001426{
Radek Krejci76512572015-08-04 09:47:08 +02001427 type->der = resolve_superior_type(type_name, type->prefix, mod, (struct lys_node *)type->der);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001428 if (type->der) {
Michal Vaskoa91333d2015-08-03 16:03:06 +02001429 type->base = type->der->type.base;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001430 return 0;
1431 }
1432
Michal Vasko12e30842015-08-04 11:54:00 +02001433 if (line > -1) {
1434 LOGVAL(VE_NORESOLV, line, "type", type_name);
1435 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001436 return 1;
1437}
1438
1439static int
Radek Krejci76512572015-08-04 09:47:08 +02001440resolve_unres_augment(struct ly_module *mod, struct lys_node_augment *aug, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001441{
Radek Krejci76512572015-08-04 09:47:08 +02001442 if (aug->parent->nodetype == LYS_USES) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001443 if ((aug->target_name[0] != '/')
Radek Krejci76512572015-08-04 09:47:08 +02001444 && resolve_schema_nodeid(aug->target_name, aug->parent->child, mod, LYS_AUGMENT)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001445 return 0;
1446 }
1447 } else {
1448 if ((aug->target_name[0] == '/')
Radek Krejci76512572015-08-04 09:47:08 +02001449 && resolve_schema_nodeid(aug->target_name, mod->data, mod, LYS_AUGMENT)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001450 return 0;
1451 }
1452 }
1453
Michal Vasko12e30842015-08-04 11:54:00 +02001454 if (line > -1) {
1455 LOGVAL(VE_NORESOLV, line, "augment", aug->target_name);
1456 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001457 return 1;
1458}
1459
1460static int
1461resolve_unres_iffeature(struct ly_module *mod, struct ly_feature **feat_ptr, const char *feat_name, int line)
1462{
1463 *feat_ptr = resolve_feature(feat_name, mod, line);
1464 if (*feat_ptr) {
1465 return 0;
1466 }
1467
Michal Vasko12e30842015-08-04 11:54:00 +02001468 if (line > -1) {
1469 LOGVAL(VE_NORESOLV, line, "if-feature", feat_name);
1470 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001471 return 1;
1472}
1473
1474static int
1475resolve_unres_uses(struct ly_mnode_uses *uses, int line, struct unres_item *unres)
1476{
1477 if (uses->grp || !resolve_grouping(uses->parent, uses, line)) {
Michal Vasko12e30842015-08-04 11:54:00 +02001478 if (!resolve_uses(uses, line, unres)) {
1479 return 0;
1480 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001481 }
1482
Michal Vasko12e30842015-08-04 11:54:00 +02001483 if (line > -1) {
1484 LOGVAL(VE_NORESOLV, line, "uses", uses->name);
1485 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001486 return 1;
1487}
1488
1489static int
Radek Krejci1574a8d2015-08-03 14:16:52 +02001490resolve_unres_type_dflt(struct lys_type *type, const char *dflt, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001491{
Michal Vasko12e30842015-08-04 11:54:00 +02001492 if (!check_default(type, dflt)) {
1493 return 0;
1494 }
1495
1496 if (line > -1) {
1497 LOGVAL(VE_NORESOLV, line, "type default", dflt);
1498 }
1499 return 1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001500}
1501
1502static int
Michal Vasko12e30842015-08-04 11:54:00 +02001503resolve_unres_choice_dflt(struct ly_mnode_choice *choice, const char *dflt, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001504{
Radek Krejci76512572015-08-04 09:47:08 +02001505 choice->dflt = resolve_child((struct lys_node *)choice, dflt, 0, LYS_ANYXML | LYS_CASE
1506 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001507 if (choice->dflt) {
1508 return 0;
1509 }
1510
Michal Vasko12e30842015-08-04 11:54:00 +02001511 if (line > -1) {
1512 LOGVAL(VE_NORESOLV, line, "choice default", dflt);
1513 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001514 return 1;
1515}
1516
1517static int
1518resolve_unres_list_keys(struct ly_mnode_list *list, const char *keys_str, int line)
1519{
1520 int i, len;
1521 const char *value;
1522
1523 for (i = 0; i < list->keys_size; ++i) {
1524 /* get the key name */
1525 if ((value = strpbrk(keys_str, " \t\n"))) {
1526 len = value - keys_str;
1527 while (isspace(value[0])) {
1528 value++;
1529 }
1530 } else {
1531 len = strlen(keys_str);
1532 }
1533
Radek Krejci76512572015-08-04 09:47:08 +02001534 list->keys[i] = (struct ly_mnode_leaf *)resolve_child((struct lys_node *)list, keys_str, len, LYS_LEAF);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001535
1536 if (check_key(list->keys[i], list->flags, list->keys, i, line, keys_str, len)) {
Michal Vasko12e30842015-08-04 11:54:00 +02001537 if (line > -1) {
1538 LOGVAL(VE_NORESOLV, line, "list keys", keys_str);
1539 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001540 return 1;
1541 }
1542
1543 /* prepare for next iteration */
1544 while (value && isspace(value[0])) {
1545 value++;
1546 }
1547 keys_str = value;
1548 }
1549
1550 return 0;
1551}
1552
1553static int
Radek Krejci76512572015-08-04 09:47:08 +02001554resolve_unres_list_uniq(struct lys_unique *uniq, const char *uniq_str, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001555{
Michal Vasko12e30842015-08-04 11:54:00 +02001556 if (!resolve_unique((struct lys_node *)uniq->leafs, uniq_str, uniq, line)) {
1557 return 0;
1558 }
1559
1560 if (line > -1) {
1561 LOGVAL(VE_NORESOLV, line, "list unique", uniq_str);
1562 }
1563 return 1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001564}
1565
1566static int
Radek Krejci76512572015-08-04 09:47:08 +02001567resolve_unres_when(struct lys_when *UNUSED(when), struct lys_node *UNUSED(start), int UNUSED(line))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001568{
1569 /* TODO */
1570 return 0;
1571}
1572
1573static int
Radek Krejci76512572015-08-04 09:47:08 +02001574resolve_unres_must(struct lys_restr *UNUSED(must), struct lys_node *UNUSED(start), int UNUSED(line))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001575{
1576 /* TODO */
1577 return 0;
1578}
1579
Michal Vasko12e30842015-08-04 11:54:00 +02001580/* line == -1 means do not log, 0 means unknown */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001581static int
1582resolve_unres_item(struct ly_module *mod, void *item, enum UNRES_ITEM type, void *str_mnode, int line,
1583 struct unres_item *unres)
1584{
1585 int ret = EXIT_FAILURE, has_str = 0;
1586
1587 switch (type) {
1588 case UNRES_RESOLVED:
1589 assert(0);
1590 case UNRES_IDENT:
1591 ret = resolve_unres_ident(mod, item, str_mnode, line);
1592 has_str = 1;
1593 break;
1594 case UNRES_TYPE_IDENTREF:
1595 ret = resolve_unres_type_identref(mod, item, str_mnode, line);
1596 has_str = 1;
1597 break;
1598 case UNRES_TYPE_LEAFREF:
1599 ret = resolve_unres_type_leafref(mod, item, str_mnode, line);
1600 has_str = 0;
1601 break;
1602 case UNRES_TYPE_DER:
1603 ret = resolve_unres_type_der(mod, item, str_mnode, line);
1604 has_str = 1;
1605 break;
1606 case UNRES_AUGMENT:
1607 ret = resolve_unres_augment(mod, item, line);
1608 has_str = 0;
1609 break;
1610 case UNRES_IFFEAT:
1611 ret = resolve_unres_iffeature(mod, item, str_mnode, line);
1612 has_str = 1;
1613 break;
1614 case UNRES_USES:
1615 ret = resolve_unres_uses(item, line, unres);
1616 has_str = 0;
1617 break;
1618 case UNRES_TYPE_DFLT:
1619 ret = resolve_unres_type_dflt(item, str_mnode, line);
1620 /* do not remove str_mnode (dflt), it's in a typedef */
1621 has_str = 0;
1622 break;
1623 case UNRES_CHOICE_DFLT:
Michal Vasko12e30842015-08-04 11:54:00 +02001624 ret = resolve_unres_choice_dflt(item, str_mnode, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001625 has_str = 1;
1626 break;
1627 case UNRES_LIST_KEYS:
1628 ret = resolve_unres_list_keys(item, str_mnode, line);
1629 has_str = 1;
1630 break;
1631 case UNRES_LIST_UNIQ:
1632 ret = resolve_unres_list_uniq(item, str_mnode, line);
1633 has_str = 1;
1634 break;
1635 case UNRES_WHEN:
1636 ret = resolve_unres_when(item, str_mnode, line);
1637 has_str = 0;
1638 break;
1639 case UNRES_MUST:
1640 ret = resolve_unres_must(item, str_mnode, line);
1641 has_str = 0;
1642 break;
1643 }
1644
1645 if (has_str && !ret) {
1646 lydict_remove(mod->ctx, str_mnode);
1647 }
1648
1649 return ret;
1650}
1651
1652int
1653resolve_unres(struct ly_module *mod, struct unres_item *unres)
1654{
1655 unsigned int i, resolved = 0;
1656
1657 assert(unres);
1658
1659 /* uses */
1660 for (i = 0; i < unres->count; ++i) {
1661 if (unres->type[i] != UNRES_USES) {
1662 continue;
1663 }
1664 if (!resolve_unres_item(mod, unres->item[i], unres->type[i], unres->str_mnode[i], unres->line[i], unres)) {
1665 unres->type[i] = UNRES_RESOLVED;
1666 ++resolved;
1667 }
1668 }
1669
1670 /* augment */
1671 for (i = 0; i < unres->count; ++i) {
1672 if (unres->type[i] != UNRES_AUGMENT) {
1673 continue;
1674 }
1675 if (!resolve_unres_item(mod, unres->item[i], unres->type[i], unres->str_mnode[i], unres->line[i], unres)) {
1676 unres->type[i] = UNRES_RESOLVED;
1677 ++resolved;
1678 }
1679 }
1680
1681 /* the rest */
1682 for (i = 0; i < unres->count; ++i) {
1683 if (unres->type[i] == UNRES_RESOLVED) {
1684 continue;
1685 }
1686 if (!resolve_unres_item(mod, unres->item[i], unres->type[i], unres->str_mnode[i], unres->line[i], unres)) {
1687 unres->type[i] = UNRES_RESOLVED;
1688 ++resolved;
1689 }
1690 }
1691
1692 if (resolved < unres->count) {
1693 return EXIT_FAILURE;
1694 }
1695
1696 return EXIT_SUCCESS;
1697}
1698
1699void
1700add_unres_str(struct ly_module *mod, struct unres_item *unres, void *item, enum UNRES_ITEM type, const char *str,
1701 int line)
1702{
1703 str = lydict_insert(mod->ctx, str, 0);
Radek Krejci76512572015-08-04 09:47:08 +02001704 add_unres_mnode(mod, unres, item, type, (struct lys_node *)str, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001705}
1706
1707void
1708add_unres_mnode(struct ly_module *mod, struct unres_item *unres, void *item, enum UNRES_ITEM type,
Radek Krejci76512572015-08-04 09:47:08 +02001709 struct lys_node *mnode, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001710{
1711 assert(unres && item);
1712
Michal Vasko12e30842015-08-04 11:54:00 +02001713 if (!resolve_unres_item(mod, item, type, mnode, -1, unres)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001714 return;
1715 }
1716
1717 unres->count++;
1718 unres->item = realloc(unres->item, unres->count*sizeof *unres->item);
1719 unres->item[unres->count-1] = item;
1720 unres->type = realloc(unres->type, unres->count*sizeof *unres->type);
1721 unres->type[unres->count-1] = type;
1722 unres->str_mnode = realloc(unres->str_mnode, unres->count*sizeof *unres->str_mnode);
1723 unres->str_mnode[unres->count-1] = mnode;
1724 unres->line = realloc(unres->line, unres->count*sizeof *unres->line);
1725 unres->line[unres->count-1] = line;
1726}
1727
1728void
1729dup_unres(struct ly_module *mod, struct unres_item *unres, void *item, enum UNRES_ITEM type, void *new_item)
1730{
1731 int i;
1732
1733 if (!item || !new_item) {
1734 return;
1735 }
1736
1737 i = find_unres(unres, item, type);
1738
1739 if (i == -1) {
1740 return;
1741 }
1742
1743 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_AUGMENT) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT)
1744 || (type == UNRES_WHEN) || (type == UNRES_MUST)) {
1745 add_unres_mnode(mod, unres, new_item, type, unres->str_mnode[i], 0);
1746 } else {
1747 add_unres_str(mod, unres, new_item, type, unres->str_mnode[i], 0);
1748 }
1749}
1750
1751int
1752find_unres(struct unres_item *unres, void *item, enum UNRES_ITEM type)
1753{
1754 uint32_t ret = -1, i;
1755
1756 for (i = 0; i < unres->count; ++i) {
1757 if ((unres->item[i] == item) && (unres->type[i] == type)) {
1758 ret = i;
1759 break;
1760 }
1761 }
1762
1763 return ret;
1764}