blob: 706770181e0b62f49569bba37761ec030d753f70 [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,
89 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;
93 const struct lysc_node *context;
94 size_t name_len, prefix_len;
Radek Krejci95710c92019-02-11 15:49:55 +010095 const struct lys_module *mod, *context_module;
96 const char *nodeid_type;
Radek Krejci9bb94eb2018-12-04 16:48:35 +010097
98 assert(nodeid);
Radek Krejci9bb94eb2018-12-04 16:48:35 +010099 assert(target);
100 *target = NULL;
101
102 id = nodeid;
103 context = context_node;
Radek Krejci95710c92019-02-11 15:49:55 +0100104
105 if (context_node) {
106 /* descendant-schema-nodeid */
107 nodeid_type = "descendant";
108 context_module = context_node->module;
109 } else {
110 /* absolute-schema-nodeid */
111 nodeid_type = "absolute";
112 context_module = ctx->mod_def;
113
114 if (*id != '/') {
115 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
116 "Invalid absolute-schema-nodeid value \"%.*s\" - missing starting \"/\".",
117 nodeid_len, nodeid);
118 return LY_EVALID;
119 }
120 ++id;
121 }
122
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100123 while (*id && (ret = lys_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len)) == LY_SUCCESS) {
124 if (prefix) {
Radek Krejci95710c92019-02-11 15:49:55 +0100125 mod = lys_module_find_prefix(context_module, prefix, prefix_len);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100126 if (!mod) {
127 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Radek Krejci95710c92019-02-11 15:49:55 +0100128 "Invalid %s-schema-nodeid value \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
129 nodeid_type, id - nodeid, nodeid, prefix_len, prefix, context_module->name);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100130 return LY_ENOTFOUND;
131 }
132 } else {
Radek Krejci95710c92019-02-11 15:49:55 +0100133 mod = context_module;
134 }
135 if (implement && !mod->implemented) {
136 /* make the module implemented */
137 ly_ctx_module_implement_internal(ctx->ctx, (struct lys_module*)mod, 2);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100138 }
Radek Krejcia9026eb2018-12-12 16:04:47 +0100139 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 +0100140 if (!context) {
141 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Radek Krejci95710c92019-02-11 15:49:55 +0100142 "Invalid %s-schema-nodeid value \"%.*s\" - target node not found.", nodeid_type, id - nodeid, nodeid);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100143 return LY_ENOTFOUND;
144 }
Radek Krejci01342af2019-01-03 15:18:08 +0100145 if (!*id || (nodeid_len && ((size_t)(id - nodeid) >= nodeid_len))) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100146 break;
147 }
Radek Krejci01342af2019-01-03 15:18:08 +0100148 if (*id != '/') {
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100149 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Radek Krejci95710c92019-02-11 15:49:55 +0100150 "Invalid %s-schema-nodeid value \"%.*s\" - missing \"/\" as node-identifier separator.",
151 nodeid_type, id - nodeid + 1, nodeid);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100152 return LY_EVALID;
153 }
154 ++id;
155 }
156
157 if (ret == LY_SUCCESS) {
158 *target = context;
159 if (nodetype && !(context->nodetype & nodetype)) {
160 return LY_EDENIED;
161 }
Radek Krejci95710c92019-02-11 15:49:55 +0100162 } else {
163 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
164 "Invalid %s-schema-nodeid value \"%.*s\" - unexpected end of expression.",
165 nodeid_type, nodeid_len, nodeid);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100166 }
167
168 return ret;
169}
170
171LY_ERR
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100172lysp_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 +0200173{
174 struct lysp_import *i;
175
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100176 if (module_prefix && &module_prefix != value && !strcmp(module_prefix, *value)) {
Radek Krejci86d106e2018-10-18 09:53:19 +0200177 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE,
178 "Prefix \"%s\" already used as module prefix.", *value);
179 return LY_EEXIST;
180 }
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100181 LY_ARRAY_FOR(imports, struct lysp_import, i) {
182 if (i->prefix && &i->prefix != value && !strcmp(i->prefix, *value)) {
183 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Prefix \"%s\" already used to import \"%s\" module.",
184 *value, i->name);
185 return LY_EEXIST;
Radek Krejci86d106e2018-10-18 09:53:19 +0200186 }
187 }
188 return LY_SUCCESS;
189}
190
191LY_ERR
Radek Krejci4f28eda2018-11-12 11:46:16 +0100192lysc_check_status(struct lysc_ctx *ctx,
193 uint16_t flags1, void *mod1, const char *name1,
194 uint16_t flags2, void *mod2, const char *name2)
195{
196 uint16_t flg1, flg2;
197
198 flg1 = (flags1 & LYS_STATUS_MASK) ? (flags1 & LYS_STATUS_MASK) : LYS_STATUS_CURR;
199 flg2 = (flags2 & LYS_STATUS_MASK) ? (flags2 & LYS_STATUS_MASK) : LYS_STATUS_CURR;
200
201 if ((flg1 < flg2) && (mod1 == mod2)) {
202 if (ctx) {
203 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
204 "A %s definition \"%s\" is not allowed to reference %s definition \"%s\".",
205 flg1 == LYS_STATUS_CURR ? "current" : "deprecated", name1,
206 flg2 == LYS_STATUS_OBSLT ? "obsolete" : "deprecated", name2);
207 }
208 return LY_EVALID;
209 }
210
211 return LY_SUCCESS;
212}
213
214LY_ERR
Radek Krejcibbe09a92018-11-08 09:36:54 +0100215lysp_check_date(struct ly_parser_ctx *ctx, const char *date, int date_len, const char *stmt)
Radek Krejci86d106e2018-10-18 09:53:19 +0200216{
217 int i;
218 struct tm tm, tm_;
219 char *r;
220
Radek Krejcibbe09a92018-11-08 09:36:54 +0100221 LY_CHECK_ARG_RET(ctx ? ctx->ctx : NULL, date, LY_EINVAL);
222 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 +0200223
224 /* check format */
225 for (i = 0; i < date_len; i++) {
226 if (i == 4 || i == 7) {
227 if (date[i] != '-') {
228 goto error;
229 }
230 } else if (!isdigit(date[i])) {
231 goto error;
232 }
233 }
234
235 /* check content, e.g. 2018-02-31 */
236 memset(&tm, 0, sizeof tm);
237 r = strptime(date, "%Y-%m-%d", &tm);
238 if (!r || r != &date[LY_REV_SIZE - 1]) {
239 goto error;
240 }
241 memcpy(&tm_, &tm, sizeof tm);
242 mktime(&tm_); /* mktime modifies tm_ if it refers invalid date */
243 if (tm.tm_mday != tm_.tm_mday) { /* e.g 2018-02-29 -> 2018-03-01 */
244 /* checking days is enough, since other errors
245 * have been checked by strptime() */
246 goto error;
247 }
248
249 return LY_SUCCESS;
250
251error:
Radek Krejcid33273d2018-10-25 14:55:52 +0200252 if (stmt) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100253 if (ctx) {
254 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LY_VCODE_INVAL, date_len, date, stmt);
255 } else {
256 LOGVAL(NULL, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, date_len, date, stmt);
257 }
Radek Krejcid33273d2018-10-25 14:55:52 +0200258 }
Radek Krejci86d106e2018-10-18 09:53:19 +0200259 return LY_EINVAL;
260}
261
262void
263lysp_sort_revisions(struct lysp_revision *revs)
264{
265 uint8_t i, r;
266 struct lysp_revision rev;
267
268 for (i = 1, r = 0; revs && i < LY_ARRAY_SIZE(revs); i++) {
Radek Krejcib7db73a2018-10-24 14:18:40 +0200269 if (strcmp(revs[i].date, revs[r].date) > 0) {
Radek Krejci86d106e2018-10-18 09:53:19 +0200270 r = i;
271 }
272 }
273
274 if (r) {
275 /* the newest revision is not on position 0, switch them */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200276 memcpy(&rev, &revs[0], sizeof rev);
277 memcpy(&revs[0], &revs[r], sizeof rev);
278 memcpy(&revs[r], &rev, sizeof rev);
Radek Krejci86d106e2018-10-18 09:53:19 +0200279 }
280}
Radek Krejci151a5b72018-10-19 14:21:44 +0200281
Radek Krejcibbe09a92018-11-08 09:36:54 +0100282static const struct lysp_tpdf *
283lysp_type_match(const char *name, struct lysp_node *node)
284{
Radek Krejci0fb28562018-12-13 15:17:37 +0100285 const struct lysp_tpdf *typedefs;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100286 unsigned int u;
287
Radek Krejci0fb28562018-12-13 15:17:37 +0100288 typedefs = lysp_node_typedefs(node);
289 LY_ARRAY_FOR(typedefs, u) {
290 if (!strcmp(name, typedefs[u].name)) {
291 /* match */
292 return &typedefs[u];
Radek Krejcibbe09a92018-11-08 09:36:54 +0100293 }
294 }
295
296 return NULL;
297}
298
Radek Krejci4f28eda2018-11-12 11:46:16 +0100299static LY_DATA_TYPE
300lysp_type_str2builtin(const char *name, size_t len)
301{
302 if (len >= 4) { /* otherwise it does not match any built-in type */
303 if (name[0] == 'b') {
304 if (name[1] == 'i') {
305 if (len == 6 && !strncmp(&name[2], "nary", 4)) {
306 return LY_TYPE_BINARY;
307 } else if (len == 4 && !strncmp(&name[2], "ts", 2)) {
308 return LY_TYPE_BITS;
309 }
310 } else if (len == 7 && !strncmp(&name[1], "oolean", 6)) {
311 return LY_TYPE_BOOL;
312 }
313 } else if (name[0] == 'd') {
314 if (len == 9 && !strncmp(&name[1], "ecimal64", 8)) {
315 return LY_TYPE_DEC64;
316 }
317 } else if (name[0] == 'e') {
318 if (len == 5 && !strncmp(&name[1], "mpty", 4)) {
319 return LY_TYPE_EMPTY;
320 } else if (len == 11 && !strncmp(&name[1], "numeration", 10)) {
321 return LY_TYPE_ENUM;
322 }
323 } else if (name[0] == 'i') {
324 if (name[1] == 'n') {
325 if (len == 4 && !strncmp(&name[2], "t8", 2)) {
326 return LY_TYPE_INT8;
327 } else if (len == 5) {
328 if (!strncmp(&name[2], "t16", 3)) {
329 return LY_TYPE_INT16;
330 } else if (!strncmp(&name[2], "t32", 3)) {
331 return LY_TYPE_INT32;
332 } else if (!strncmp(&name[2], "t64", 3)) {
333 return LY_TYPE_INT64;
334 }
335 } else if (len == 19 && !strncmp(&name[2], "stance-identifier", 17)) {
336 return LY_TYPE_INST;
337 }
338 } else if (len == 11 && !strncmp(&name[1], "dentityref", 10)) {
339 return LY_TYPE_IDENT;
340 }
341 } else if (name[0] == 'l') {
342 if (len == 7 && !strncmp(&name[1], "eafref", 6)) {
343 return LY_TYPE_LEAFREF;
344 }
345 } else if (name[0] == 's') {
346 if (len == 6 && !strncmp(&name[1], "tring", 5)) {
347 return LY_TYPE_STRING;
348 }
349 } else if (name[0] == 'u') {
350 if (name[1] == 'n') {
351 if (len == 5 && !strncmp(&name[2], "ion", 3)) {
352 return LY_TYPE_UNION;
353 }
354 } else if (name[1] == 'i' && name[2] == 'n' && name[3] == 't') {
355 if (len == 5 && name[4] == '8') {
356 return LY_TYPE_UINT8;
357 } else if (len == 6) {
358 if (!strncmp(&name[4], "16", 2)) {
359 return LY_TYPE_UINT16;
360 } else if (!strncmp(&name[4], "32", 2)) {
361 return LY_TYPE_UINT32;
362 } else if (!strncmp(&name[4], "64", 2)) {
363 return LY_TYPE_UINT64;
364 }
365 }
366 }
367 }
368 }
369
370 return LY_TYPE_UNKNOWN;
371}
372
Radek Krejcibbe09a92018-11-08 09:36:54 +0100373LY_ERR
374lysp_type_find(const char *id, struct lysp_node *start_node, struct lysp_module *start_module,
Radek Krejci4f28eda2018-11-12 11:46:16 +0100375 LY_DATA_TYPE *type, const struct lysp_tpdf **tpdf, struct lysp_node **node, struct lysp_module **module)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100376{
377 const char *str, *name;
378 struct lysp_tpdf *typedefs;
379 unsigned int u, v;
380
381 assert(id);
382 assert(start_module);
383 assert(tpdf);
384 assert(node);
385 assert(module);
386
Radek Krejci4f28eda2018-11-12 11:46:16 +0100387 *node = NULL;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100388 str = strchr(id, ':');
389 if (str) {
390 *module = lysp_module_find_prefix(start_module, id, str - id);
391 name = str + 1;
Radek Krejci4f28eda2018-11-12 11:46:16 +0100392 *type = LY_TYPE_UNKNOWN;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100393 } else {
394 *module = start_module;
395 name = id;
Radek Krejci4f28eda2018-11-12 11:46:16 +0100396
397 /* check for built-in types */
398 *type = lysp_type_str2builtin(name, strlen(name));
399 if (*type) {
400 *tpdf = NULL;
401 return LY_SUCCESS;
402 }
Radek Krejcibbe09a92018-11-08 09:36:54 +0100403 }
404 LY_CHECK_RET(!(*module), LY_ENOTFOUND);
405
406 if (start_node && *module == start_module) {
407 /* search typedefs in parent's nodes */
408 *node = start_node;
409 while (*node) {
410 *tpdf = lysp_type_match(name, *node);
411 if (*tpdf) {
412 /* match */
413 return LY_SUCCESS;
414 }
415 *node = (*node)->parent;
416 }
417 }
418
419 /* search in top-level typedefs */
420 if ((*module)->typedefs) {
421 LY_ARRAY_FOR((*module)->typedefs, u) {
422 if (!strcmp(name, (*module)->typedefs[u].name)) {
423 /* match */
424 *tpdf = &(*module)->typedefs[u];
425 return LY_SUCCESS;
426 }
427 }
428 }
429
430 /* search in submodules' typedefs */
431 LY_ARRAY_FOR((*module)->includes, u) {
432 typedefs = (*module)->includes[u].submodule->typedefs;
Radek Krejci76b3e962018-12-14 17:01:25 +0100433 LY_ARRAY_FOR(typedefs, v) {
434 if (!strcmp(name, typedefs[v].name)) {
435 /* match */
436 *tpdf = &typedefs[v];
437 return LY_SUCCESS;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100438 }
439 }
440 }
441
442 return LY_ENOTFOUND;
443}
444
445/*
446 * @brief Check name of a new type to avoid name collisions.
447 *
448 * @param[in] ctx Parser context, module where the type is being defined is taken from here.
449 * @param[in] node Schema node where the type is being defined, NULL in case of a top-level typedef.
450 * @param[in] tpdf Typedef definition to check.
451 * @param[in,out] tpdfs_global Initialized hash table to store temporary data between calls. When the module's
452 * typedefs are checked, caller is supposed to free the table.
453 * @param[in,out] tpdfs_global Initialized hash table to store temporary data between calls. When the module's
454 * typedefs are checked, caller is supposed to free the table.
455 * @return LY_EEXIST in case of collision, LY_SUCCESS otherwise.
456 */
457static LY_ERR
Radek Krejci0fb28562018-12-13 15:17:37 +0100458lysp_check_typedef(struct ly_parser_ctx *ctx, struct lysp_node *node, const struct lysp_tpdf *tpdf,
Radek Krejcibbe09a92018-11-08 09:36:54 +0100459 struct hash_table *tpdfs_global, struct hash_table *tpdfs_scoped)
460{
461 struct lysp_node *parent;
462 uint32_t hash;
463 size_t name_len;
464 const char *name;
465 unsigned int u;
Radek Krejci0fb28562018-12-13 15:17:37 +0100466 const struct lysp_tpdf *typedefs;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100467
468 assert(ctx);
469 assert(tpdf);
470
471 name = tpdf->name;
472 name_len = strlen(name);
473
Radek Krejci4f28eda2018-11-12 11:46:16 +0100474 if (lysp_type_str2builtin(name, name_len)) {
475 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
476 "Invalid name \"%s\" of typedef - name collision with a built-in type.", name);
477 return LY_EEXIST;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100478 }
479
480 /* check locally scoped typedefs (avoid name shadowing) */
481 if (node) {
Radek Krejci0fb28562018-12-13 15:17:37 +0100482 typedefs = lysp_node_typedefs(node);
483 LY_ARRAY_FOR(typedefs, u) {
484 if (&typedefs[u] == tpdf) {
485 break;
486 }
487 if (!strcmp(name, typedefs[u].name)) {
488 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
489 "Invalid name \"%s\" of typedef - name collision with sibling type.", name);
490 return LY_EEXIST;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100491 }
492 }
493 /* search typedefs in parent's nodes */
494 for (parent = node->parent; parent; parent = node->parent) {
495 if (lysp_type_match(name, parent)) {
496 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
497 "Invalid name \"%s\" of typedef - name collision with another scoped type.", name);
498 return LY_EEXIST;
499 }
500 }
501 }
502
503 /* check collision with the top-level typedefs */
504 hash = dict_hash(name, name_len);
505 if (node) {
506 lyht_insert(tpdfs_scoped, &name, hash, NULL);
507 if (!lyht_find(tpdfs_global, &name, hash, NULL)) {
508 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
509 "Invalid name \"%s\" of typedef - scoped type collide with a top-level type.", name);
510 return LY_EEXIST;
511 }
512 } else {
513 if (lyht_insert(tpdfs_global, &name, hash, NULL)) {
514 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
515 "Invalid name \"%s\" of typedef - name collision with another top-level type.", name);
516 return LY_EEXIST;
517 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100518 /* it is not necessary to test collision with the scoped types - in lysp_check_typedefs, all the
519 * top-level typedefs are inserted into the tables before the scoped typedefs, so the collision
520 * is detected in the first branch few lines above */
Radek Krejcibbe09a92018-11-08 09:36:54 +0100521 }
522
523 return LY_SUCCESS;
524}
525
526static int
527lysp_id_cmp(void *val1, void *val2, int UNUSED(mod), void *UNUSED(cb_data))
528{
529 return !strcmp(val1, val2);
530}
531
532LY_ERR
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100533lysp_check_typedefs(struct ly_parser_ctx *ctx, struct lysp_module *mod)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100534{
535 struct hash_table *ids_global;
536 struct hash_table *ids_scoped;
Radek Krejci0fb28562018-12-13 15:17:37 +0100537 const struct lysp_tpdf *typedefs;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100538 unsigned int i, u;
539 LY_ERR ret = LY_EVALID;
540
541 /* check name collisions - typedefs and groupings */
542 ids_global = lyht_new(8, sizeof(char*), lysp_id_cmp, NULL, 1);
543 ids_scoped = lyht_new(8, sizeof(char*), lysp_id_cmp, NULL, 1);
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100544 LY_ARRAY_FOR(mod->typedefs, i) {
545 if (lysp_check_typedef(ctx, NULL, &mod->typedefs[i], ids_global, ids_scoped)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100546 goto cleanup;
547 }
548 }
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100549 LY_ARRAY_FOR(mod->includes, i) {
550 LY_ARRAY_FOR(mod->includes[i].submodule->typedefs, u) {
551 if (lysp_check_typedef(ctx, NULL, &mod->includes[i].submodule->typedefs[u], ids_global, ids_scoped)) {
Radek Krejci3b1f9292018-11-08 10:58:35 +0100552 goto cleanup;
553 }
554 }
555 }
Radek Krejcibbe09a92018-11-08 09:36:54 +0100556 for (u = 0; u < ctx->tpdfs_nodes.count; ++u) {
Radek Krejci0fb28562018-12-13 15:17:37 +0100557 typedefs = lysp_node_typedefs((struct lysp_node *)ctx->tpdfs_nodes.objs[u]);
558 LY_ARRAY_FOR(typedefs, i) {
559 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 +0100560 goto cleanup;
561 }
562 }
563 }
564 ret = LY_SUCCESS;
565cleanup:
566 lyht_free(ids_global);
567 lyht_free(ids_scoped);
568 ly_set_erase(&ctx->tpdfs_nodes, NULL);
569
570 return ret;
571}
572
Radek Krejci9ed7a192018-10-31 16:23:51 +0100573struct lysp_load_module_check_data {
574 const char *name;
575 const char *revision;
576 const char *path;
577 const char* submoduleof;
578};
579
580static LY_ERR
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100581lysp_load_module_check(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data)
Radek Krejci9ed7a192018-10-31 16:23:51 +0100582{
583 struct lysp_load_module_check_data *info = data;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100584 const char *filename, *dot, *rev, *name;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100585 size_t len;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100586 struct lysp_revision *revs;
587
588 name = mod ? mod->mod->name : submod->name;
589 revs = mod ? mod->revs : submod->revs;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100590
591 if (info->name) {
592 /* check name of the parsed model */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100593 if (strcmp(info->name, name)) {
594 LOGERR(ctx, LY_EINVAL, "Unexpected module \"%s\" parsed instead of \"%s\").", name, info->name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100595 return LY_EINVAL;
596 }
597 }
598 if (info->revision) {
599 /* check revision of the parsed model */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100600 if (!revs || strcmp(info->revision, revs[0].date)) {
601 LOGERR(ctx, LY_EINVAL, "Module \"%s\" parsed with the wrong revision (\"%s\" instead \"%s\").", name,
602 revs[0].date, info->revision);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100603 return LY_EINVAL;
604 }
605 }
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100606 if (submod) {
607 assert(info->submoduleof);
608
Radek Krejci9ed7a192018-10-31 16:23:51 +0100609 /* check that the submodule belongs-to our module */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100610 if (strcmp(info->submoduleof, submod->belongsto)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100611 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 +0100612 submod->name, info->submoduleof, submod->belongsto);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100613 return LY_EVALID;
614 }
615 /* check circular dependency */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100616 if (submod->parsing) {
617 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (include) for module \"%s\".", submod->name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100618 return LY_EVALID;
619 }
620 }
621 if (info->path) {
622 /* check that name and revision match filename */
623 filename = strrchr(info->path, '/');
624 if (!filename) {
625 filename = info->path;
626 } else {
627 filename++;
628 }
629 /* name */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100630 len = strlen(name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100631 rev = strchr(filename, '@');
632 dot = strrchr(info->path, '.');
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100633 if (strncmp(filename, name, len) ||
Radek Krejci9ed7a192018-10-31 16:23:51 +0100634 ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100635 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100636 }
637 /* revision */
638 if (rev) {
639 len = dot - ++rev;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100640 if (!revs || len != 10 || strncmp(revs[0].date, rev, len)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100641 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100642 revs ? revs[0].date : "none");
Radek Krejci9ed7a192018-10-31 16:23:51 +0100643 }
644 }
645 }
646 return LY_SUCCESS;
647}
648
649LY_ERR
Radek Krejci3b1f9292018-11-08 10:58:35 +0100650lys_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 +0100651 void **result)
Radek Krejci9ed7a192018-10-31 16:23:51 +0100652{
653 int fd;
654 char *filepath = NULL;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100655 const char **fp;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100656 LYS_INFORMAT format;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100657 void *mod = NULL;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100658 LY_ERR ret = LY_SUCCESS;
659 struct lysp_load_module_check_data check_data = {0};
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100660 char rpath[PATH_MAX];
Radek Krejci9ed7a192018-10-31 16:23:51 +0100661
662 LY_CHECK_RET(lys_search_localfile(ly_ctx_get_searchdirs(ctx), !(ctx->flags & LY_CTX_DISABLE_SEARCHDIR_CWD), name, revision,
663 &filepath, &format));
664 LY_CHECK_ERR_RET(!filepath, LOGERR(ctx, LY_ENOTFOUND, "Data model \"%s%s%s\" not found in local searchdirs.",
665 name, revision ? "@" : "", revision ? revision : ""), LY_ENOTFOUND);
666
667
668 LOGVRB("Loading schema from \"%s\" file.", filepath);
669
670 /* open the file */
671 fd = open(filepath, O_RDONLY);
672 LY_CHECK_ERR_GOTO(fd < 0, LOGERR(ctx, LY_ESYS, "Unable to open data model file \"%s\" (%s).",
673 filepath, strerror(errno)); ret = LY_ESYS, cleanup);
674
675 check_data.name = name;
676 check_data.revision = revision;
677 check_data.path = filepath;
Radek Krejci3b1f9292018-11-08 10:58:35 +0100678 mod = lys_parse_fd_(ctx, fd, format, implement, main_ctx,
Radek Krejci9ed7a192018-10-31 16:23:51 +0100679 lysp_load_module_check, &check_data);
680 close(fd);
681 LY_CHECK_ERR_GOTO(!mod, ly_errcode(ctx), cleanup);
682
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100683 if (main_ctx) {
684 fp = &((struct lysp_submodule*)mod)->filepath;
685 } else {
686 fp = &((struct lys_module*)mod)->filepath;
687 }
688 if (!(*fp)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100689 if (realpath(filepath, rpath) != NULL) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100690 (*fp) = lydict_insert(ctx, rpath, 0);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100691 } else {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100692 (*fp) = lydict_insert(ctx, filepath, 0);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100693 }
694 }
695
696 *result = mod;
697
698 /* success */
699cleanup:
700 free(filepath);
701 return ret;
702}
703
Radek Krejcid33273d2018-10-25 14:55:52 +0200704LY_ERR
Radek Krejci6d6e4e42018-10-29 13:28:19 +0100705lysp_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 +0200706{
Radek Krejci9ed7a192018-10-31 16:23:51 +0100707 const char *module_data = NULL;
Radek Krejci086c7132018-10-26 15:29:04 +0200708 LYS_INFORMAT format = LYS_IN_UNKNOWN;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100709 void (*module_data_free)(void *module_data, void *user_data) = NULL;
710 struct lysp_load_module_check_data check_data = {0};
Radek Krejci0af46292019-01-11 16:02:31 +0100711 struct lys_module *m;
Radek Krejci086c7132018-10-26 15:29:04 +0200712
Radek Krejci0af46292019-01-11 16:02:31 +0100713 assert(mod);
714
715 if (!*mod) {
716 /* try to get the module from the context */
717 if (revision) {
718 *mod = (struct lys_module*)ly_ctx_get_module(ctx, name, revision);
719 } else {
720 *mod = (struct lys_module*)ly_ctx_get_module_latest(ctx, name);
721 }
Radek Krejci086c7132018-10-26 15:29:04 +0200722 }
723
Radek Krejci6d6e4e42018-10-29 13:28:19 +0100724 if (!(*mod) || (require_parsed && !(*mod)->parsed)) {
725 (*mod) = NULL;
726
Radek Krejci086c7132018-10-26 15:29:04 +0200727 /* check collision with other implemented revision */
728 if (implement && ly_ctx_get_module_implemented(ctx, name)) {
729 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
730 "Module \"%s\" is already present in other implemented revision.", name);
731 return LY_EDENIED;
732 }
733
Radek Krejci9ed7a192018-10-31 16:23:51 +0100734 /* module not present in the context, get the input data and parse it */
Radek Krejci086c7132018-10-26 15:29:04 +0200735 if (!(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
736search_clb:
737 if (ctx->imp_clb) {
738 if (ctx->imp_clb(name, revision, NULL, NULL, ctx->imp_clb_data,
Radek Krejci9ed7a192018-10-31 16:23:51 +0100739 &format, &module_data, &module_data_free) == LY_SUCCESS) {
740 check_data.name = name;
741 check_data.revision = revision;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100742 *mod = lys_parse_mem_module(ctx, module_data, format, implement,
743 lysp_load_module_check, &check_data);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100744 if (module_data_free) {
745 module_data_free((void*)module_data, ctx->imp_clb_data);
746 }
Radek Krejci096235c2019-01-11 11:12:19 +0100747 if (*mod && implement && lys_compile(*mod, 0)) {
748 ly_set_rm(&ctx->list, *mod, NULL);
749 lys_module_free(*mod, NULL);
750 *mod = NULL;
751 }
Radek Krejci086c7132018-10-26 15:29:04 +0200752 }
753 }
754 if (!(*mod) && !(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
755 goto search_file;
756 }
757 } else {
758search_file:
759 if (!(ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
760 /* module was not received from the callback or there is no callback set */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100761 lys_module_localfile(ctx, name, revision, implement, NULL, (void **)mod);
Radek Krejci086c7132018-10-26 15:29:04 +0200762 }
763 if (!(*mod) && (ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
764 goto search_clb;
765 }
766 }
Radek Krejci9ed7a192018-10-31 16:23:51 +0100767
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100768 if ((*mod) && !revision && ((*mod)->latest_revision == 1)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100769 /* update the latest_revision flag - here we have selected the latest available schema,
770 * consider that even the callback provides correct latest revision */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100771 (*mod)->latest_revision = 2;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100772 }
Radek Krejci086c7132018-10-26 15:29:04 +0200773 } else {
774 /* we have module from the current context */
Radek Krejci0af46292019-01-11 16:02:31 +0100775 if (implement) {
776 m = ly_ctx_get_module_implemented(ctx, name);
777 if (m && m != *mod) {
778 /* check collision with other implemented revision */
779 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
780 "Module \"%s\" is already present in other implemented revision.", name);
781 *mod = NULL;
782 return LY_EDENIED;
783 }
Radek Krejci086c7132018-10-26 15:29:04 +0200784 }
785
786 /* circular check */
Radek Krejcif8f882a2018-10-31 14:51:15 +0100787 if ((*mod)->parsed && (*mod)->parsed->parsing) {
Radek Krejci086c7132018-10-26 15:29:04 +0200788 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (import) for module \"%s\".", name);
789 *mod = NULL;
790 return LY_EVALID;
791 }
792 }
793 if (!(*mod)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100794 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "%s \"%s\" module failed.", implement ? "Loading" : "Importing", name);
Radek Krejci086c7132018-10-26 15:29:04 +0200795 return LY_EVALID;
796 }
797
798 if (implement) {
799 /* mark the module implemented, check for collision was already done */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100800 (*mod)->implemented = 1;
Radek Krejci086c7132018-10-26 15:29:04 +0200801 }
Radek Krejci086c7132018-10-26 15:29:04 +0200802
803 return LY_SUCCESS;
804}
805
806LY_ERR
Radek Krejci3b1f9292018-11-08 10:58:35 +0100807lysp_load_submodule(struct ly_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc)
Radek Krejcid33273d2018-10-25 14:55:52 +0200808{
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100809 struct lysp_submodule *submod;
Radek Krejcid33273d2018-10-25 14:55:52 +0200810 const char *submodule_data = NULL;
811 LYS_INFORMAT format = LYS_IN_UNKNOWN;
812 void (*submodule_data_free)(void *module_data, void *user_data) = NULL;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100813 struct lysp_load_module_check_data check_data = {0};
Radek Krejcid33273d2018-10-25 14:55:52 +0200814
Radek Krejcibbe09a92018-11-08 09:36:54 +0100815 /* submodule not present in the context, get the input data and parse it */
Radek Krejci3b1f9292018-11-08 10:58:35 +0100816 if (!(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcid33273d2018-10-25 14:55:52 +0200817search_clb:
Radek Krejci3b1f9292018-11-08 10:58:35 +0100818 if (ctx->ctx->imp_clb) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100819 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 +0100820 &format, &submodule_data, &submodule_data_free) == LY_SUCCESS) {
821 check_data.name = inc->name;
822 check_data.revision = inc->rev[0] ? inc->rev : NULL;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100823 check_data.submoduleof = mod->mod->name;
824 submod = lys_parse_mem_submodule(ctx->ctx, submodule_data, format, ctx,
825 lysp_load_module_check, &check_data);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100826 if (submodule_data_free) {
Radek Krejci3b1f9292018-11-08 10:58:35 +0100827 submodule_data_free((void*)submodule_data, ctx->ctx->imp_clb_data);
Radek Krejcid33273d2018-10-25 14:55:52 +0200828 }
829 }
Radek Krejcid33273d2018-10-25 14:55:52 +0200830 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100831 if (!submod && !(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100832 goto search_file;
Radek Krejcid33273d2018-10-25 14:55:52 +0200833 }
Radek Krejci2d31ea72018-10-25 15:46:42 +0200834 } else {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100835search_file:
Radek Krejci3b1f9292018-11-08 10:58:35 +0100836 if (!(ctx->ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100837 /* submodule was not received from the callback or there is no callback set */
838 lys_module_localfile(ctx->ctx, inc->name, inc->rev[0] ? inc->rev : NULL, 0, ctx, (void**)&submod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100839 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100840 if (!submod && (ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100841 goto search_clb;
842 }
843 }
844 if (submod) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100845 if (!inc->rev[0] && (submod->latest_revision == 1)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100846 /* update the latest_revision flag - here we have selected the latest available schema,
847 * consider that even the callback provides correct latest revision */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100848 submod->latest_revision = 2;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100849 }
850
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100851 inc->submodule = submod;
Radek Krejcid33273d2018-10-25 14:55:52 +0200852 }
853 if (!inc->submodule) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100854 LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Including \"%s\" submodule into \"%s\" failed.",
855 inc->name, mod->mod->name);
Radek Krejcid33273d2018-10-25 14:55:52 +0200856 return LY_EVALID;
857 }
858
859 return LY_SUCCESS;
860}
861
Radek Krejci01342af2019-01-03 15:18:08 +0100862#define FIND_MODULE(TYPE, MOD) \
Radek Krejcice8c1592018-10-29 15:35:51 +0100863 TYPE *imp; \
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100864 if (!strncmp((MOD)->mod->prefix, prefix, len) && (MOD)->mod->prefix[len] == '\0') { \
Radek Krejcice8c1592018-10-29 15:35:51 +0100865 /* it is the prefix of the module itself */ \
Radek Krejci0af46292019-01-11 16:02:31 +0100866 m = ly_ctx_get_module((MOD)->mod->ctx, (MOD)->mod->name, (MOD)->mod->revision); \
Radek Krejcice8c1592018-10-29 15:35:51 +0100867 } \
868 /* search in imports */ \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100869 if (!m) { \
870 LY_ARRAY_FOR((MOD)->imports, TYPE, imp) { \
Radek Krejci01342af2019-01-03 15:18:08 +0100871 if (!strncmp(imp->prefix, prefix, len) && imp->prefix[len] == '\0') { \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100872 m = imp->module; \
873 break; \
874 } \
Radek Krejcice8c1592018-10-29 15:35:51 +0100875 } \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100876 }
Radek Krejcice8c1592018-10-29 15:35:51 +0100877
Radek Krejcibbe09a92018-11-08 09:36:54 +0100878struct lysc_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100879lysc_module_find_prefix(const struct lysc_module *mod, const char *prefix, size_t len)
Radek Krejci151a5b72018-10-19 14:21:44 +0200880{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100881 const struct lys_module *m = NULL;
882
Radek Krejci01342af2019-01-03 15:18:08 +0100883 FIND_MODULE(struct lysc_import, mod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100884 return m ? m->compiled : NULL;
Radek Krejcice8c1592018-10-29 15:35:51 +0100885}
Radek Krejci151a5b72018-10-19 14:21:44 +0200886
Radek Krejcibbe09a92018-11-08 09:36:54 +0100887struct lysp_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100888lysp_module_find_prefix(const struct lysp_module *mod, const char *prefix, size_t len)
Radek Krejcice8c1592018-10-29 15:35:51 +0100889{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100890 const struct lys_module *m = NULL;
891
Radek Krejci01342af2019-01-03 15:18:08 +0100892 FIND_MODULE(struct lysp_import, mod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100893 return m ? m->parsed : NULL;
Radek Krejcice8c1592018-10-29 15:35:51 +0100894}
Radek Krejci151a5b72018-10-19 14:21:44 +0200895
Radek Krejcice8c1592018-10-29 15:35:51 +0100896struct lys_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100897lys_module_find_prefix(const struct lys_module *mod, const char *prefix, size_t len)
Radek Krejcice8c1592018-10-29 15:35:51 +0100898{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100899 const struct lys_module *m = NULL;
900
Radek Krejcice8c1592018-10-29 15:35:51 +0100901 if (mod->compiled) {
Radek Krejci01342af2019-01-03 15:18:08 +0100902 FIND_MODULE(struct lysc_import, mod->compiled);
Radek Krejcice8c1592018-10-29 15:35:51 +0100903 } else {
Radek Krejci01342af2019-01-03 15:18:08 +0100904 FIND_MODULE(struct lysp_import, mod->parsed);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100905 }
906 return (struct lys_module*)m;
907}
908
Radek Krejcia3045382018-11-22 14:30:31 +0100909const char *
910lys_nodetype2str(uint16_t nodetype)
911{
912 switch(nodetype) {
913 case LYS_CONTAINER:
914 return "container";
915 case LYS_CHOICE:
916 return "choice";
917 case LYS_LEAF:
918 return "leaf";
919 case LYS_LEAFLIST:
920 return "leaf-list";
921 case LYS_LIST:
922 return "list";
923 case LYS_ANYXML:
924 return "anyxml";
925 case LYS_ANYDATA:
926 return "anydata";
Radek Krejcif12a1f02019-02-11 16:42:08 +0100927 case LYS_CASE:
928 return "case";
Radek Krejcia3045382018-11-22 14:30:31 +0100929 default:
930 return "unknown";
931 }
932}
933
Radek Krejci056d0a82018-12-06 16:57:25 +0100934API const struct lysp_tpdf *
935lysp_node_typedefs(const struct lysp_node *node)
936{
Radek Krejci0fb28562018-12-13 15:17:37 +0100937 switch (node->nodetype) {
938 case LYS_CONTAINER:
939 return ((struct lysp_node_container*)node)->typedefs;
940 case LYS_LIST:
941 return ((struct lysp_node_list*)node)->typedefs;
942 case LYS_GROUPING:
943 return ((struct lysp_grp*)node)->typedefs;
944 case LYS_ACTION:
945 return ((struct lysp_action*)node)->typedefs;
946 case LYS_INOUT:
947 return ((struct lysp_action_inout*)node)->typedefs;
948 case LYS_NOTIF:
949 return ((struct lysp_notif*)node)->typedefs;
950 default:
Radek Krejci056d0a82018-12-06 16:57:25 +0100951 return NULL;
952 }
953}
954
Radek Krejci53ea6152018-12-13 15:21:15 +0100955API const struct lysp_grp *
956lysp_node_groupings(const struct lysp_node *node)
957{
958 switch (node->nodetype) {
959 case LYS_CONTAINER:
960 return ((struct lysp_node_container*)node)->groupings;
961 case LYS_LIST:
962 return ((struct lysp_node_list*)node)->groupings;
963 case LYS_GROUPING:
964 return ((struct lysp_grp*)node)->groupings;
965 case LYS_ACTION:
966 return ((struct lysp_action*)node)->groupings;
967 case LYS_INOUT:
968 return ((struct lysp_action_inout*)node)->groupings;
969 case LYS_NOTIF:
970 return ((struct lysp_notif*)node)->groupings;
971 default:
972 return NULL;
973 }
974}
975
Radek Krejcibbe09a92018-11-08 09:36:54 +0100976struct lysp_action **
Radek Krejci056d0a82018-12-06 16:57:25 +0100977lysp_node_actions_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100978{
979 assert(node);
980 switch (node->nodetype) {
981 case LYS_CONTAINER:
982 return &((struct lysp_node_container*)node)->actions;
983 case LYS_LIST:
984 return &((struct lysp_node_list*)node)->actions;
985 case LYS_GROUPING:
986 return &((struct lysp_grp*)node)->actions;
987 case LYS_AUGMENT:
988 return &((struct lysp_augment*)node)->actions;
989 default:
990 return NULL;
991 }
992}
993
Radek Krejci056d0a82018-12-06 16:57:25 +0100994API const struct lysp_action *
995lysp_node_actions(const struct lysp_node *node)
996{
997 struct lysp_action **actions;
998 actions = lysp_node_actions_p((struct lysp_node*)node);
999 if (actions) {
1000 return *actions;
1001 } else {
1002 return NULL;
1003 }
1004}
1005
Radek Krejcibbe09a92018-11-08 09:36:54 +01001006struct lysp_notif **
Radek Krejci056d0a82018-12-06 16:57:25 +01001007lysp_node_notifs_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001008{
1009 assert(node);
1010 switch (node->nodetype) {
1011 case LYS_CONTAINER:
1012 return &((struct lysp_node_container*)node)->notifs;
1013 case LYS_LIST:
1014 return &((struct lysp_node_list*)node)->notifs;
1015 case LYS_GROUPING:
1016 return &((struct lysp_grp*)node)->notifs;
1017 case LYS_AUGMENT:
1018 return &((struct lysp_augment*)node)->notifs;
1019 default:
1020 return NULL;
1021 }
1022}
1023
Radek Krejci056d0a82018-12-06 16:57:25 +01001024API const struct lysp_notif *
1025lysp_node_notifs(const struct lysp_node *node)
1026{
1027 struct lysp_notif **notifs;
1028 notifs = lysp_node_notifs_p((struct lysp_node*)node);
1029 if (notifs) {
1030 return *notifs;
1031 } else {
1032 return NULL;
1033 }
1034}
1035
Radek Krejcibbe09a92018-11-08 09:36:54 +01001036struct lysp_node **
Radek Krejci056d0a82018-12-06 16:57:25 +01001037lysp_node_children_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001038{
1039 assert(node);
1040 switch (node->nodetype) {
1041 case LYS_CONTAINER:
1042 return &((struct lysp_node_container*)node)->child;
1043 case LYS_CHOICE:
1044 return &((struct lysp_node_choice*)node)->child;
1045 case LYS_LIST:
1046 return &((struct lysp_node_list*)node)->child;
1047 case LYS_CASE:
1048 return &((struct lysp_node_case*)node)->child;
1049 case LYS_GROUPING:
1050 return &((struct lysp_grp*)node)->data;
1051 case LYS_AUGMENT:
1052 return &((struct lysp_augment*)node)->child;
1053 case LYS_INOUT:
1054 return &((struct lysp_action_inout*)node)->data;
1055 case LYS_NOTIF:
1056 return &((struct lysp_notif*)node)->data;
1057 default:
1058 return NULL;
1059 }
1060}
1061
Radek Krejci056d0a82018-12-06 16:57:25 +01001062API const struct lysp_node *
1063lysp_node_children(const struct lysp_node *node)
1064{
1065 struct lysp_node **children;
1066 children = lysp_node_children_p((struct lysp_node*)node);
1067 if (children) {
1068 return *children;
1069 } else {
1070 return NULL;
1071 }
1072}
1073
1074struct lysc_action **
1075lysc_node_actions_p(struct lysc_node *node)
1076{
1077 assert(node);
1078 switch (node->nodetype) {
1079 case LYS_CONTAINER:
1080 return &((struct lysc_node_container*)node)->actions;
1081 case LYS_LIST:
1082 return &((struct lysc_node_list*)node)->actions;
1083 default:
1084 return NULL;
1085 }
1086}
1087
1088API const struct lysc_action *
1089lysc_node_actions(const struct lysc_node *node)
1090{
1091 struct lysc_action **actions;
1092 actions = lysc_node_actions_p((struct lysc_node*)node);
1093 if (actions) {
1094 return *actions;
1095 } else {
1096 return NULL;
1097 }
1098}
1099
1100struct lysc_notif **
1101lysc_node_notifs_p(struct lysc_node *node)
1102{
1103 assert(node);
1104 switch (node->nodetype) {
1105 case LYS_CONTAINER:
1106 return &((struct lysc_node_container*)node)->notifs;
1107 case LYS_LIST:
1108 return &((struct lysc_node_list*)node)->notifs;
1109 default:
1110 return NULL;
1111 }
1112}
1113
1114API const struct lysc_notif *
1115lysc_node_notifs(const struct lysc_node *node)
1116{
1117 struct lysc_notif **notifs;
1118 notifs = lysc_node_notifs_p((struct lysc_node*)node);
1119 if (notifs) {
1120 return *notifs;
1121 } else {
1122 return NULL;
1123 }
1124}
1125
Radek Krejcibbe09a92018-11-08 09:36:54 +01001126struct lysc_node **
Radek Krejci056d0a82018-12-06 16:57:25 +01001127lysc_node_children_p(const struct lysc_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001128{
1129 assert(node);
1130 switch (node->nodetype) {
1131 case LYS_CONTAINER:
1132 return &((struct lysc_node_container*)node)->child;
1133 case LYS_CHOICE:
Radek Krejcia3045382018-11-22 14:30:31 +01001134 if (((struct lysc_node_choice*)node)->cases) {
Radek Krejci95710c92019-02-11 15:49:55 +01001135 return &((struct lysc_node_choice*)node)->cases->child;
Radek Krejcia3045382018-11-22 14:30:31 +01001136 } else {
1137 return NULL;
1138 }
Radek Krejci01342af2019-01-03 15:18:08 +01001139 case LYS_CASE:
1140 return &((struct lysc_node_case*)node)->child;
Radek Krejcibbe09a92018-11-08 09:36:54 +01001141 case LYS_LIST:
1142 return &((struct lysc_node_list*)node)->child;
Radek Krejcibbe09a92018-11-08 09:36:54 +01001143/* TODO
1144 case LYS_INOUT:
1145 return &((struct lysc_action_inout*)node)->child;
1146 case LYS_NOTIF:
1147 return &((struct lysc_notif*)node)->child;
1148*/
1149 default:
1150 return NULL;
1151 }
1152}
1153
Radek Krejci056d0a82018-12-06 16:57:25 +01001154API const struct lysc_node *
1155lysc_node_children(const struct lysc_node *node)
Radek Krejcia3045382018-11-22 14:30:31 +01001156{
Radek Krejci056d0a82018-12-06 16:57:25 +01001157 struct lysc_node **children;
1158 children = lysc_node_children_p((struct lysc_node*)node);
1159 if (children) {
1160 return *children;
1161 } else {
Radek Krejcia3045382018-11-22 14:30:31 +01001162 return NULL;
1163 }
1164}
1165
Radek Krejci96a0bfd2018-11-22 15:25:06 +01001166struct lys_module *
1167lysp_find_module(struct ly_ctx *ctx, const struct lysp_module *mod)
1168{
1169 unsigned int u;
1170
1171 for (u = 0; u < ctx->list.count; ++u) {
1172 if (((struct lys_module*)ctx->list.objs[u])->parsed == mod) {
1173 return ((struct lys_module*)ctx->list.objs[u]);
1174 }
1175 }
1176 return NULL;
1177}
1178