blob: 692acaa8f19ac90aee5798978c9bcf002e9b50f2 [file] [log] [blame]
Radek Krejci86d106e2018-10-18 09:53:19 +02001/**
2 * @file tree_schema_helpers.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Parsing and validation helper functions
5 *
6 * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
Radek Krejci9ed7a192018-10-31 16:23:51 +010014#include "common.h"
Radek Krejci86d106e2018-10-18 09:53:19 +020015
16#include <ctype.h>
Radek Krejci9ed7a192018-10-31 16:23:51 +010017#include <dirent.h>
18#include <errno.h>
19#include <fcntl.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020020#include <limits.h>
Radek Krejci9ed7a192018-10-31 16:23:51 +010021#include <stdlib.h>
22#include <sys/stat.h>
23#include <sys/types.h>
24#include <unistd.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020025#include <time.h>
26
27#include "libyang.h"
Radek Krejci86d106e2018-10-18 09:53:19 +020028#include "tree_schema_internal.h"
29
Radek Krejcia3045382018-11-22 14:30:31 +010030/**
31 * @brief Parse an identifier.
32 *
33 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
34 * identifier = (ALPHA / "_")
35 * *(ALPHA / DIGIT / "_" / "-" / ".")
36 *
37 * @param[in,out] id Identifier to parse. When returned, it points to the first character which is not part of the identifier.
38 * @return LY_ERR value: LY_SUCCESS or LY_EINVAL in case of invalid starting character.
39 */
40static LY_ERR
41lys_parse_id(const char **id)
42{
43 assert(id && *id);
44
Radek Krejcia9026eb2018-12-12 16:04:47 +010045 if (!is_yangidentstartchar(**id)) {
Radek Krejcia3045382018-11-22 14:30:31 +010046 return LY_EINVAL;
47 }
48 ++(*id);
49
Radek Krejcia9026eb2018-12-12 16:04:47 +010050 while (is_yangidentchar(**id)) {
Radek Krejcia3045382018-11-22 14:30:31 +010051 ++(*id);
52 }
53 return LY_SUCCESS;
54}
55
56LY_ERR
57lys_parse_nodeid(const char **id, const char **prefix, size_t *prefix_len, const char **name, size_t *name_len)
58{
59 assert(id && *id);
60 assert(prefix && prefix_len);
61 assert(name && name_len);
62
63 *prefix = *id;
64 *prefix_len = 0;
65 *name = NULL;
66 *name_len = 0;
67
68 LY_CHECK_RET(lys_parse_id(id));
69 if (**id == ':') {
70 /* there is prefix */
71 *prefix_len = *id - *prefix;
72 ++(*id);
73 *name = *id;
74
75 LY_CHECK_RET(lys_parse_id(id));
76 *name_len = *id - *name;
77 } else {
78 /* there is no prefix, so what we have as prefix now is actually the name */
79 *name = *prefix;
80 *name_len = *id - *name;
81 *prefix = NULL;
82 }
83
84 return LY_SUCCESS;
85}
86
Radek Krejci86d106e2018-10-18 09:53:19 +020087LY_ERR
Radek Krejci9bb94eb2018-12-04 16:48:35 +010088lys_resolve_descendant_schema_nodeid(struct lysc_ctx *ctx, const char *nodeid, size_t nodeid_len, const struct lysc_node *context_node,
89 int nodetype, const struct lysc_node **target)
90{
91 LY_ERR ret = LY_EVALID;
92 const char *name, *prefix, *id;
93 const struct lysc_node *context;
94 size_t name_len, prefix_len;
95 const struct lys_module *mod;
96
97 assert(nodeid);
98 assert(context_node);
99 assert(target);
100 *target = NULL;
101
102 id = nodeid;
103 context = context_node;
104 while (*id && (ret = lys_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len)) == LY_SUCCESS) {
105 if (prefix) {
106 mod = lys_module_find_prefix(context_node->module, prefix, prefix_len);
107 if (!mod) {
108 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
109 "Invalid descendant-schema-nodeid value \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100110 id - nodeid, nodeid, prefix_len, prefix, context_node->module->name);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100111 return LY_ENOTFOUND;
112 }
113 } else {
114 mod = context_node->module;
115 }
Radek Krejcia9026eb2018-12-12 16:04:47 +0100116 context = lys_child(context, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100117 if (!context) {
118 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
119 "Invalid descendant-schema-nodeid value \"%.*s\" - target node not found.", id - nodeid, nodeid);
120 return LY_ENOTFOUND;
121 }
Radek Krejci01342af2019-01-03 15:18:08 +0100122 if (!*id || (nodeid_len && ((size_t)(id - nodeid) >= nodeid_len))) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100123 break;
124 }
Radek Krejci01342af2019-01-03 15:18:08 +0100125 if (*id != '/') {
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100126 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
127 "Invalid descendant-schema-nodeid value \"%.*s\" - missing \"/\" as node-identifier separator.",
Radek Krejci665421c2018-12-05 08:03:39 +0100128 id - nodeid + 1, nodeid);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100129 return LY_EVALID;
130 }
131 ++id;
132 }
133
134 if (ret == LY_SUCCESS) {
135 *target = context;
136 if (nodetype && !(context->nodetype & nodetype)) {
137 return LY_EDENIED;
138 }
139 }
140
141 return ret;
142}
143
144LY_ERR
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100145lysp_check_prefix(struct ly_parser_ctx *ctx, struct lysp_import *imports, const char *module_prefix, const char **value)
Radek Krejci86d106e2018-10-18 09:53:19 +0200146{
147 struct lysp_import *i;
148
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100149 if (module_prefix && &module_prefix != value && !strcmp(module_prefix, *value)) {
Radek Krejci86d106e2018-10-18 09:53:19 +0200150 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE,
151 "Prefix \"%s\" already used as module prefix.", *value);
152 return LY_EEXIST;
153 }
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100154 LY_ARRAY_FOR(imports, struct lysp_import, i) {
155 if (i->prefix && &i->prefix != value && !strcmp(i->prefix, *value)) {
156 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Prefix \"%s\" already used to import \"%s\" module.",
157 *value, i->name);
158 return LY_EEXIST;
Radek Krejci86d106e2018-10-18 09:53:19 +0200159 }
160 }
161 return LY_SUCCESS;
162}
163
164LY_ERR
Radek Krejci4f28eda2018-11-12 11:46:16 +0100165lysc_check_status(struct lysc_ctx *ctx,
166 uint16_t flags1, void *mod1, const char *name1,
167 uint16_t flags2, void *mod2, const char *name2)
168{
169 uint16_t flg1, flg2;
170
171 flg1 = (flags1 & LYS_STATUS_MASK) ? (flags1 & LYS_STATUS_MASK) : LYS_STATUS_CURR;
172 flg2 = (flags2 & LYS_STATUS_MASK) ? (flags2 & LYS_STATUS_MASK) : LYS_STATUS_CURR;
173
174 if ((flg1 < flg2) && (mod1 == mod2)) {
175 if (ctx) {
176 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
177 "A %s definition \"%s\" is not allowed to reference %s definition \"%s\".",
178 flg1 == LYS_STATUS_CURR ? "current" : "deprecated", name1,
179 flg2 == LYS_STATUS_OBSLT ? "obsolete" : "deprecated", name2);
180 }
181 return LY_EVALID;
182 }
183
184 return LY_SUCCESS;
185}
186
187LY_ERR
Radek Krejcibbe09a92018-11-08 09:36:54 +0100188lysp_check_date(struct ly_parser_ctx *ctx, const char *date, int date_len, const char *stmt)
Radek Krejci86d106e2018-10-18 09:53:19 +0200189{
190 int i;
191 struct tm tm, tm_;
192 char *r;
193
Radek Krejcibbe09a92018-11-08 09:36:54 +0100194 LY_CHECK_ARG_RET(ctx ? ctx->ctx : NULL, date, LY_EINVAL);
195 LY_CHECK_ERR_RET(date_len != LY_REV_SIZE - 1, LOGARG(ctx ? ctx->ctx : NULL, date_len), LY_EINVAL);
Radek Krejci86d106e2018-10-18 09:53:19 +0200196
197 /* check format */
198 for (i = 0; i < date_len; i++) {
199 if (i == 4 || i == 7) {
200 if (date[i] != '-') {
201 goto error;
202 }
203 } else if (!isdigit(date[i])) {
204 goto error;
205 }
206 }
207
208 /* check content, e.g. 2018-02-31 */
209 memset(&tm, 0, sizeof tm);
210 r = strptime(date, "%Y-%m-%d", &tm);
211 if (!r || r != &date[LY_REV_SIZE - 1]) {
212 goto error;
213 }
214 memcpy(&tm_, &tm, sizeof tm);
215 mktime(&tm_); /* mktime modifies tm_ if it refers invalid date */
216 if (tm.tm_mday != tm_.tm_mday) { /* e.g 2018-02-29 -> 2018-03-01 */
217 /* checking days is enough, since other errors
218 * have been checked by strptime() */
219 goto error;
220 }
221
222 return LY_SUCCESS;
223
224error:
Radek Krejcid33273d2018-10-25 14:55:52 +0200225 if (stmt) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100226 if (ctx) {
227 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LY_VCODE_INVAL, date_len, date, stmt);
228 } else {
229 LOGVAL(NULL, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, date_len, date, stmt);
230 }
Radek Krejcid33273d2018-10-25 14:55:52 +0200231 }
Radek Krejci86d106e2018-10-18 09:53:19 +0200232 return LY_EINVAL;
233}
234
235void
236lysp_sort_revisions(struct lysp_revision *revs)
237{
238 uint8_t i, r;
239 struct lysp_revision rev;
240
241 for (i = 1, r = 0; revs && i < LY_ARRAY_SIZE(revs); i++) {
Radek Krejcib7db73a2018-10-24 14:18:40 +0200242 if (strcmp(revs[i].date, revs[r].date) > 0) {
Radek Krejci86d106e2018-10-18 09:53:19 +0200243 r = i;
244 }
245 }
246
247 if (r) {
248 /* the newest revision is not on position 0, switch them */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200249 memcpy(&rev, &revs[0], sizeof rev);
250 memcpy(&revs[0], &revs[r], sizeof rev);
251 memcpy(&revs[r], &rev, sizeof rev);
Radek Krejci86d106e2018-10-18 09:53:19 +0200252 }
253}
Radek Krejci151a5b72018-10-19 14:21:44 +0200254
Radek Krejcibbe09a92018-11-08 09:36:54 +0100255static const struct lysp_tpdf *
256lysp_type_match(const char *name, struct lysp_node *node)
257{
Radek Krejci0fb28562018-12-13 15:17:37 +0100258 const struct lysp_tpdf *typedefs;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100259 unsigned int u;
260
Radek Krejci0fb28562018-12-13 15:17:37 +0100261 typedefs = lysp_node_typedefs(node);
262 LY_ARRAY_FOR(typedefs, u) {
263 if (!strcmp(name, typedefs[u].name)) {
264 /* match */
265 return &typedefs[u];
Radek Krejcibbe09a92018-11-08 09:36:54 +0100266 }
267 }
268
269 return NULL;
270}
271
Radek Krejci4f28eda2018-11-12 11:46:16 +0100272static LY_DATA_TYPE
273lysp_type_str2builtin(const char *name, size_t len)
274{
275 if (len >= 4) { /* otherwise it does not match any built-in type */
276 if (name[0] == 'b') {
277 if (name[1] == 'i') {
278 if (len == 6 && !strncmp(&name[2], "nary", 4)) {
279 return LY_TYPE_BINARY;
280 } else if (len == 4 && !strncmp(&name[2], "ts", 2)) {
281 return LY_TYPE_BITS;
282 }
283 } else if (len == 7 && !strncmp(&name[1], "oolean", 6)) {
284 return LY_TYPE_BOOL;
285 }
286 } else if (name[0] == 'd') {
287 if (len == 9 && !strncmp(&name[1], "ecimal64", 8)) {
288 return LY_TYPE_DEC64;
289 }
290 } else if (name[0] == 'e') {
291 if (len == 5 && !strncmp(&name[1], "mpty", 4)) {
292 return LY_TYPE_EMPTY;
293 } else if (len == 11 && !strncmp(&name[1], "numeration", 10)) {
294 return LY_TYPE_ENUM;
295 }
296 } else if (name[0] == 'i') {
297 if (name[1] == 'n') {
298 if (len == 4 && !strncmp(&name[2], "t8", 2)) {
299 return LY_TYPE_INT8;
300 } else if (len == 5) {
301 if (!strncmp(&name[2], "t16", 3)) {
302 return LY_TYPE_INT16;
303 } else if (!strncmp(&name[2], "t32", 3)) {
304 return LY_TYPE_INT32;
305 } else if (!strncmp(&name[2], "t64", 3)) {
306 return LY_TYPE_INT64;
307 }
308 } else if (len == 19 && !strncmp(&name[2], "stance-identifier", 17)) {
309 return LY_TYPE_INST;
310 }
311 } else if (len == 11 && !strncmp(&name[1], "dentityref", 10)) {
312 return LY_TYPE_IDENT;
313 }
314 } else if (name[0] == 'l') {
315 if (len == 7 && !strncmp(&name[1], "eafref", 6)) {
316 return LY_TYPE_LEAFREF;
317 }
318 } else if (name[0] == 's') {
319 if (len == 6 && !strncmp(&name[1], "tring", 5)) {
320 return LY_TYPE_STRING;
321 }
322 } else if (name[0] == 'u') {
323 if (name[1] == 'n') {
324 if (len == 5 && !strncmp(&name[2], "ion", 3)) {
325 return LY_TYPE_UNION;
326 }
327 } else if (name[1] == 'i' && name[2] == 'n' && name[3] == 't') {
328 if (len == 5 && name[4] == '8') {
329 return LY_TYPE_UINT8;
330 } else if (len == 6) {
331 if (!strncmp(&name[4], "16", 2)) {
332 return LY_TYPE_UINT16;
333 } else if (!strncmp(&name[4], "32", 2)) {
334 return LY_TYPE_UINT32;
335 } else if (!strncmp(&name[4], "64", 2)) {
336 return LY_TYPE_UINT64;
337 }
338 }
339 }
340 }
341 }
342
343 return LY_TYPE_UNKNOWN;
344}
345
Radek Krejcibbe09a92018-11-08 09:36:54 +0100346LY_ERR
347lysp_type_find(const char *id, struct lysp_node *start_node, struct lysp_module *start_module,
Radek Krejci4f28eda2018-11-12 11:46:16 +0100348 LY_DATA_TYPE *type, const struct lysp_tpdf **tpdf, struct lysp_node **node, struct lysp_module **module)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100349{
350 const char *str, *name;
351 struct lysp_tpdf *typedefs;
352 unsigned int u, v;
353
354 assert(id);
355 assert(start_module);
356 assert(tpdf);
357 assert(node);
358 assert(module);
359
Radek Krejci4f28eda2018-11-12 11:46:16 +0100360 *node = NULL;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100361 str = strchr(id, ':');
362 if (str) {
363 *module = lysp_module_find_prefix(start_module, id, str - id);
364 name = str + 1;
Radek Krejci4f28eda2018-11-12 11:46:16 +0100365 *type = LY_TYPE_UNKNOWN;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100366 } else {
367 *module = start_module;
368 name = id;
Radek Krejci4f28eda2018-11-12 11:46:16 +0100369
370 /* check for built-in types */
371 *type = lysp_type_str2builtin(name, strlen(name));
372 if (*type) {
373 *tpdf = NULL;
374 return LY_SUCCESS;
375 }
Radek Krejcibbe09a92018-11-08 09:36:54 +0100376 }
377 LY_CHECK_RET(!(*module), LY_ENOTFOUND);
378
379 if (start_node && *module == start_module) {
380 /* search typedefs in parent's nodes */
381 *node = start_node;
382 while (*node) {
383 *tpdf = lysp_type_match(name, *node);
384 if (*tpdf) {
385 /* match */
386 return LY_SUCCESS;
387 }
388 *node = (*node)->parent;
389 }
390 }
391
392 /* search in top-level typedefs */
393 if ((*module)->typedefs) {
394 LY_ARRAY_FOR((*module)->typedefs, u) {
395 if (!strcmp(name, (*module)->typedefs[u].name)) {
396 /* match */
397 *tpdf = &(*module)->typedefs[u];
398 return LY_SUCCESS;
399 }
400 }
401 }
402
403 /* search in submodules' typedefs */
404 LY_ARRAY_FOR((*module)->includes, u) {
405 typedefs = (*module)->includes[u].submodule->typedefs;
Radek Krejci76b3e962018-12-14 17:01:25 +0100406 LY_ARRAY_FOR(typedefs, v) {
407 if (!strcmp(name, typedefs[v].name)) {
408 /* match */
409 *tpdf = &typedefs[v];
410 return LY_SUCCESS;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100411 }
412 }
413 }
414
415 return LY_ENOTFOUND;
416}
417
418/*
419 * @brief Check name of a new type to avoid name collisions.
420 *
421 * @param[in] ctx Parser context, module where the type is being defined is taken from here.
422 * @param[in] node Schema node where the type is being defined, NULL in case of a top-level typedef.
423 * @param[in] tpdf Typedef definition to check.
424 * @param[in,out] tpdfs_global Initialized hash table to store temporary data between calls. When the module's
425 * typedefs are checked, caller is supposed to free the table.
426 * @param[in,out] tpdfs_global Initialized hash table to store temporary data between calls. When the module's
427 * typedefs are checked, caller is supposed to free the table.
428 * @return LY_EEXIST in case of collision, LY_SUCCESS otherwise.
429 */
430static LY_ERR
Radek Krejci0fb28562018-12-13 15:17:37 +0100431lysp_check_typedef(struct ly_parser_ctx *ctx, struct lysp_node *node, const struct lysp_tpdf *tpdf,
Radek Krejcibbe09a92018-11-08 09:36:54 +0100432 struct hash_table *tpdfs_global, struct hash_table *tpdfs_scoped)
433{
434 struct lysp_node *parent;
435 uint32_t hash;
436 size_t name_len;
437 const char *name;
438 unsigned int u;
Radek Krejci0fb28562018-12-13 15:17:37 +0100439 const struct lysp_tpdf *typedefs;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100440
441 assert(ctx);
442 assert(tpdf);
443
444 name = tpdf->name;
445 name_len = strlen(name);
446
Radek Krejci4f28eda2018-11-12 11:46:16 +0100447 if (lysp_type_str2builtin(name, name_len)) {
448 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
449 "Invalid name \"%s\" of typedef - name collision with a built-in type.", name);
450 return LY_EEXIST;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100451 }
452
453 /* check locally scoped typedefs (avoid name shadowing) */
454 if (node) {
Radek Krejci0fb28562018-12-13 15:17:37 +0100455 typedefs = lysp_node_typedefs(node);
456 LY_ARRAY_FOR(typedefs, u) {
457 if (&typedefs[u] == tpdf) {
458 break;
459 }
460 if (!strcmp(name, typedefs[u].name)) {
461 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
462 "Invalid name \"%s\" of typedef - name collision with sibling type.", name);
463 return LY_EEXIST;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100464 }
465 }
466 /* search typedefs in parent's nodes */
467 for (parent = node->parent; parent; parent = node->parent) {
468 if (lysp_type_match(name, parent)) {
469 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
470 "Invalid name \"%s\" of typedef - name collision with another scoped type.", name);
471 return LY_EEXIST;
472 }
473 }
474 }
475
476 /* check collision with the top-level typedefs */
477 hash = dict_hash(name, name_len);
478 if (node) {
479 lyht_insert(tpdfs_scoped, &name, hash, NULL);
480 if (!lyht_find(tpdfs_global, &name, hash, NULL)) {
481 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
482 "Invalid name \"%s\" of typedef - scoped type collide with a top-level type.", name);
483 return LY_EEXIST;
484 }
485 } else {
486 if (lyht_insert(tpdfs_global, &name, hash, NULL)) {
487 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
488 "Invalid name \"%s\" of typedef - name collision with another top-level type.", name);
489 return LY_EEXIST;
490 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100491 /* it is not necessary to test collision with the scoped types - in lysp_check_typedefs, all the
492 * top-level typedefs are inserted into the tables before the scoped typedefs, so the collision
493 * is detected in the first branch few lines above */
Radek Krejcibbe09a92018-11-08 09:36:54 +0100494 }
495
496 return LY_SUCCESS;
497}
498
499static int
500lysp_id_cmp(void *val1, void *val2, int UNUSED(mod), void *UNUSED(cb_data))
501{
502 return !strcmp(val1, val2);
503}
504
505LY_ERR
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100506lysp_check_typedefs(struct ly_parser_ctx *ctx, struct lysp_module *mod)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100507{
508 struct hash_table *ids_global;
509 struct hash_table *ids_scoped;
Radek Krejci0fb28562018-12-13 15:17:37 +0100510 const struct lysp_tpdf *typedefs;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100511 unsigned int i, u;
512 LY_ERR ret = LY_EVALID;
513
514 /* check name collisions - typedefs and groupings */
515 ids_global = lyht_new(8, sizeof(char*), lysp_id_cmp, NULL, 1);
516 ids_scoped = lyht_new(8, sizeof(char*), lysp_id_cmp, NULL, 1);
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100517 LY_ARRAY_FOR(mod->typedefs, i) {
518 if (lysp_check_typedef(ctx, NULL, &mod->typedefs[i], ids_global, ids_scoped)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100519 goto cleanup;
520 }
521 }
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100522 LY_ARRAY_FOR(mod->includes, i) {
523 LY_ARRAY_FOR(mod->includes[i].submodule->typedefs, u) {
524 if (lysp_check_typedef(ctx, NULL, &mod->includes[i].submodule->typedefs[u], ids_global, ids_scoped)) {
Radek Krejci3b1f9292018-11-08 10:58:35 +0100525 goto cleanup;
526 }
527 }
528 }
Radek Krejcibbe09a92018-11-08 09:36:54 +0100529 for (u = 0; u < ctx->tpdfs_nodes.count; ++u) {
Radek Krejci0fb28562018-12-13 15:17:37 +0100530 typedefs = lysp_node_typedefs((struct lysp_node *)ctx->tpdfs_nodes.objs[u]);
531 LY_ARRAY_FOR(typedefs, i) {
532 if (lysp_check_typedef(ctx, (struct lysp_node *)ctx->tpdfs_nodes.objs[u], &typedefs[i], ids_global, ids_scoped)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100533 goto cleanup;
534 }
535 }
536 }
537 ret = LY_SUCCESS;
538cleanup:
539 lyht_free(ids_global);
540 lyht_free(ids_scoped);
541 ly_set_erase(&ctx->tpdfs_nodes, NULL);
542
543 return ret;
544}
545
Radek Krejci9ed7a192018-10-31 16:23:51 +0100546struct lysp_load_module_check_data {
547 const char *name;
548 const char *revision;
549 const char *path;
550 const char* submoduleof;
551};
552
553static LY_ERR
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100554lysp_load_module_check(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data)
Radek Krejci9ed7a192018-10-31 16:23:51 +0100555{
556 struct lysp_load_module_check_data *info = data;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100557 const char *filename, *dot, *rev, *name;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100558 size_t len;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100559 struct lysp_revision *revs;
560
561 name = mod ? mod->mod->name : submod->name;
562 revs = mod ? mod->revs : submod->revs;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100563
564 if (info->name) {
565 /* check name of the parsed model */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100566 if (strcmp(info->name, name)) {
567 LOGERR(ctx, LY_EINVAL, "Unexpected module \"%s\" parsed instead of \"%s\").", name, info->name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100568 return LY_EINVAL;
569 }
570 }
571 if (info->revision) {
572 /* check revision of the parsed model */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100573 if (!revs || strcmp(info->revision, revs[0].date)) {
574 LOGERR(ctx, LY_EINVAL, "Module \"%s\" parsed with the wrong revision (\"%s\" instead \"%s\").", name,
575 revs[0].date, info->revision);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100576 return LY_EINVAL;
577 }
578 }
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100579 if (submod) {
580 assert(info->submoduleof);
581
Radek Krejci9ed7a192018-10-31 16:23:51 +0100582 /* check that the submodule belongs-to our module */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100583 if (strcmp(info->submoduleof, submod->belongsto)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100584 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Included \"%s\" submodule from \"%s\" belongs-to a different module \"%s\".",
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100585 submod->name, info->submoduleof, submod->belongsto);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100586 return LY_EVALID;
587 }
588 /* check circular dependency */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100589 if (submod->parsing) {
590 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (include) for module \"%s\".", submod->name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100591 return LY_EVALID;
592 }
593 }
594 if (info->path) {
595 /* check that name and revision match filename */
596 filename = strrchr(info->path, '/');
597 if (!filename) {
598 filename = info->path;
599 } else {
600 filename++;
601 }
602 /* name */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100603 len = strlen(name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100604 rev = strchr(filename, '@');
605 dot = strrchr(info->path, '.');
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100606 if (strncmp(filename, name, len) ||
Radek Krejci9ed7a192018-10-31 16:23:51 +0100607 ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100608 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100609 }
610 /* revision */
611 if (rev) {
612 len = dot - ++rev;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100613 if (!revs || len != 10 || strncmp(revs[0].date, rev, len)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100614 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100615 revs ? revs[0].date : "none");
Radek Krejci9ed7a192018-10-31 16:23:51 +0100616 }
617 }
618 }
619 return LY_SUCCESS;
620}
621
622LY_ERR
Radek Krejci3b1f9292018-11-08 10:58:35 +0100623lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct ly_parser_ctx *main_ctx,
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100624 void **result)
Radek Krejci9ed7a192018-10-31 16:23:51 +0100625{
626 int fd;
627 char *filepath = NULL;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100628 const char **fp;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100629 LYS_INFORMAT format;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100630 void *mod = NULL;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100631 LY_ERR ret = LY_SUCCESS;
632 struct lysp_load_module_check_data check_data = {0};
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100633 char rpath[PATH_MAX];
Radek Krejci9ed7a192018-10-31 16:23:51 +0100634
635 LY_CHECK_RET(lys_search_localfile(ly_ctx_get_searchdirs(ctx), !(ctx->flags & LY_CTX_DISABLE_SEARCHDIR_CWD), name, revision,
636 &filepath, &format));
637 LY_CHECK_ERR_RET(!filepath, LOGERR(ctx, LY_ENOTFOUND, "Data model \"%s%s%s\" not found in local searchdirs.",
638 name, revision ? "@" : "", revision ? revision : ""), LY_ENOTFOUND);
639
640
641 LOGVRB("Loading schema from \"%s\" file.", filepath);
642
643 /* open the file */
644 fd = open(filepath, O_RDONLY);
645 LY_CHECK_ERR_GOTO(fd < 0, LOGERR(ctx, LY_ESYS, "Unable to open data model file \"%s\" (%s).",
646 filepath, strerror(errno)); ret = LY_ESYS, cleanup);
647
648 check_data.name = name;
649 check_data.revision = revision;
650 check_data.path = filepath;
Radek Krejci3b1f9292018-11-08 10:58:35 +0100651 mod = lys_parse_fd_(ctx, fd, format, implement, main_ctx,
Radek Krejci9ed7a192018-10-31 16:23:51 +0100652 lysp_load_module_check, &check_data);
653 close(fd);
654 LY_CHECK_ERR_GOTO(!mod, ly_errcode(ctx), cleanup);
655
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100656 if (main_ctx) {
657 fp = &((struct lysp_submodule*)mod)->filepath;
658 } else {
659 fp = &((struct lys_module*)mod)->filepath;
660 }
661 if (!(*fp)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100662 if (realpath(filepath, rpath) != NULL) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100663 (*fp) = lydict_insert(ctx, rpath, 0);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100664 } else {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100665 (*fp) = lydict_insert(ctx, filepath, 0);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100666 }
667 }
668
669 *result = mod;
670
671 /* success */
672cleanup:
673 free(filepath);
674 return ret;
675}
676
Radek Krejcid33273d2018-10-25 14:55:52 +0200677LY_ERR
Radek Krejci6d6e4e42018-10-29 13:28:19 +0100678lysp_load_module(struct ly_ctx *ctx, const char *name, const char *revision, int implement, int require_parsed, struct lys_module **mod)
Radek Krejci086c7132018-10-26 15:29:04 +0200679{
Radek Krejci9ed7a192018-10-31 16:23:51 +0100680 const char *module_data = NULL;
Radek Krejci086c7132018-10-26 15:29:04 +0200681 LYS_INFORMAT format = LYS_IN_UNKNOWN;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100682 void (*module_data_free)(void *module_data, void *user_data) = NULL;
683 struct lysp_load_module_check_data check_data = {0};
Radek Krejci086c7132018-10-26 15:29:04 +0200684
685 /* try to get the module from the context */
686 if (revision) {
687 *mod = (struct lys_module*)ly_ctx_get_module(ctx, name, revision);
688 } else {
689 *mod = (struct lys_module*)ly_ctx_get_module_latest(ctx, name);
690 }
691
Radek Krejci6d6e4e42018-10-29 13:28:19 +0100692 if (!(*mod) || (require_parsed && !(*mod)->parsed)) {
693 (*mod) = NULL;
694
Radek Krejci086c7132018-10-26 15:29:04 +0200695 /* check collision with other implemented revision */
696 if (implement && ly_ctx_get_module_implemented(ctx, name)) {
697 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
698 "Module \"%s\" is already present in other implemented revision.", name);
699 return LY_EDENIED;
700 }
701
Radek Krejci9ed7a192018-10-31 16:23:51 +0100702 /* module not present in the context, get the input data and parse it */
Radek Krejci086c7132018-10-26 15:29:04 +0200703 if (!(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
704search_clb:
705 if (ctx->imp_clb) {
706 if (ctx->imp_clb(name, revision, NULL, NULL, ctx->imp_clb_data,
Radek Krejci9ed7a192018-10-31 16:23:51 +0100707 &format, &module_data, &module_data_free) == LY_SUCCESS) {
708 check_data.name = name;
709 check_data.revision = revision;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100710 *mod = lys_parse_mem_module(ctx, module_data, format, implement,
711 lysp_load_module_check, &check_data);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100712 if (module_data_free) {
713 module_data_free((void*)module_data, ctx->imp_clb_data);
714 }
Radek Krejci096235c2019-01-11 11:12:19 +0100715 if (*mod && implement && lys_compile(*mod, 0)) {
716 ly_set_rm(&ctx->list, *mod, NULL);
717 lys_module_free(*mod, NULL);
718 *mod = NULL;
719 }
Radek Krejci086c7132018-10-26 15:29:04 +0200720 }
721 }
722 if (!(*mod) && !(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
723 goto search_file;
724 }
725 } else {
726search_file:
727 if (!(ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
728 /* module was not received from the callback or there is no callback set */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100729 lys_module_localfile(ctx, name, revision, implement, NULL, (void **)mod);
Radek Krejci086c7132018-10-26 15:29:04 +0200730 }
731 if (!(*mod) && (ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
732 goto search_clb;
733 }
734 }
Radek Krejci9ed7a192018-10-31 16:23:51 +0100735
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100736 if ((*mod) && !revision && ((*mod)->latest_revision == 1)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100737 /* update the latest_revision flag - here we have selected the latest available schema,
738 * consider that even the callback provides correct latest revision */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100739 (*mod)->latest_revision = 2;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100740 }
Radek Krejci086c7132018-10-26 15:29:04 +0200741 } else {
742 /* we have module from the current context */
743 if (implement && (ly_ctx_get_module_implemented(ctx, name) != *mod)) {
744 /* check collision with other implemented revision */
745 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
746 "Module \"%s\" is already present in other implemented revision.", name);
747 *mod = NULL;
748 return LY_EDENIED;
749 }
750
751 /* circular check */
Radek Krejcif8f882a2018-10-31 14:51:15 +0100752 if ((*mod)->parsed && (*mod)->parsed->parsing) {
Radek Krejci086c7132018-10-26 15:29:04 +0200753 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (import) for module \"%s\".", name);
754 *mod = NULL;
755 return LY_EVALID;
756 }
757 }
758 if (!(*mod)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100759 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "%s \"%s\" module failed.", implement ? "Loading" : "Importing", name);
Radek Krejci086c7132018-10-26 15:29:04 +0200760 return LY_EVALID;
761 }
762
763 if (implement) {
764 /* mark the module implemented, check for collision was already done */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100765 (*mod)->implemented = 1;
Radek Krejci086c7132018-10-26 15:29:04 +0200766 }
Radek Krejci086c7132018-10-26 15:29:04 +0200767
768 return LY_SUCCESS;
769}
770
771LY_ERR
Radek Krejci3b1f9292018-11-08 10:58:35 +0100772lysp_load_submodule(struct ly_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc)
Radek Krejcid33273d2018-10-25 14:55:52 +0200773{
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100774 struct lysp_submodule *submod;
Radek Krejcid33273d2018-10-25 14:55:52 +0200775 const char *submodule_data = NULL;
776 LYS_INFORMAT format = LYS_IN_UNKNOWN;
777 void (*submodule_data_free)(void *module_data, void *user_data) = NULL;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100778 struct lysp_load_module_check_data check_data = {0};
Radek Krejcid33273d2018-10-25 14:55:52 +0200779
Radek Krejcibbe09a92018-11-08 09:36:54 +0100780 /* submodule not present in the context, get the input data and parse it */
Radek Krejci3b1f9292018-11-08 10:58:35 +0100781 if (!(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcid33273d2018-10-25 14:55:52 +0200782search_clb:
Radek Krejci3b1f9292018-11-08 10:58:35 +0100783 if (ctx->ctx->imp_clb) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100784 if (ctx->ctx->imp_clb(mod->mod->name, NULL, inc->name, inc->rev[0] ? inc->rev : NULL, ctx->ctx->imp_clb_data,
Radek Krejcibbe09a92018-11-08 09:36:54 +0100785 &format, &submodule_data, &submodule_data_free) == LY_SUCCESS) {
786 check_data.name = inc->name;
787 check_data.revision = inc->rev[0] ? inc->rev : NULL;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100788 check_data.submoduleof = mod->mod->name;
789 submod = lys_parse_mem_submodule(ctx->ctx, submodule_data, format, ctx,
790 lysp_load_module_check, &check_data);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100791 if (submodule_data_free) {
Radek Krejci3b1f9292018-11-08 10:58:35 +0100792 submodule_data_free((void*)submodule_data, ctx->ctx->imp_clb_data);
Radek Krejcid33273d2018-10-25 14:55:52 +0200793 }
794 }
Radek Krejcid33273d2018-10-25 14:55:52 +0200795 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100796 if (!submod && !(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100797 goto search_file;
Radek Krejcid33273d2018-10-25 14:55:52 +0200798 }
Radek Krejci2d31ea72018-10-25 15:46:42 +0200799 } else {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100800search_file:
Radek Krejci3b1f9292018-11-08 10:58:35 +0100801 if (!(ctx->ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100802 /* submodule was not received from the callback or there is no callback set */
803 lys_module_localfile(ctx->ctx, inc->name, inc->rev[0] ? inc->rev : NULL, 0, ctx, (void**)&submod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100804 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100805 if (!submod && (ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100806 goto search_clb;
807 }
808 }
809 if (submod) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100810 if (!inc->rev[0] && (submod->latest_revision == 1)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100811 /* update the latest_revision flag - here we have selected the latest available schema,
812 * consider that even the callback provides correct latest revision */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100813 submod->latest_revision = 2;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100814 }
815
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100816 inc->submodule = submod;
Radek Krejcid33273d2018-10-25 14:55:52 +0200817 }
818 if (!inc->submodule) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100819 LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Including \"%s\" submodule into \"%s\" failed.",
820 inc->name, mod->mod->name);
Radek Krejcid33273d2018-10-25 14:55:52 +0200821 return LY_EVALID;
822 }
823
824 return LY_SUCCESS;
825}
826
Radek Krejci01342af2019-01-03 15:18:08 +0100827#define FIND_MODULE(TYPE, MOD) \
Radek Krejcice8c1592018-10-29 15:35:51 +0100828 TYPE *imp; \
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100829 if (!strncmp((MOD)->mod->prefix, prefix, len) && (MOD)->mod->prefix[len] == '\0') { \
Radek Krejcice8c1592018-10-29 15:35:51 +0100830 /* it is the prefix of the module itself */ \
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100831 m = ly_ctx_get_module((MOD)->mod->ctx, (MOD)->mod->name, ((struct lysc_module*)(MOD))->revision); \
Radek Krejcice8c1592018-10-29 15:35:51 +0100832 } \
833 /* search in imports */ \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100834 if (!m) { \
835 LY_ARRAY_FOR((MOD)->imports, TYPE, imp) { \
Radek Krejci01342af2019-01-03 15:18:08 +0100836 if (!strncmp(imp->prefix, prefix, len) && imp->prefix[len] == '\0') { \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100837 m = imp->module; \
838 break; \
839 } \
Radek Krejcice8c1592018-10-29 15:35:51 +0100840 } \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100841 }
Radek Krejcice8c1592018-10-29 15:35:51 +0100842
Radek Krejcibbe09a92018-11-08 09:36:54 +0100843struct lysc_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100844lysc_module_find_prefix(const struct lysc_module *mod, const char *prefix, size_t len)
Radek Krejci151a5b72018-10-19 14:21:44 +0200845{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100846 const struct lys_module *m = NULL;
847
Radek Krejci01342af2019-01-03 15:18:08 +0100848 FIND_MODULE(struct lysc_import, mod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100849 return m ? m->compiled : NULL;
Radek Krejcice8c1592018-10-29 15:35:51 +0100850}
Radek Krejci151a5b72018-10-19 14:21:44 +0200851
Radek Krejcibbe09a92018-11-08 09:36:54 +0100852struct lysp_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100853lysp_module_find_prefix(const struct lysp_module *mod, const char *prefix, size_t len)
Radek Krejcice8c1592018-10-29 15:35:51 +0100854{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100855 const struct lys_module *m = NULL;
856
Radek Krejci01342af2019-01-03 15:18:08 +0100857 FIND_MODULE(struct lysp_import, mod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100858 return m ? m->parsed : NULL;
Radek Krejcice8c1592018-10-29 15:35:51 +0100859}
Radek Krejci151a5b72018-10-19 14:21:44 +0200860
Radek Krejcice8c1592018-10-29 15:35:51 +0100861struct lys_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100862lys_module_find_prefix(const struct lys_module *mod, const char *prefix, size_t len)
Radek Krejcice8c1592018-10-29 15:35:51 +0100863{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100864 const struct lys_module *m = NULL;
865
Radek Krejcice8c1592018-10-29 15:35:51 +0100866 if (mod->compiled) {
Radek Krejci01342af2019-01-03 15:18:08 +0100867 FIND_MODULE(struct lysc_import, mod->compiled);
Radek Krejcice8c1592018-10-29 15:35:51 +0100868 } else {
Radek Krejci01342af2019-01-03 15:18:08 +0100869 FIND_MODULE(struct lysp_import, mod->parsed);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100870 }
871 return (struct lys_module*)m;
872}
873
Radek Krejcia3045382018-11-22 14:30:31 +0100874const char *
875lys_nodetype2str(uint16_t nodetype)
876{
877 switch(nodetype) {
878 case LYS_CONTAINER:
879 return "container";
880 case LYS_CHOICE:
881 return "choice";
882 case LYS_LEAF:
883 return "leaf";
884 case LYS_LEAFLIST:
885 return "leaf-list";
886 case LYS_LIST:
887 return "list";
888 case LYS_ANYXML:
889 return "anyxml";
890 case LYS_ANYDATA:
891 return "anydata";
892 default:
893 return "unknown";
894 }
895}
896
Radek Krejci056d0a82018-12-06 16:57:25 +0100897API const struct lysp_tpdf *
898lysp_node_typedefs(const struct lysp_node *node)
899{
Radek Krejci0fb28562018-12-13 15:17:37 +0100900 switch (node->nodetype) {
901 case LYS_CONTAINER:
902 return ((struct lysp_node_container*)node)->typedefs;
903 case LYS_LIST:
904 return ((struct lysp_node_list*)node)->typedefs;
905 case LYS_GROUPING:
906 return ((struct lysp_grp*)node)->typedefs;
907 case LYS_ACTION:
908 return ((struct lysp_action*)node)->typedefs;
909 case LYS_INOUT:
910 return ((struct lysp_action_inout*)node)->typedefs;
911 case LYS_NOTIF:
912 return ((struct lysp_notif*)node)->typedefs;
913 default:
Radek Krejci056d0a82018-12-06 16:57:25 +0100914 return NULL;
915 }
916}
917
Radek Krejci53ea6152018-12-13 15:21:15 +0100918API const struct lysp_grp *
919lysp_node_groupings(const struct lysp_node *node)
920{
921 switch (node->nodetype) {
922 case LYS_CONTAINER:
923 return ((struct lysp_node_container*)node)->groupings;
924 case LYS_LIST:
925 return ((struct lysp_node_list*)node)->groupings;
926 case LYS_GROUPING:
927 return ((struct lysp_grp*)node)->groupings;
928 case LYS_ACTION:
929 return ((struct lysp_action*)node)->groupings;
930 case LYS_INOUT:
931 return ((struct lysp_action_inout*)node)->groupings;
932 case LYS_NOTIF:
933 return ((struct lysp_notif*)node)->groupings;
934 default:
935 return NULL;
936 }
937}
938
Radek Krejcibbe09a92018-11-08 09:36:54 +0100939struct lysp_action **
Radek Krejci056d0a82018-12-06 16:57:25 +0100940lysp_node_actions_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100941{
942 assert(node);
943 switch (node->nodetype) {
944 case LYS_CONTAINER:
945 return &((struct lysp_node_container*)node)->actions;
946 case LYS_LIST:
947 return &((struct lysp_node_list*)node)->actions;
948 case LYS_GROUPING:
949 return &((struct lysp_grp*)node)->actions;
950 case LYS_AUGMENT:
951 return &((struct lysp_augment*)node)->actions;
952 default:
953 return NULL;
954 }
955}
956
Radek Krejci056d0a82018-12-06 16:57:25 +0100957API const struct lysp_action *
958lysp_node_actions(const struct lysp_node *node)
959{
960 struct lysp_action **actions;
961 actions = lysp_node_actions_p((struct lysp_node*)node);
962 if (actions) {
963 return *actions;
964 } else {
965 return NULL;
966 }
967}
968
Radek Krejcibbe09a92018-11-08 09:36:54 +0100969struct lysp_notif **
Radek Krejci056d0a82018-12-06 16:57:25 +0100970lysp_node_notifs_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100971{
972 assert(node);
973 switch (node->nodetype) {
974 case LYS_CONTAINER:
975 return &((struct lysp_node_container*)node)->notifs;
976 case LYS_LIST:
977 return &((struct lysp_node_list*)node)->notifs;
978 case LYS_GROUPING:
979 return &((struct lysp_grp*)node)->notifs;
980 case LYS_AUGMENT:
981 return &((struct lysp_augment*)node)->notifs;
982 default:
983 return NULL;
984 }
985}
986
Radek Krejci056d0a82018-12-06 16:57:25 +0100987API const struct lysp_notif *
988lysp_node_notifs(const struct lysp_node *node)
989{
990 struct lysp_notif **notifs;
991 notifs = lysp_node_notifs_p((struct lysp_node*)node);
992 if (notifs) {
993 return *notifs;
994 } else {
995 return NULL;
996 }
997}
998
Radek Krejcibbe09a92018-11-08 09:36:54 +0100999struct lysp_node **
Radek Krejci056d0a82018-12-06 16:57:25 +01001000lysp_node_children_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001001{
1002 assert(node);
1003 switch (node->nodetype) {
1004 case LYS_CONTAINER:
1005 return &((struct lysp_node_container*)node)->child;
1006 case LYS_CHOICE:
1007 return &((struct lysp_node_choice*)node)->child;
1008 case LYS_LIST:
1009 return &((struct lysp_node_list*)node)->child;
1010 case LYS_CASE:
1011 return &((struct lysp_node_case*)node)->child;
1012 case LYS_GROUPING:
1013 return &((struct lysp_grp*)node)->data;
1014 case LYS_AUGMENT:
1015 return &((struct lysp_augment*)node)->child;
1016 case LYS_INOUT:
1017 return &((struct lysp_action_inout*)node)->data;
1018 case LYS_NOTIF:
1019 return &((struct lysp_notif*)node)->data;
1020 default:
1021 return NULL;
1022 }
1023}
1024
Radek Krejci056d0a82018-12-06 16:57:25 +01001025API const struct lysp_node *
1026lysp_node_children(const struct lysp_node *node)
1027{
1028 struct lysp_node **children;
1029 children = lysp_node_children_p((struct lysp_node*)node);
1030 if (children) {
1031 return *children;
1032 } else {
1033 return NULL;
1034 }
1035}
1036
1037struct lysc_action **
1038lysc_node_actions_p(struct lysc_node *node)
1039{
1040 assert(node);
1041 switch (node->nodetype) {
1042 case LYS_CONTAINER:
1043 return &((struct lysc_node_container*)node)->actions;
1044 case LYS_LIST:
1045 return &((struct lysc_node_list*)node)->actions;
1046 default:
1047 return NULL;
1048 }
1049}
1050
1051API const struct lysc_action *
1052lysc_node_actions(const struct lysc_node *node)
1053{
1054 struct lysc_action **actions;
1055 actions = lysc_node_actions_p((struct lysc_node*)node);
1056 if (actions) {
1057 return *actions;
1058 } else {
1059 return NULL;
1060 }
1061}
1062
1063struct lysc_notif **
1064lysc_node_notifs_p(struct lysc_node *node)
1065{
1066 assert(node);
1067 switch (node->nodetype) {
1068 case LYS_CONTAINER:
1069 return &((struct lysc_node_container*)node)->notifs;
1070 case LYS_LIST:
1071 return &((struct lysc_node_list*)node)->notifs;
1072 default:
1073 return NULL;
1074 }
1075}
1076
1077API const struct lysc_notif *
1078lysc_node_notifs(const struct lysc_node *node)
1079{
1080 struct lysc_notif **notifs;
1081 notifs = lysc_node_notifs_p((struct lysc_node*)node);
1082 if (notifs) {
1083 return *notifs;
1084 } else {
1085 return NULL;
1086 }
1087}
1088
Radek Krejcibbe09a92018-11-08 09:36:54 +01001089struct lysc_node **
Radek Krejci056d0a82018-12-06 16:57:25 +01001090lysc_node_children_p(const struct lysc_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001091{
1092 assert(node);
1093 switch (node->nodetype) {
1094 case LYS_CONTAINER:
1095 return &((struct lysc_node_container*)node)->child;
1096 case LYS_CHOICE:
Radek Krejcia3045382018-11-22 14:30:31 +01001097 if (((struct lysc_node_choice*)node)->cases) {
1098 return &((struct lysc_node_choice*)node)->cases[0].child;
1099 } else {
1100 return NULL;
1101 }
Radek Krejci01342af2019-01-03 15:18:08 +01001102 case LYS_CASE:
1103 return &((struct lysc_node_case*)node)->child;
Radek Krejcibbe09a92018-11-08 09:36:54 +01001104 case LYS_LIST:
1105 return &((struct lysc_node_list*)node)->child;
Radek Krejcibbe09a92018-11-08 09:36:54 +01001106/* TODO
1107 case LYS_INOUT:
1108 return &((struct lysc_action_inout*)node)->child;
1109 case LYS_NOTIF:
1110 return &((struct lysc_notif*)node)->child;
1111*/
1112 default:
1113 return NULL;
1114 }
1115}
1116
Radek Krejci056d0a82018-12-06 16:57:25 +01001117API const struct lysc_node *
1118lysc_node_children(const struct lysc_node *node)
Radek Krejcia3045382018-11-22 14:30:31 +01001119{
Radek Krejci056d0a82018-12-06 16:57:25 +01001120 struct lysc_node **children;
1121 children = lysc_node_children_p((struct lysc_node*)node);
1122 if (children) {
1123 return *children;
1124 } else {
Radek Krejcia3045382018-11-22 14:30:31 +01001125 return NULL;
1126 }
1127}
1128
Radek Krejci96a0bfd2018-11-22 15:25:06 +01001129struct lys_module *
1130lysp_find_module(struct ly_ctx *ctx, const struct lysp_module *mod)
1131{
1132 unsigned int u;
1133
1134 for (u = 0; u < ctx->list.count; ++u) {
1135 if (((struct lys_module*)ctx->list.objs[u])->parsed == mod) {
1136 return ((struct lys_module*)ctx->list.objs[u]);
1137 }
1138 }
1139 return NULL;
1140}
1141