blob: 0295995b56a1f26682f0dc4e2cfaa0d034db9203 [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 Krejci95710c92019-02-11 15:49:55 +010088lys_resolve_schema_nodeid(struct lysc_ctx *ctx, const char *nodeid, size_t nodeid_len, const struct lysc_node *context_node,
Radek Krejci7af64242019-02-18 13:07:53 +010089 const struct lys_module *context_module, int nodetype, int implement, const struct lysc_node **target)
Radek Krejci9bb94eb2018-12-04 16:48:35 +010090{
91 LY_ERR ret = LY_EVALID;
92 const char *name, *prefix, *id;
Radek Krejci9bb94eb2018-12-04 16:48:35 +010093 size_t name_len, prefix_len;
Radek Krejci7af64242019-02-18 13:07:53 +010094 const struct lys_module *mod;
Radek Krejci95710c92019-02-11 15:49:55 +010095 const char *nodeid_type;
Radek Krejci9bb94eb2018-12-04 16:48:35 +010096
97 assert(nodeid);
Radek Krejci9bb94eb2018-12-04 16:48:35 +010098 assert(target);
99 *target = NULL;
100
101 id = nodeid;
Radek Krejci95710c92019-02-11 15:49:55 +0100102
103 if (context_node) {
104 /* descendant-schema-nodeid */
105 nodeid_type = "descendant";
Radek Krejci3641f562019-02-13 15:38:40 +0100106
107 if (*id == '/') {
108 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
109 "Invalid descendant-schema-nodeid value \"%.*s\" - absolute-schema-nodeid used.",
110 nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
111 return LY_EVALID;
112 }
Radek Krejci95710c92019-02-11 15:49:55 +0100113 } else {
114 /* absolute-schema-nodeid */
115 nodeid_type = "absolute";
Radek Krejci95710c92019-02-11 15:49:55 +0100116
117 if (*id != '/') {
118 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
119 "Invalid absolute-schema-nodeid value \"%.*s\" - missing starting \"/\".",
Radek Krejci3641f562019-02-13 15:38:40 +0100120 nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
Radek Krejci95710c92019-02-11 15:49:55 +0100121 return LY_EVALID;
122 }
123 ++id;
124 }
125
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100126 while (*id && (ret = lys_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len)) == LY_SUCCESS) {
127 if (prefix) {
Radek Krejci95710c92019-02-11 15:49:55 +0100128 mod = lys_module_find_prefix(context_module, prefix, prefix_len);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100129 if (!mod) {
130 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Radek Krejci95710c92019-02-11 15:49:55 +0100131 "Invalid %s-schema-nodeid value \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
132 nodeid_type, id - nodeid, nodeid, prefix_len, prefix, context_module->name);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100133 return LY_ENOTFOUND;
134 }
135 } else {
Radek Krejci95710c92019-02-11 15:49:55 +0100136 mod = context_module;
137 }
138 if (implement && !mod->implemented) {
139 /* make the module implemented */
140 ly_ctx_module_implement_internal(ctx->ctx, (struct lys_module*)mod, 2);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100141 }
Radek Krejci7af64242019-02-18 13:07:53 +0100142 context_node = lys_child(context_node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE);
143 if (!context_node) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100144 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Radek Krejci95710c92019-02-11 15:49:55 +0100145 "Invalid %s-schema-nodeid value \"%.*s\" - target node not found.", nodeid_type, id - nodeid, nodeid);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100146 return LY_ENOTFOUND;
147 }
Radek Krejci01342af2019-01-03 15:18:08 +0100148 if (!*id || (nodeid_len && ((size_t)(id - nodeid) >= nodeid_len))) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100149 break;
150 }
Radek Krejci01342af2019-01-03 15:18:08 +0100151 if (*id != '/') {
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100152 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Radek Krejci95710c92019-02-11 15:49:55 +0100153 "Invalid %s-schema-nodeid value \"%.*s\" - missing \"/\" as node-identifier separator.",
154 nodeid_type, id - nodeid + 1, nodeid);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100155 return LY_EVALID;
156 }
157 ++id;
158 }
159
160 if (ret == LY_SUCCESS) {
Radek Krejci7af64242019-02-18 13:07:53 +0100161 *target = context_node;
162 if (nodetype && !(context_node->nodetype & nodetype)) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100163 return LY_EDENIED;
164 }
Radek Krejci95710c92019-02-11 15:49:55 +0100165 } else {
166 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
167 "Invalid %s-schema-nodeid value \"%.*s\" - unexpected end of expression.",
Radek Krejci3641f562019-02-13 15:38:40 +0100168 nodeid_type, nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100169 }
170
171 return ret;
172}
173
174LY_ERR
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100175lysp_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 +0200176{
177 struct lysp_import *i;
178
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100179 if (module_prefix && &module_prefix != value && !strcmp(module_prefix, *value)) {
Radek Krejci86d106e2018-10-18 09:53:19 +0200180 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE,
181 "Prefix \"%s\" already used as module prefix.", *value);
182 return LY_EEXIST;
183 }
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100184 LY_ARRAY_FOR(imports, struct lysp_import, i) {
185 if (i->prefix && &i->prefix != value && !strcmp(i->prefix, *value)) {
186 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Prefix \"%s\" already used to import \"%s\" module.",
187 *value, i->name);
188 return LY_EEXIST;
Radek Krejci86d106e2018-10-18 09:53:19 +0200189 }
190 }
191 return LY_SUCCESS;
192}
193
194LY_ERR
Radek Krejci4f28eda2018-11-12 11:46:16 +0100195lysc_check_status(struct lysc_ctx *ctx,
196 uint16_t flags1, void *mod1, const char *name1,
197 uint16_t flags2, void *mod2, const char *name2)
198{
199 uint16_t flg1, flg2;
200
201 flg1 = (flags1 & LYS_STATUS_MASK) ? (flags1 & LYS_STATUS_MASK) : LYS_STATUS_CURR;
202 flg2 = (flags2 & LYS_STATUS_MASK) ? (flags2 & LYS_STATUS_MASK) : LYS_STATUS_CURR;
203
204 if ((flg1 < flg2) && (mod1 == mod2)) {
205 if (ctx) {
206 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
207 "A %s definition \"%s\" is not allowed to reference %s definition \"%s\".",
208 flg1 == LYS_STATUS_CURR ? "current" : "deprecated", name1,
209 flg2 == LYS_STATUS_OBSLT ? "obsolete" : "deprecated", name2);
210 }
211 return LY_EVALID;
212 }
213
214 return LY_SUCCESS;
215}
216
217LY_ERR
Radek Krejcibbe09a92018-11-08 09:36:54 +0100218lysp_check_date(struct ly_parser_ctx *ctx, const char *date, int date_len, const char *stmt)
Radek Krejci86d106e2018-10-18 09:53:19 +0200219{
220 int i;
221 struct tm tm, tm_;
222 char *r;
223
Radek Krejcibbe09a92018-11-08 09:36:54 +0100224 LY_CHECK_ARG_RET(ctx ? ctx->ctx : NULL, date, LY_EINVAL);
225 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 +0200226
227 /* check format */
228 for (i = 0; i < date_len; i++) {
229 if (i == 4 || i == 7) {
230 if (date[i] != '-') {
231 goto error;
232 }
233 } else if (!isdigit(date[i])) {
234 goto error;
235 }
236 }
237
238 /* check content, e.g. 2018-02-31 */
239 memset(&tm, 0, sizeof tm);
240 r = strptime(date, "%Y-%m-%d", &tm);
241 if (!r || r != &date[LY_REV_SIZE - 1]) {
242 goto error;
243 }
244 memcpy(&tm_, &tm, sizeof tm);
245 mktime(&tm_); /* mktime modifies tm_ if it refers invalid date */
246 if (tm.tm_mday != tm_.tm_mday) { /* e.g 2018-02-29 -> 2018-03-01 */
247 /* checking days is enough, since other errors
248 * have been checked by strptime() */
249 goto error;
250 }
251
252 return LY_SUCCESS;
253
254error:
Radek Krejcid33273d2018-10-25 14:55:52 +0200255 if (stmt) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100256 if (ctx) {
257 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LY_VCODE_INVAL, date_len, date, stmt);
258 } else {
259 LOGVAL(NULL, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, date_len, date, stmt);
260 }
Radek Krejcid33273d2018-10-25 14:55:52 +0200261 }
Radek Krejci86d106e2018-10-18 09:53:19 +0200262 return LY_EINVAL;
263}
264
265void
266lysp_sort_revisions(struct lysp_revision *revs)
267{
268 uint8_t i, r;
269 struct lysp_revision rev;
270
271 for (i = 1, r = 0; revs && i < LY_ARRAY_SIZE(revs); i++) {
Radek Krejcib7db73a2018-10-24 14:18:40 +0200272 if (strcmp(revs[i].date, revs[r].date) > 0) {
Radek Krejci86d106e2018-10-18 09:53:19 +0200273 r = i;
274 }
275 }
276
277 if (r) {
278 /* the newest revision is not on position 0, switch them */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200279 memcpy(&rev, &revs[0], sizeof rev);
280 memcpy(&revs[0], &revs[r], sizeof rev);
281 memcpy(&revs[r], &rev, sizeof rev);
Radek Krejci86d106e2018-10-18 09:53:19 +0200282 }
283}
Radek Krejci151a5b72018-10-19 14:21:44 +0200284
Radek Krejcibbe09a92018-11-08 09:36:54 +0100285static const struct lysp_tpdf *
286lysp_type_match(const char *name, struct lysp_node *node)
287{
Radek Krejci0fb28562018-12-13 15:17:37 +0100288 const struct lysp_tpdf *typedefs;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100289 unsigned int u;
290
Radek Krejci0fb28562018-12-13 15:17:37 +0100291 typedefs = lysp_node_typedefs(node);
292 LY_ARRAY_FOR(typedefs, u) {
293 if (!strcmp(name, typedefs[u].name)) {
294 /* match */
295 return &typedefs[u];
Radek Krejcibbe09a92018-11-08 09:36:54 +0100296 }
297 }
298
299 return NULL;
300}
301
Radek Krejci4f28eda2018-11-12 11:46:16 +0100302static LY_DATA_TYPE
303lysp_type_str2builtin(const char *name, size_t len)
304{
305 if (len >= 4) { /* otherwise it does not match any built-in type */
306 if (name[0] == 'b') {
307 if (name[1] == 'i') {
308 if (len == 6 && !strncmp(&name[2], "nary", 4)) {
309 return LY_TYPE_BINARY;
310 } else if (len == 4 && !strncmp(&name[2], "ts", 2)) {
311 return LY_TYPE_BITS;
312 }
313 } else if (len == 7 && !strncmp(&name[1], "oolean", 6)) {
314 return LY_TYPE_BOOL;
315 }
316 } else if (name[0] == 'd') {
317 if (len == 9 && !strncmp(&name[1], "ecimal64", 8)) {
318 return LY_TYPE_DEC64;
319 }
320 } else if (name[0] == 'e') {
321 if (len == 5 && !strncmp(&name[1], "mpty", 4)) {
322 return LY_TYPE_EMPTY;
323 } else if (len == 11 && !strncmp(&name[1], "numeration", 10)) {
324 return LY_TYPE_ENUM;
325 }
326 } else if (name[0] == 'i') {
327 if (name[1] == 'n') {
328 if (len == 4 && !strncmp(&name[2], "t8", 2)) {
329 return LY_TYPE_INT8;
330 } else if (len == 5) {
331 if (!strncmp(&name[2], "t16", 3)) {
332 return LY_TYPE_INT16;
333 } else if (!strncmp(&name[2], "t32", 3)) {
334 return LY_TYPE_INT32;
335 } else if (!strncmp(&name[2], "t64", 3)) {
336 return LY_TYPE_INT64;
337 }
338 } else if (len == 19 && !strncmp(&name[2], "stance-identifier", 17)) {
339 return LY_TYPE_INST;
340 }
341 } else if (len == 11 && !strncmp(&name[1], "dentityref", 10)) {
342 return LY_TYPE_IDENT;
343 }
344 } else if (name[0] == 'l') {
345 if (len == 7 && !strncmp(&name[1], "eafref", 6)) {
346 return LY_TYPE_LEAFREF;
347 }
348 } else if (name[0] == 's') {
349 if (len == 6 && !strncmp(&name[1], "tring", 5)) {
350 return LY_TYPE_STRING;
351 }
352 } else if (name[0] == 'u') {
353 if (name[1] == 'n') {
354 if (len == 5 && !strncmp(&name[2], "ion", 3)) {
355 return LY_TYPE_UNION;
356 }
357 } else if (name[1] == 'i' && name[2] == 'n' && name[3] == 't') {
358 if (len == 5 && name[4] == '8') {
359 return LY_TYPE_UINT8;
360 } else if (len == 6) {
361 if (!strncmp(&name[4], "16", 2)) {
362 return LY_TYPE_UINT16;
363 } else if (!strncmp(&name[4], "32", 2)) {
364 return LY_TYPE_UINT32;
365 } else if (!strncmp(&name[4], "64", 2)) {
366 return LY_TYPE_UINT64;
367 }
368 }
369 }
370 }
371 }
372
373 return LY_TYPE_UNKNOWN;
374}
375
Radek Krejcibbe09a92018-11-08 09:36:54 +0100376LY_ERR
377lysp_type_find(const char *id, struct lysp_node *start_node, struct lysp_module *start_module,
Radek Krejci4f28eda2018-11-12 11:46:16 +0100378 LY_DATA_TYPE *type, const struct lysp_tpdf **tpdf, struct lysp_node **node, struct lysp_module **module)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100379{
380 const char *str, *name;
381 struct lysp_tpdf *typedefs;
382 unsigned int u, v;
383
384 assert(id);
385 assert(start_module);
386 assert(tpdf);
387 assert(node);
388 assert(module);
389
Radek Krejci4f28eda2018-11-12 11:46:16 +0100390 *node = NULL;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100391 str = strchr(id, ':');
392 if (str) {
393 *module = lysp_module_find_prefix(start_module, id, str - id);
394 name = str + 1;
Radek Krejci4f28eda2018-11-12 11:46:16 +0100395 *type = LY_TYPE_UNKNOWN;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100396 } else {
397 *module = start_module;
398 name = id;
Radek Krejci4f28eda2018-11-12 11:46:16 +0100399
400 /* check for built-in types */
401 *type = lysp_type_str2builtin(name, strlen(name));
402 if (*type) {
403 *tpdf = NULL;
404 return LY_SUCCESS;
405 }
Radek Krejcibbe09a92018-11-08 09:36:54 +0100406 }
407 LY_CHECK_RET(!(*module), LY_ENOTFOUND);
408
409 if (start_node && *module == start_module) {
410 /* search typedefs in parent's nodes */
411 *node = start_node;
412 while (*node) {
413 *tpdf = lysp_type_match(name, *node);
414 if (*tpdf) {
415 /* match */
416 return LY_SUCCESS;
417 }
418 *node = (*node)->parent;
419 }
420 }
421
422 /* search in top-level typedefs */
423 if ((*module)->typedefs) {
424 LY_ARRAY_FOR((*module)->typedefs, u) {
425 if (!strcmp(name, (*module)->typedefs[u].name)) {
426 /* match */
427 *tpdf = &(*module)->typedefs[u];
428 return LY_SUCCESS;
429 }
430 }
431 }
432
433 /* search in submodules' typedefs */
434 LY_ARRAY_FOR((*module)->includes, u) {
435 typedefs = (*module)->includes[u].submodule->typedefs;
Radek Krejci76b3e962018-12-14 17:01:25 +0100436 LY_ARRAY_FOR(typedefs, v) {
437 if (!strcmp(name, typedefs[v].name)) {
438 /* match */
439 *tpdf = &typedefs[v];
440 return LY_SUCCESS;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100441 }
442 }
443 }
444
445 return LY_ENOTFOUND;
446}
447
448/*
449 * @brief Check name of a new type to avoid name collisions.
450 *
451 * @param[in] ctx Parser context, module where the type is being defined is taken from here.
452 * @param[in] node Schema node where the type is being defined, NULL in case of a top-level typedef.
453 * @param[in] tpdf Typedef definition to check.
454 * @param[in,out] tpdfs_global Initialized hash table to store temporary data between calls. When the module's
455 * typedefs are checked, caller is supposed to free the table.
456 * @param[in,out] tpdfs_global Initialized hash table to store temporary data between calls. When the module's
457 * typedefs are checked, caller is supposed to free the table.
458 * @return LY_EEXIST in case of collision, LY_SUCCESS otherwise.
459 */
460static LY_ERR
Radek Krejci0fb28562018-12-13 15:17:37 +0100461lysp_check_typedef(struct ly_parser_ctx *ctx, struct lysp_node *node, const struct lysp_tpdf *tpdf,
Radek Krejcibbe09a92018-11-08 09:36:54 +0100462 struct hash_table *tpdfs_global, struct hash_table *tpdfs_scoped)
463{
464 struct lysp_node *parent;
465 uint32_t hash;
466 size_t name_len;
467 const char *name;
468 unsigned int u;
Radek Krejci0fb28562018-12-13 15:17:37 +0100469 const struct lysp_tpdf *typedefs;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100470
471 assert(ctx);
472 assert(tpdf);
473
474 name = tpdf->name;
475 name_len = strlen(name);
476
Radek Krejci4f28eda2018-11-12 11:46:16 +0100477 if (lysp_type_str2builtin(name, name_len)) {
478 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
479 "Invalid name \"%s\" of typedef - name collision with a built-in type.", name);
480 return LY_EEXIST;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100481 }
482
483 /* check locally scoped typedefs (avoid name shadowing) */
484 if (node) {
Radek Krejci0fb28562018-12-13 15:17:37 +0100485 typedefs = lysp_node_typedefs(node);
486 LY_ARRAY_FOR(typedefs, u) {
487 if (&typedefs[u] == tpdf) {
488 break;
489 }
490 if (!strcmp(name, typedefs[u].name)) {
491 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
492 "Invalid name \"%s\" of typedef - name collision with sibling type.", name);
493 return LY_EEXIST;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100494 }
495 }
496 /* search typedefs in parent's nodes */
497 for (parent = node->parent; parent; parent = node->parent) {
498 if (lysp_type_match(name, parent)) {
499 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
500 "Invalid name \"%s\" of typedef - name collision with another scoped type.", name);
501 return LY_EEXIST;
502 }
503 }
504 }
505
506 /* check collision with the top-level typedefs */
507 hash = dict_hash(name, name_len);
508 if (node) {
509 lyht_insert(tpdfs_scoped, &name, hash, NULL);
510 if (!lyht_find(tpdfs_global, &name, hash, NULL)) {
511 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
512 "Invalid name \"%s\" of typedef - scoped type collide with a top-level type.", name);
513 return LY_EEXIST;
514 }
515 } else {
516 if (lyht_insert(tpdfs_global, &name, hash, NULL)) {
517 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
518 "Invalid name \"%s\" of typedef - name collision with another top-level type.", name);
519 return LY_EEXIST;
520 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100521 /* it is not necessary to test collision with the scoped types - in lysp_check_typedefs, all the
522 * top-level typedefs are inserted into the tables before the scoped typedefs, so the collision
523 * is detected in the first branch few lines above */
Radek Krejcibbe09a92018-11-08 09:36:54 +0100524 }
525
526 return LY_SUCCESS;
527}
528
529static int
530lysp_id_cmp(void *val1, void *val2, int UNUSED(mod), void *UNUSED(cb_data))
531{
532 return !strcmp(val1, val2);
533}
534
535LY_ERR
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100536lysp_check_typedefs(struct ly_parser_ctx *ctx, struct lysp_module *mod)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100537{
538 struct hash_table *ids_global;
539 struct hash_table *ids_scoped;
Radek Krejci0fb28562018-12-13 15:17:37 +0100540 const struct lysp_tpdf *typedefs;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100541 unsigned int i, u;
542 LY_ERR ret = LY_EVALID;
543
544 /* check name collisions - typedefs and groupings */
545 ids_global = lyht_new(8, sizeof(char*), lysp_id_cmp, NULL, 1);
546 ids_scoped = lyht_new(8, sizeof(char*), lysp_id_cmp, NULL, 1);
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100547 LY_ARRAY_FOR(mod->typedefs, i) {
548 if (lysp_check_typedef(ctx, NULL, &mod->typedefs[i], ids_global, ids_scoped)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100549 goto cleanup;
550 }
551 }
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100552 LY_ARRAY_FOR(mod->includes, i) {
553 LY_ARRAY_FOR(mod->includes[i].submodule->typedefs, u) {
554 if (lysp_check_typedef(ctx, NULL, &mod->includes[i].submodule->typedefs[u], ids_global, ids_scoped)) {
Radek Krejci3b1f9292018-11-08 10:58:35 +0100555 goto cleanup;
556 }
557 }
558 }
Radek Krejcibbe09a92018-11-08 09:36:54 +0100559 for (u = 0; u < ctx->tpdfs_nodes.count; ++u) {
Radek Krejci0fb28562018-12-13 15:17:37 +0100560 typedefs = lysp_node_typedefs((struct lysp_node *)ctx->tpdfs_nodes.objs[u]);
561 LY_ARRAY_FOR(typedefs, i) {
562 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 +0100563 goto cleanup;
564 }
565 }
566 }
567 ret = LY_SUCCESS;
568cleanup:
569 lyht_free(ids_global);
570 lyht_free(ids_scoped);
571 ly_set_erase(&ctx->tpdfs_nodes, NULL);
572
573 return ret;
574}
575
Radek Krejci9ed7a192018-10-31 16:23:51 +0100576struct lysp_load_module_check_data {
577 const char *name;
578 const char *revision;
579 const char *path;
580 const char* submoduleof;
581};
582
583static LY_ERR
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100584lysp_load_module_check(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data)
Radek Krejci9ed7a192018-10-31 16:23:51 +0100585{
586 struct lysp_load_module_check_data *info = data;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100587 const char *filename, *dot, *rev, *name;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100588 size_t len;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100589 struct lysp_revision *revs;
590
591 name = mod ? mod->mod->name : submod->name;
592 revs = mod ? mod->revs : submod->revs;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100593
594 if (info->name) {
595 /* check name of the parsed model */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100596 if (strcmp(info->name, name)) {
597 LOGERR(ctx, LY_EINVAL, "Unexpected module \"%s\" parsed instead of \"%s\").", name, info->name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100598 return LY_EINVAL;
599 }
600 }
601 if (info->revision) {
602 /* check revision of the parsed model */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100603 if (!revs || strcmp(info->revision, revs[0].date)) {
604 LOGERR(ctx, LY_EINVAL, "Module \"%s\" parsed with the wrong revision (\"%s\" instead \"%s\").", name,
605 revs[0].date, info->revision);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100606 return LY_EINVAL;
607 }
608 }
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100609 if (submod) {
610 assert(info->submoduleof);
611
Radek Krejci9ed7a192018-10-31 16:23:51 +0100612 /* check that the submodule belongs-to our module */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100613 if (strcmp(info->submoduleof, submod->belongsto)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100614 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 +0100615 submod->name, info->submoduleof, submod->belongsto);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100616 return LY_EVALID;
617 }
618 /* check circular dependency */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100619 if (submod->parsing) {
620 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (include) for module \"%s\".", submod->name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100621 return LY_EVALID;
622 }
623 }
624 if (info->path) {
625 /* check that name and revision match filename */
626 filename = strrchr(info->path, '/');
627 if (!filename) {
628 filename = info->path;
629 } else {
630 filename++;
631 }
632 /* name */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100633 len = strlen(name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100634 rev = strchr(filename, '@');
635 dot = strrchr(info->path, '.');
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100636 if (strncmp(filename, name, len) ||
Radek Krejci9ed7a192018-10-31 16:23:51 +0100637 ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100638 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100639 }
640 /* revision */
641 if (rev) {
642 len = dot - ++rev;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100643 if (!revs || len != 10 || strncmp(revs[0].date, rev, len)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100644 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100645 revs ? revs[0].date : "none");
Radek Krejci9ed7a192018-10-31 16:23:51 +0100646 }
647 }
648 }
649 return LY_SUCCESS;
650}
651
652LY_ERR
Radek Krejci3b1f9292018-11-08 10:58:35 +0100653lys_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 +0100654 void **result)
Radek Krejci9ed7a192018-10-31 16:23:51 +0100655{
656 int fd;
657 char *filepath = NULL;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100658 const char **fp;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100659 LYS_INFORMAT format;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100660 void *mod = NULL;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100661 LY_ERR ret = LY_SUCCESS;
662 struct lysp_load_module_check_data check_data = {0};
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100663 char rpath[PATH_MAX];
Radek Krejci9ed7a192018-10-31 16:23:51 +0100664
665 LY_CHECK_RET(lys_search_localfile(ly_ctx_get_searchdirs(ctx), !(ctx->flags & LY_CTX_DISABLE_SEARCHDIR_CWD), name, revision,
666 &filepath, &format));
667 LY_CHECK_ERR_RET(!filepath, LOGERR(ctx, LY_ENOTFOUND, "Data model \"%s%s%s\" not found in local searchdirs.",
668 name, revision ? "@" : "", revision ? revision : ""), LY_ENOTFOUND);
669
670
671 LOGVRB("Loading schema from \"%s\" file.", filepath);
672
673 /* open the file */
674 fd = open(filepath, O_RDONLY);
675 LY_CHECK_ERR_GOTO(fd < 0, LOGERR(ctx, LY_ESYS, "Unable to open data model file \"%s\" (%s).",
676 filepath, strerror(errno)); ret = LY_ESYS, cleanup);
677
678 check_data.name = name;
679 check_data.revision = revision;
680 check_data.path = filepath;
Radek Krejci3b1f9292018-11-08 10:58:35 +0100681 mod = lys_parse_fd_(ctx, fd, format, implement, main_ctx,
Radek Krejci9ed7a192018-10-31 16:23:51 +0100682 lysp_load_module_check, &check_data);
683 close(fd);
684 LY_CHECK_ERR_GOTO(!mod, ly_errcode(ctx), cleanup);
685
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100686 if (main_ctx) {
687 fp = &((struct lysp_submodule*)mod)->filepath;
688 } else {
689 fp = &((struct lys_module*)mod)->filepath;
690 }
691 if (!(*fp)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100692 if (realpath(filepath, rpath) != NULL) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100693 (*fp) = lydict_insert(ctx, rpath, 0);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100694 } else {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100695 (*fp) = lydict_insert(ctx, filepath, 0);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100696 }
697 }
698
699 *result = mod;
700
701 /* success */
702cleanup:
703 free(filepath);
704 return ret;
705}
706
Radek Krejcid33273d2018-10-25 14:55:52 +0200707LY_ERR
Radek Krejci6d6e4e42018-10-29 13:28:19 +0100708lysp_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 +0200709{
Radek Krejci9ed7a192018-10-31 16:23:51 +0100710 const char *module_data = NULL;
Radek Krejci086c7132018-10-26 15:29:04 +0200711 LYS_INFORMAT format = LYS_IN_UNKNOWN;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100712 void (*module_data_free)(void *module_data, void *user_data) = NULL;
713 struct lysp_load_module_check_data check_data = {0};
Radek Krejci0af46292019-01-11 16:02:31 +0100714 struct lys_module *m;
Radek Krejci086c7132018-10-26 15:29:04 +0200715
Radek Krejci0af46292019-01-11 16:02:31 +0100716 assert(mod);
717
718 if (!*mod) {
719 /* try to get the module from the context */
720 if (revision) {
721 *mod = (struct lys_module*)ly_ctx_get_module(ctx, name, revision);
722 } else {
723 *mod = (struct lys_module*)ly_ctx_get_module_latest(ctx, name);
724 }
Radek Krejci086c7132018-10-26 15:29:04 +0200725 }
726
Radek Krejci6d6e4e42018-10-29 13:28:19 +0100727 if (!(*mod) || (require_parsed && !(*mod)->parsed)) {
728 (*mod) = NULL;
729
Radek Krejci086c7132018-10-26 15:29:04 +0200730 /* check collision with other implemented revision */
731 if (implement && ly_ctx_get_module_implemented(ctx, name)) {
732 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
733 "Module \"%s\" is already present in other implemented revision.", name);
734 return LY_EDENIED;
735 }
736
Radek Krejci9ed7a192018-10-31 16:23:51 +0100737 /* module not present in the context, get the input data and parse it */
Radek Krejci086c7132018-10-26 15:29:04 +0200738 if (!(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
739search_clb:
740 if (ctx->imp_clb) {
741 if (ctx->imp_clb(name, revision, NULL, NULL, ctx->imp_clb_data,
Radek Krejci9ed7a192018-10-31 16:23:51 +0100742 &format, &module_data, &module_data_free) == LY_SUCCESS) {
743 check_data.name = name;
744 check_data.revision = revision;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100745 *mod = lys_parse_mem_module(ctx, module_data, format, implement,
746 lysp_load_module_check, &check_data);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100747 if (module_data_free) {
748 module_data_free((void*)module_data, ctx->imp_clb_data);
749 }
Radek Krejci096235c2019-01-11 11:12:19 +0100750 if (*mod && implement && lys_compile(*mod, 0)) {
751 ly_set_rm(&ctx->list, *mod, NULL);
752 lys_module_free(*mod, NULL);
753 *mod = NULL;
754 }
Radek Krejci086c7132018-10-26 15:29:04 +0200755 }
756 }
757 if (!(*mod) && !(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
758 goto search_file;
759 }
760 } else {
761search_file:
762 if (!(ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
763 /* module was not received from the callback or there is no callback set */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100764 lys_module_localfile(ctx, name, revision, implement, NULL, (void **)mod);
Radek Krejci086c7132018-10-26 15:29:04 +0200765 }
766 if (!(*mod) && (ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
767 goto search_clb;
768 }
769 }
Radek Krejci9ed7a192018-10-31 16:23:51 +0100770
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100771 if ((*mod) && !revision && ((*mod)->latest_revision == 1)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100772 /* update the latest_revision flag - here we have selected the latest available schema,
773 * consider that even the callback provides correct latest revision */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100774 (*mod)->latest_revision = 2;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100775 }
Radek Krejci086c7132018-10-26 15:29:04 +0200776 } else {
777 /* we have module from the current context */
Radek Krejci0af46292019-01-11 16:02:31 +0100778 if (implement) {
779 m = ly_ctx_get_module_implemented(ctx, name);
780 if (m && m != *mod) {
781 /* check collision with other implemented revision */
782 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
783 "Module \"%s\" is already present in other implemented revision.", name);
784 *mod = NULL;
785 return LY_EDENIED;
786 }
Radek Krejci086c7132018-10-26 15:29:04 +0200787 }
788
789 /* circular check */
Radek Krejcif8f882a2018-10-31 14:51:15 +0100790 if ((*mod)->parsed && (*mod)->parsed->parsing) {
Radek Krejci086c7132018-10-26 15:29:04 +0200791 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (import) for module \"%s\".", name);
792 *mod = NULL;
793 return LY_EVALID;
794 }
795 }
796 if (!(*mod)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100797 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "%s \"%s\" module failed.", implement ? "Loading" : "Importing", name);
Radek Krejci086c7132018-10-26 15:29:04 +0200798 return LY_EVALID;
799 }
800
801 if (implement) {
802 /* mark the module implemented, check for collision was already done */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100803 (*mod)->implemented = 1;
Radek Krejci086c7132018-10-26 15:29:04 +0200804 }
Radek Krejci086c7132018-10-26 15:29:04 +0200805
806 return LY_SUCCESS;
807}
808
809LY_ERR
Radek Krejci3b1f9292018-11-08 10:58:35 +0100810lysp_load_submodule(struct ly_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc)
Radek Krejcid33273d2018-10-25 14:55:52 +0200811{
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100812 struct lysp_submodule *submod;
Radek Krejcid33273d2018-10-25 14:55:52 +0200813 const char *submodule_data = NULL;
814 LYS_INFORMAT format = LYS_IN_UNKNOWN;
815 void (*submodule_data_free)(void *module_data, void *user_data) = NULL;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100816 struct lysp_load_module_check_data check_data = {0};
Radek Krejcid33273d2018-10-25 14:55:52 +0200817
Radek Krejcibbe09a92018-11-08 09:36:54 +0100818 /* submodule not present in the context, get the input data and parse it */
Radek Krejci3b1f9292018-11-08 10:58:35 +0100819 if (!(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcid33273d2018-10-25 14:55:52 +0200820search_clb:
Radek Krejci3b1f9292018-11-08 10:58:35 +0100821 if (ctx->ctx->imp_clb) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100822 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 +0100823 &format, &submodule_data, &submodule_data_free) == LY_SUCCESS) {
824 check_data.name = inc->name;
825 check_data.revision = inc->rev[0] ? inc->rev : NULL;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100826 check_data.submoduleof = mod->mod->name;
827 submod = lys_parse_mem_submodule(ctx->ctx, submodule_data, format, ctx,
828 lysp_load_module_check, &check_data);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100829 if (submodule_data_free) {
Radek Krejci3b1f9292018-11-08 10:58:35 +0100830 submodule_data_free((void*)submodule_data, ctx->ctx->imp_clb_data);
Radek Krejcid33273d2018-10-25 14:55:52 +0200831 }
832 }
Radek Krejcid33273d2018-10-25 14:55:52 +0200833 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100834 if (!submod && !(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100835 goto search_file;
Radek Krejcid33273d2018-10-25 14:55:52 +0200836 }
Radek Krejci2d31ea72018-10-25 15:46:42 +0200837 } else {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100838search_file:
Radek Krejci3b1f9292018-11-08 10:58:35 +0100839 if (!(ctx->ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100840 /* submodule was not received from the callback or there is no callback set */
841 lys_module_localfile(ctx->ctx, inc->name, inc->rev[0] ? inc->rev : NULL, 0, ctx, (void**)&submod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100842 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100843 if (!submod && (ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100844 goto search_clb;
845 }
846 }
847 if (submod) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100848 if (!inc->rev[0] && (submod->latest_revision == 1)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100849 /* update the latest_revision flag - here we have selected the latest available schema,
850 * consider that even the callback provides correct latest revision */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100851 submod->latest_revision = 2;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100852 }
853
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100854 inc->submodule = submod;
Radek Krejcid33273d2018-10-25 14:55:52 +0200855 }
856 if (!inc->submodule) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100857 LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Including \"%s\" submodule into \"%s\" failed.",
858 inc->name, mod->mod->name);
Radek Krejcid33273d2018-10-25 14:55:52 +0200859 return LY_EVALID;
860 }
861
862 return LY_SUCCESS;
863}
864
Radek Krejci01342af2019-01-03 15:18:08 +0100865#define FIND_MODULE(TYPE, MOD) \
Radek Krejcice8c1592018-10-29 15:35:51 +0100866 TYPE *imp; \
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100867 if (!strncmp((MOD)->mod->prefix, prefix, len) && (MOD)->mod->prefix[len] == '\0') { \
Radek Krejcice8c1592018-10-29 15:35:51 +0100868 /* it is the prefix of the module itself */ \
Radek Krejci0af46292019-01-11 16:02:31 +0100869 m = ly_ctx_get_module((MOD)->mod->ctx, (MOD)->mod->name, (MOD)->mod->revision); \
Radek Krejcice8c1592018-10-29 15:35:51 +0100870 } \
871 /* search in imports */ \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100872 if (!m) { \
873 LY_ARRAY_FOR((MOD)->imports, TYPE, imp) { \
Radek Krejci01342af2019-01-03 15:18:08 +0100874 if (!strncmp(imp->prefix, prefix, len) && imp->prefix[len] == '\0') { \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100875 m = imp->module; \
876 break; \
877 } \
Radek Krejcice8c1592018-10-29 15:35:51 +0100878 } \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100879 }
Radek Krejcice8c1592018-10-29 15:35:51 +0100880
Radek Krejcibbe09a92018-11-08 09:36:54 +0100881struct lysc_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100882lysc_module_find_prefix(const struct lysc_module *mod, const char *prefix, size_t len)
Radek Krejci151a5b72018-10-19 14:21:44 +0200883{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100884 const struct lys_module *m = NULL;
885
Radek Krejci01342af2019-01-03 15:18:08 +0100886 FIND_MODULE(struct lysc_import, mod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100887 return m ? m->compiled : NULL;
Radek Krejcice8c1592018-10-29 15:35:51 +0100888}
Radek Krejci151a5b72018-10-19 14:21:44 +0200889
Radek Krejcibbe09a92018-11-08 09:36:54 +0100890struct lysp_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100891lysp_module_find_prefix(const struct lysp_module *mod, const char *prefix, size_t len)
Radek Krejcice8c1592018-10-29 15:35:51 +0100892{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100893 const struct lys_module *m = NULL;
894
Radek Krejci01342af2019-01-03 15:18:08 +0100895 FIND_MODULE(struct lysp_import, mod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100896 return m ? m->parsed : NULL;
Radek Krejcice8c1592018-10-29 15:35:51 +0100897}
Radek Krejci151a5b72018-10-19 14:21:44 +0200898
Radek Krejcice8c1592018-10-29 15:35:51 +0100899struct lys_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100900lys_module_find_prefix(const struct lys_module *mod, const char *prefix, size_t len)
Radek Krejcice8c1592018-10-29 15:35:51 +0100901{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100902 const struct lys_module *m = NULL;
903
Radek Krejcice8c1592018-10-29 15:35:51 +0100904 if (mod->compiled) {
Radek Krejci01342af2019-01-03 15:18:08 +0100905 FIND_MODULE(struct lysc_import, mod->compiled);
Radek Krejcice8c1592018-10-29 15:35:51 +0100906 } else {
Radek Krejci01342af2019-01-03 15:18:08 +0100907 FIND_MODULE(struct lysp_import, mod->parsed);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100908 }
909 return (struct lys_module*)m;
910}
911
Radek Krejcia3045382018-11-22 14:30:31 +0100912const char *
913lys_nodetype2str(uint16_t nodetype)
914{
915 switch(nodetype) {
916 case LYS_CONTAINER:
917 return "container";
918 case LYS_CHOICE:
919 return "choice";
920 case LYS_LEAF:
921 return "leaf";
922 case LYS_LEAFLIST:
923 return "leaf-list";
924 case LYS_LIST:
925 return "list";
926 case LYS_ANYXML:
927 return "anyxml";
928 case LYS_ANYDATA:
929 return "anydata";
Radek Krejcif12a1f02019-02-11 16:42:08 +0100930 case LYS_CASE:
931 return "case";
Radek Krejcia3045382018-11-22 14:30:31 +0100932 default:
933 return "unknown";
934 }
935}
936
Radek Krejci056d0a82018-12-06 16:57:25 +0100937API const struct lysp_tpdf *
938lysp_node_typedefs(const struct lysp_node *node)
939{
Radek Krejci0fb28562018-12-13 15:17:37 +0100940 switch (node->nodetype) {
941 case LYS_CONTAINER:
942 return ((struct lysp_node_container*)node)->typedefs;
943 case LYS_LIST:
944 return ((struct lysp_node_list*)node)->typedefs;
945 case LYS_GROUPING:
946 return ((struct lysp_grp*)node)->typedefs;
947 case LYS_ACTION:
948 return ((struct lysp_action*)node)->typedefs;
949 case LYS_INOUT:
950 return ((struct lysp_action_inout*)node)->typedefs;
951 case LYS_NOTIF:
952 return ((struct lysp_notif*)node)->typedefs;
953 default:
Radek Krejci056d0a82018-12-06 16:57:25 +0100954 return NULL;
955 }
956}
957
Radek Krejci53ea6152018-12-13 15:21:15 +0100958API const struct lysp_grp *
959lysp_node_groupings(const struct lysp_node *node)
960{
961 switch (node->nodetype) {
962 case LYS_CONTAINER:
963 return ((struct lysp_node_container*)node)->groupings;
964 case LYS_LIST:
965 return ((struct lysp_node_list*)node)->groupings;
966 case LYS_GROUPING:
967 return ((struct lysp_grp*)node)->groupings;
968 case LYS_ACTION:
969 return ((struct lysp_action*)node)->groupings;
970 case LYS_INOUT:
971 return ((struct lysp_action_inout*)node)->groupings;
972 case LYS_NOTIF:
973 return ((struct lysp_notif*)node)->groupings;
974 default:
975 return NULL;
976 }
977}
978
Radek Krejcibbe09a92018-11-08 09:36:54 +0100979struct lysp_action **
Radek Krejci056d0a82018-12-06 16:57:25 +0100980lysp_node_actions_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100981{
982 assert(node);
983 switch (node->nodetype) {
984 case LYS_CONTAINER:
985 return &((struct lysp_node_container*)node)->actions;
986 case LYS_LIST:
987 return &((struct lysp_node_list*)node)->actions;
988 case LYS_GROUPING:
989 return &((struct lysp_grp*)node)->actions;
990 case LYS_AUGMENT:
991 return &((struct lysp_augment*)node)->actions;
992 default:
993 return NULL;
994 }
995}
996
Radek Krejci056d0a82018-12-06 16:57:25 +0100997API const struct lysp_action *
998lysp_node_actions(const struct lysp_node *node)
999{
1000 struct lysp_action **actions;
1001 actions = lysp_node_actions_p((struct lysp_node*)node);
1002 if (actions) {
1003 return *actions;
1004 } else {
1005 return NULL;
1006 }
1007}
1008
Radek Krejcibbe09a92018-11-08 09:36:54 +01001009struct lysp_notif **
Radek Krejci056d0a82018-12-06 16:57:25 +01001010lysp_node_notifs_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001011{
1012 assert(node);
1013 switch (node->nodetype) {
1014 case LYS_CONTAINER:
1015 return &((struct lysp_node_container*)node)->notifs;
1016 case LYS_LIST:
1017 return &((struct lysp_node_list*)node)->notifs;
1018 case LYS_GROUPING:
1019 return &((struct lysp_grp*)node)->notifs;
1020 case LYS_AUGMENT:
1021 return &((struct lysp_augment*)node)->notifs;
1022 default:
1023 return NULL;
1024 }
1025}
1026
Radek Krejci056d0a82018-12-06 16:57:25 +01001027API const struct lysp_notif *
1028lysp_node_notifs(const struct lysp_node *node)
1029{
1030 struct lysp_notif **notifs;
1031 notifs = lysp_node_notifs_p((struct lysp_node*)node);
1032 if (notifs) {
1033 return *notifs;
1034 } else {
1035 return NULL;
1036 }
1037}
1038
Radek Krejcibbe09a92018-11-08 09:36:54 +01001039struct lysp_node **
Radek Krejci056d0a82018-12-06 16:57:25 +01001040lysp_node_children_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001041{
1042 assert(node);
1043 switch (node->nodetype) {
1044 case LYS_CONTAINER:
1045 return &((struct lysp_node_container*)node)->child;
1046 case LYS_CHOICE:
1047 return &((struct lysp_node_choice*)node)->child;
1048 case LYS_LIST:
1049 return &((struct lysp_node_list*)node)->child;
1050 case LYS_CASE:
1051 return &((struct lysp_node_case*)node)->child;
1052 case LYS_GROUPING:
1053 return &((struct lysp_grp*)node)->data;
1054 case LYS_AUGMENT:
1055 return &((struct lysp_augment*)node)->child;
1056 case LYS_INOUT:
1057 return &((struct lysp_action_inout*)node)->data;
1058 case LYS_NOTIF:
1059 return &((struct lysp_notif*)node)->data;
1060 default:
1061 return NULL;
1062 }
1063}
1064
Radek Krejci056d0a82018-12-06 16:57:25 +01001065API const struct lysp_node *
1066lysp_node_children(const struct lysp_node *node)
1067{
1068 struct lysp_node **children;
1069 children = lysp_node_children_p((struct lysp_node*)node);
1070 if (children) {
1071 return *children;
1072 } else {
1073 return NULL;
1074 }
1075}
1076
1077struct lysc_action **
1078lysc_node_actions_p(struct lysc_node *node)
1079{
1080 assert(node);
1081 switch (node->nodetype) {
1082 case LYS_CONTAINER:
1083 return &((struct lysc_node_container*)node)->actions;
1084 case LYS_LIST:
1085 return &((struct lysc_node_list*)node)->actions;
1086 default:
1087 return NULL;
1088 }
1089}
1090
1091API const struct lysc_action *
1092lysc_node_actions(const struct lysc_node *node)
1093{
1094 struct lysc_action **actions;
1095 actions = lysc_node_actions_p((struct lysc_node*)node);
1096 if (actions) {
1097 return *actions;
1098 } else {
1099 return NULL;
1100 }
1101}
1102
1103struct lysc_notif **
1104lysc_node_notifs_p(struct lysc_node *node)
1105{
1106 assert(node);
1107 switch (node->nodetype) {
1108 case LYS_CONTAINER:
1109 return &((struct lysc_node_container*)node)->notifs;
1110 case LYS_LIST:
1111 return &((struct lysc_node_list*)node)->notifs;
1112 default:
1113 return NULL;
1114 }
1115}
1116
1117API const struct lysc_notif *
1118lysc_node_notifs(const struct lysc_node *node)
1119{
1120 struct lysc_notif **notifs;
1121 notifs = lysc_node_notifs_p((struct lysc_node*)node);
1122 if (notifs) {
1123 return *notifs;
1124 } else {
1125 return NULL;
1126 }
1127}
1128
Radek Krejcibbe09a92018-11-08 09:36:54 +01001129struct lysc_node **
Radek Krejci056d0a82018-12-06 16:57:25 +01001130lysc_node_children_p(const struct lysc_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001131{
1132 assert(node);
1133 switch (node->nodetype) {
1134 case LYS_CONTAINER:
1135 return &((struct lysc_node_container*)node)->child;
1136 case LYS_CHOICE:
Radek Krejcia3045382018-11-22 14:30:31 +01001137 if (((struct lysc_node_choice*)node)->cases) {
Radek Krejci95710c92019-02-11 15:49:55 +01001138 return &((struct lysc_node_choice*)node)->cases->child;
Radek Krejcia3045382018-11-22 14:30:31 +01001139 } else {
1140 return NULL;
1141 }
Radek Krejci01342af2019-01-03 15:18:08 +01001142 case LYS_CASE:
1143 return &((struct lysc_node_case*)node)->child;
Radek Krejcibbe09a92018-11-08 09:36:54 +01001144 case LYS_LIST:
1145 return &((struct lysc_node_list*)node)->child;
Radek Krejcibbe09a92018-11-08 09:36:54 +01001146/* TODO
1147 case LYS_INOUT:
1148 return &((struct lysc_action_inout*)node)->child;
1149 case LYS_NOTIF:
1150 return &((struct lysc_notif*)node)->child;
1151*/
1152 default:
1153 return NULL;
1154 }
1155}
1156
Radek Krejci056d0a82018-12-06 16:57:25 +01001157API const struct lysc_node *
1158lysc_node_children(const struct lysc_node *node)
Radek Krejcia3045382018-11-22 14:30:31 +01001159{
Radek Krejci056d0a82018-12-06 16:57:25 +01001160 struct lysc_node **children;
1161 children = lysc_node_children_p((struct lysc_node*)node);
1162 if (children) {
1163 return *children;
1164 } else {
Radek Krejcia3045382018-11-22 14:30:31 +01001165 return NULL;
1166 }
1167}
1168
Radek Krejci96a0bfd2018-11-22 15:25:06 +01001169struct lys_module *
1170lysp_find_module(struct ly_ctx *ctx, const struct lysp_module *mod)
1171{
1172 unsigned int u;
1173
1174 for (u = 0; u < ctx->list.count; ++u) {
1175 if (((struct lys_module*)ctx->list.objs[u])->parsed == mod) {
1176 return ((struct lys_module*)ctx->list.objs[u]);
1177 }
1178 }
1179 return NULL;
1180}
1181