blob: 20a06dcd1d2291d7aca4e318ddccf0a8303bd32b [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 Krejci0af46292019-01-11 16:02:31 +0100684 struct lys_module *m;
Radek Krejci086c7132018-10-26 15:29:04 +0200685
Radek Krejci0af46292019-01-11 16:02:31 +0100686 assert(mod);
687
688 if (!*mod) {
689 /* try to get the module from the context */
690 if (revision) {
691 *mod = (struct lys_module*)ly_ctx_get_module(ctx, name, revision);
692 } else {
693 *mod = (struct lys_module*)ly_ctx_get_module_latest(ctx, name);
694 }
Radek Krejci086c7132018-10-26 15:29:04 +0200695 }
696
Radek Krejci6d6e4e42018-10-29 13:28:19 +0100697 if (!(*mod) || (require_parsed && !(*mod)->parsed)) {
698 (*mod) = NULL;
699
Radek Krejci086c7132018-10-26 15:29:04 +0200700 /* check collision with other implemented revision */
701 if (implement && ly_ctx_get_module_implemented(ctx, name)) {
702 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
703 "Module \"%s\" is already present in other implemented revision.", name);
704 return LY_EDENIED;
705 }
706
Radek Krejci9ed7a192018-10-31 16:23:51 +0100707 /* module not present in the context, get the input data and parse it */
Radek Krejci086c7132018-10-26 15:29:04 +0200708 if (!(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
709search_clb:
710 if (ctx->imp_clb) {
711 if (ctx->imp_clb(name, revision, NULL, NULL, ctx->imp_clb_data,
Radek Krejci9ed7a192018-10-31 16:23:51 +0100712 &format, &module_data, &module_data_free) == LY_SUCCESS) {
713 check_data.name = name;
714 check_data.revision = revision;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100715 *mod = lys_parse_mem_module(ctx, module_data, format, implement,
716 lysp_load_module_check, &check_data);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100717 if (module_data_free) {
718 module_data_free((void*)module_data, ctx->imp_clb_data);
719 }
Radek Krejci096235c2019-01-11 11:12:19 +0100720 if (*mod && implement && lys_compile(*mod, 0)) {
721 ly_set_rm(&ctx->list, *mod, NULL);
722 lys_module_free(*mod, NULL);
723 *mod = NULL;
724 }
Radek Krejci086c7132018-10-26 15:29:04 +0200725 }
726 }
727 if (!(*mod) && !(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
728 goto search_file;
729 }
730 } else {
731search_file:
732 if (!(ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
733 /* module was not received from the callback or there is no callback set */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100734 lys_module_localfile(ctx, name, revision, implement, NULL, (void **)mod);
Radek Krejci086c7132018-10-26 15:29:04 +0200735 }
736 if (!(*mod) && (ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
737 goto search_clb;
738 }
739 }
Radek Krejci9ed7a192018-10-31 16:23:51 +0100740
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100741 if ((*mod) && !revision && ((*mod)->latest_revision == 1)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100742 /* update the latest_revision flag - here we have selected the latest available schema,
743 * consider that even the callback provides correct latest revision */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100744 (*mod)->latest_revision = 2;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100745 }
Radek Krejci086c7132018-10-26 15:29:04 +0200746 } else {
747 /* we have module from the current context */
Radek Krejci0af46292019-01-11 16:02:31 +0100748 if (implement) {
749 m = ly_ctx_get_module_implemented(ctx, name);
750 if (m && m != *mod) {
751 /* check collision with other implemented revision */
752 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
753 "Module \"%s\" is already present in other implemented revision.", name);
754 *mod = NULL;
755 return LY_EDENIED;
756 }
Radek Krejci086c7132018-10-26 15:29:04 +0200757 }
758
759 /* circular check */
Radek Krejcif8f882a2018-10-31 14:51:15 +0100760 if ((*mod)->parsed && (*mod)->parsed->parsing) {
Radek Krejci086c7132018-10-26 15:29:04 +0200761 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (import) for module \"%s\".", name);
762 *mod = NULL;
763 return LY_EVALID;
764 }
765 }
766 if (!(*mod)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100767 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "%s \"%s\" module failed.", implement ? "Loading" : "Importing", name);
Radek Krejci086c7132018-10-26 15:29:04 +0200768 return LY_EVALID;
769 }
770
771 if (implement) {
772 /* mark the module implemented, check for collision was already done */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100773 (*mod)->implemented = 1;
Radek Krejci086c7132018-10-26 15:29:04 +0200774 }
Radek Krejci086c7132018-10-26 15:29:04 +0200775
776 return LY_SUCCESS;
777}
778
779LY_ERR
Radek Krejci3b1f9292018-11-08 10:58:35 +0100780lysp_load_submodule(struct ly_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc)
Radek Krejcid33273d2018-10-25 14:55:52 +0200781{
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100782 struct lysp_submodule *submod;
Radek Krejcid33273d2018-10-25 14:55:52 +0200783 const char *submodule_data = NULL;
784 LYS_INFORMAT format = LYS_IN_UNKNOWN;
785 void (*submodule_data_free)(void *module_data, void *user_data) = NULL;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100786 struct lysp_load_module_check_data check_data = {0};
Radek Krejcid33273d2018-10-25 14:55:52 +0200787
Radek Krejcibbe09a92018-11-08 09:36:54 +0100788 /* submodule not present in the context, get the input data and parse it */
Radek Krejci3b1f9292018-11-08 10:58:35 +0100789 if (!(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcid33273d2018-10-25 14:55:52 +0200790search_clb:
Radek Krejci3b1f9292018-11-08 10:58:35 +0100791 if (ctx->ctx->imp_clb) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100792 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 +0100793 &format, &submodule_data, &submodule_data_free) == LY_SUCCESS) {
794 check_data.name = inc->name;
795 check_data.revision = inc->rev[0] ? inc->rev : NULL;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100796 check_data.submoduleof = mod->mod->name;
797 submod = lys_parse_mem_submodule(ctx->ctx, submodule_data, format, ctx,
798 lysp_load_module_check, &check_data);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100799 if (submodule_data_free) {
Radek Krejci3b1f9292018-11-08 10:58:35 +0100800 submodule_data_free((void*)submodule_data, ctx->ctx->imp_clb_data);
Radek Krejcid33273d2018-10-25 14:55:52 +0200801 }
802 }
Radek Krejcid33273d2018-10-25 14:55:52 +0200803 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100804 if (!submod && !(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100805 goto search_file;
Radek Krejcid33273d2018-10-25 14:55:52 +0200806 }
Radek Krejci2d31ea72018-10-25 15:46:42 +0200807 } else {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100808search_file:
Radek Krejci3b1f9292018-11-08 10:58:35 +0100809 if (!(ctx->ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100810 /* submodule was not received from the callback or there is no callback set */
811 lys_module_localfile(ctx->ctx, inc->name, inc->rev[0] ? inc->rev : NULL, 0, ctx, (void**)&submod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100812 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100813 if (!submod && (ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100814 goto search_clb;
815 }
816 }
817 if (submod) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100818 if (!inc->rev[0] && (submod->latest_revision == 1)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100819 /* update the latest_revision flag - here we have selected the latest available schema,
820 * consider that even the callback provides correct latest revision */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100821 submod->latest_revision = 2;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100822 }
823
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100824 inc->submodule = submod;
Radek Krejcid33273d2018-10-25 14:55:52 +0200825 }
826 if (!inc->submodule) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100827 LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Including \"%s\" submodule into \"%s\" failed.",
828 inc->name, mod->mod->name);
Radek Krejcid33273d2018-10-25 14:55:52 +0200829 return LY_EVALID;
830 }
831
832 return LY_SUCCESS;
833}
834
Radek Krejci01342af2019-01-03 15:18:08 +0100835#define FIND_MODULE(TYPE, MOD) \
Radek Krejcice8c1592018-10-29 15:35:51 +0100836 TYPE *imp; \
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100837 if (!strncmp((MOD)->mod->prefix, prefix, len) && (MOD)->mod->prefix[len] == '\0') { \
Radek Krejcice8c1592018-10-29 15:35:51 +0100838 /* it is the prefix of the module itself */ \
Radek Krejci0af46292019-01-11 16:02:31 +0100839 m = ly_ctx_get_module((MOD)->mod->ctx, (MOD)->mod->name, (MOD)->mod->revision); \
Radek Krejcice8c1592018-10-29 15:35:51 +0100840 } \
841 /* search in imports */ \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100842 if (!m) { \
843 LY_ARRAY_FOR((MOD)->imports, TYPE, imp) { \
Radek Krejci01342af2019-01-03 15:18:08 +0100844 if (!strncmp(imp->prefix, prefix, len) && imp->prefix[len] == '\0') { \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100845 m = imp->module; \
846 break; \
847 } \
Radek Krejcice8c1592018-10-29 15:35:51 +0100848 } \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100849 }
Radek Krejcice8c1592018-10-29 15:35:51 +0100850
Radek Krejcibbe09a92018-11-08 09:36:54 +0100851struct lysc_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100852lysc_module_find_prefix(const struct lysc_module *mod, const char *prefix, size_t len)
Radek Krejci151a5b72018-10-19 14:21:44 +0200853{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100854 const struct lys_module *m = NULL;
855
Radek Krejci01342af2019-01-03 15:18:08 +0100856 FIND_MODULE(struct lysc_import, mod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100857 return m ? m->compiled : NULL;
Radek Krejcice8c1592018-10-29 15:35:51 +0100858}
Radek Krejci151a5b72018-10-19 14:21:44 +0200859
Radek Krejcibbe09a92018-11-08 09:36:54 +0100860struct lysp_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100861lysp_module_find_prefix(const struct lysp_module *mod, const char *prefix, size_t len)
Radek Krejcice8c1592018-10-29 15:35:51 +0100862{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100863 const struct lys_module *m = NULL;
864
Radek Krejci01342af2019-01-03 15:18:08 +0100865 FIND_MODULE(struct lysp_import, mod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100866 return m ? m->parsed : NULL;
Radek Krejcice8c1592018-10-29 15:35:51 +0100867}
Radek Krejci151a5b72018-10-19 14:21:44 +0200868
Radek Krejcice8c1592018-10-29 15:35:51 +0100869struct lys_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100870lys_module_find_prefix(const struct lys_module *mod, const char *prefix, size_t len)
Radek Krejcice8c1592018-10-29 15:35:51 +0100871{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100872 const struct lys_module *m = NULL;
873
Radek Krejcice8c1592018-10-29 15:35:51 +0100874 if (mod->compiled) {
Radek Krejci01342af2019-01-03 15:18:08 +0100875 FIND_MODULE(struct lysc_import, mod->compiled);
Radek Krejcice8c1592018-10-29 15:35:51 +0100876 } else {
Radek Krejci01342af2019-01-03 15:18:08 +0100877 FIND_MODULE(struct lysp_import, mod->parsed);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100878 }
879 return (struct lys_module*)m;
880}
881
Radek Krejcia3045382018-11-22 14:30:31 +0100882const char *
883lys_nodetype2str(uint16_t nodetype)
884{
885 switch(nodetype) {
886 case LYS_CONTAINER:
887 return "container";
888 case LYS_CHOICE:
889 return "choice";
890 case LYS_LEAF:
891 return "leaf";
892 case LYS_LEAFLIST:
893 return "leaf-list";
894 case LYS_LIST:
895 return "list";
896 case LYS_ANYXML:
897 return "anyxml";
898 case LYS_ANYDATA:
899 return "anydata";
900 default:
901 return "unknown";
902 }
903}
904
Radek Krejci056d0a82018-12-06 16:57:25 +0100905API const struct lysp_tpdf *
906lysp_node_typedefs(const struct lysp_node *node)
907{
Radek Krejci0fb28562018-12-13 15:17:37 +0100908 switch (node->nodetype) {
909 case LYS_CONTAINER:
910 return ((struct lysp_node_container*)node)->typedefs;
911 case LYS_LIST:
912 return ((struct lysp_node_list*)node)->typedefs;
913 case LYS_GROUPING:
914 return ((struct lysp_grp*)node)->typedefs;
915 case LYS_ACTION:
916 return ((struct lysp_action*)node)->typedefs;
917 case LYS_INOUT:
918 return ((struct lysp_action_inout*)node)->typedefs;
919 case LYS_NOTIF:
920 return ((struct lysp_notif*)node)->typedefs;
921 default:
Radek Krejci056d0a82018-12-06 16:57:25 +0100922 return NULL;
923 }
924}
925
Radek Krejci53ea6152018-12-13 15:21:15 +0100926API const struct lysp_grp *
927lysp_node_groupings(const struct lysp_node *node)
928{
929 switch (node->nodetype) {
930 case LYS_CONTAINER:
931 return ((struct lysp_node_container*)node)->groupings;
932 case LYS_LIST:
933 return ((struct lysp_node_list*)node)->groupings;
934 case LYS_GROUPING:
935 return ((struct lysp_grp*)node)->groupings;
936 case LYS_ACTION:
937 return ((struct lysp_action*)node)->groupings;
938 case LYS_INOUT:
939 return ((struct lysp_action_inout*)node)->groupings;
940 case LYS_NOTIF:
941 return ((struct lysp_notif*)node)->groupings;
942 default:
943 return NULL;
944 }
945}
946
Radek Krejcibbe09a92018-11-08 09:36:54 +0100947struct lysp_action **
Radek Krejci056d0a82018-12-06 16:57:25 +0100948lysp_node_actions_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100949{
950 assert(node);
951 switch (node->nodetype) {
952 case LYS_CONTAINER:
953 return &((struct lysp_node_container*)node)->actions;
954 case LYS_LIST:
955 return &((struct lysp_node_list*)node)->actions;
956 case LYS_GROUPING:
957 return &((struct lysp_grp*)node)->actions;
958 case LYS_AUGMENT:
959 return &((struct lysp_augment*)node)->actions;
960 default:
961 return NULL;
962 }
963}
964
Radek Krejci056d0a82018-12-06 16:57:25 +0100965API const struct lysp_action *
966lysp_node_actions(const struct lysp_node *node)
967{
968 struct lysp_action **actions;
969 actions = lysp_node_actions_p((struct lysp_node*)node);
970 if (actions) {
971 return *actions;
972 } else {
973 return NULL;
974 }
975}
976
Radek Krejcibbe09a92018-11-08 09:36:54 +0100977struct lysp_notif **
Radek Krejci056d0a82018-12-06 16:57:25 +0100978lysp_node_notifs_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100979{
980 assert(node);
981 switch (node->nodetype) {
982 case LYS_CONTAINER:
983 return &((struct lysp_node_container*)node)->notifs;
984 case LYS_LIST:
985 return &((struct lysp_node_list*)node)->notifs;
986 case LYS_GROUPING:
987 return &((struct lysp_grp*)node)->notifs;
988 case LYS_AUGMENT:
989 return &((struct lysp_augment*)node)->notifs;
990 default:
991 return NULL;
992 }
993}
994
Radek Krejci056d0a82018-12-06 16:57:25 +0100995API const struct lysp_notif *
996lysp_node_notifs(const struct lysp_node *node)
997{
998 struct lysp_notif **notifs;
999 notifs = lysp_node_notifs_p((struct lysp_node*)node);
1000 if (notifs) {
1001 return *notifs;
1002 } else {
1003 return NULL;
1004 }
1005}
1006
Radek Krejcibbe09a92018-11-08 09:36:54 +01001007struct lysp_node **
Radek Krejci056d0a82018-12-06 16:57:25 +01001008lysp_node_children_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001009{
1010 assert(node);
1011 switch (node->nodetype) {
1012 case LYS_CONTAINER:
1013 return &((struct lysp_node_container*)node)->child;
1014 case LYS_CHOICE:
1015 return &((struct lysp_node_choice*)node)->child;
1016 case LYS_LIST:
1017 return &((struct lysp_node_list*)node)->child;
1018 case LYS_CASE:
1019 return &((struct lysp_node_case*)node)->child;
1020 case LYS_GROUPING:
1021 return &((struct lysp_grp*)node)->data;
1022 case LYS_AUGMENT:
1023 return &((struct lysp_augment*)node)->child;
1024 case LYS_INOUT:
1025 return &((struct lysp_action_inout*)node)->data;
1026 case LYS_NOTIF:
1027 return &((struct lysp_notif*)node)->data;
1028 default:
1029 return NULL;
1030 }
1031}
1032
Radek Krejci056d0a82018-12-06 16:57:25 +01001033API const struct lysp_node *
1034lysp_node_children(const struct lysp_node *node)
1035{
1036 struct lysp_node **children;
1037 children = lysp_node_children_p((struct lysp_node*)node);
1038 if (children) {
1039 return *children;
1040 } else {
1041 return NULL;
1042 }
1043}
1044
1045struct lysc_action **
1046lysc_node_actions_p(struct lysc_node *node)
1047{
1048 assert(node);
1049 switch (node->nodetype) {
1050 case LYS_CONTAINER:
1051 return &((struct lysc_node_container*)node)->actions;
1052 case LYS_LIST:
1053 return &((struct lysc_node_list*)node)->actions;
1054 default:
1055 return NULL;
1056 }
1057}
1058
1059API const struct lysc_action *
1060lysc_node_actions(const struct lysc_node *node)
1061{
1062 struct lysc_action **actions;
1063 actions = lysc_node_actions_p((struct lysc_node*)node);
1064 if (actions) {
1065 return *actions;
1066 } else {
1067 return NULL;
1068 }
1069}
1070
1071struct lysc_notif **
1072lysc_node_notifs_p(struct lysc_node *node)
1073{
1074 assert(node);
1075 switch (node->nodetype) {
1076 case LYS_CONTAINER:
1077 return &((struct lysc_node_container*)node)->notifs;
1078 case LYS_LIST:
1079 return &((struct lysc_node_list*)node)->notifs;
1080 default:
1081 return NULL;
1082 }
1083}
1084
1085API const struct lysc_notif *
1086lysc_node_notifs(const struct lysc_node *node)
1087{
1088 struct lysc_notif **notifs;
1089 notifs = lysc_node_notifs_p((struct lysc_node*)node);
1090 if (notifs) {
1091 return *notifs;
1092 } else {
1093 return NULL;
1094 }
1095}
1096
Radek Krejcibbe09a92018-11-08 09:36:54 +01001097struct lysc_node **
Radek Krejci056d0a82018-12-06 16:57:25 +01001098lysc_node_children_p(const struct lysc_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001099{
1100 assert(node);
1101 switch (node->nodetype) {
1102 case LYS_CONTAINER:
1103 return &((struct lysc_node_container*)node)->child;
1104 case LYS_CHOICE:
Radek Krejcia3045382018-11-22 14:30:31 +01001105 if (((struct lysc_node_choice*)node)->cases) {
1106 return &((struct lysc_node_choice*)node)->cases[0].child;
1107 } else {
1108 return NULL;
1109 }
Radek Krejci01342af2019-01-03 15:18:08 +01001110 case LYS_CASE:
1111 return &((struct lysc_node_case*)node)->child;
Radek Krejcibbe09a92018-11-08 09:36:54 +01001112 case LYS_LIST:
1113 return &((struct lysc_node_list*)node)->child;
Radek Krejcibbe09a92018-11-08 09:36:54 +01001114/* TODO
1115 case LYS_INOUT:
1116 return &((struct lysc_action_inout*)node)->child;
1117 case LYS_NOTIF:
1118 return &((struct lysc_notif*)node)->child;
1119*/
1120 default:
1121 return NULL;
1122 }
1123}
1124
Radek Krejci056d0a82018-12-06 16:57:25 +01001125API const struct lysc_node *
1126lysc_node_children(const struct lysc_node *node)
Radek Krejcia3045382018-11-22 14:30:31 +01001127{
Radek Krejci056d0a82018-12-06 16:57:25 +01001128 struct lysc_node **children;
1129 children = lysc_node_children_p((struct lysc_node*)node);
1130 if (children) {
1131 return *children;
1132 } else {
Radek Krejcia3045382018-11-22 14:30:31 +01001133 return NULL;
1134 }
1135}
1136
Radek Krejci96a0bfd2018-11-22 15:25:06 +01001137struct lys_module *
1138lysp_find_module(struct ly_ctx *ctx, const struct lysp_module *mod)
1139{
1140 unsigned int u;
1141
1142 for (u = 0; u < ctx->list.count; ++u) {
1143 if (((struct lys_module*)ctx->list.objs[u])->parsed == mod) {
1144 return ((struct lys_module*)ctx->list.objs[u]);
1145 }
1146 }
1147 return NULL;
1148}
1149