blob: b2e1a593b700d8b226593218c5d83924ccef1ea3 [file] [log] [blame]
Radek Krejci86d106e2018-10-18 09:53:19 +02001/**
2 * @file tree_schema_helpers.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Parsing and validation helper functions
5 *
6 * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
Radek Krejci9ed7a192018-10-31 16:23:51 +010014#include "common.h"
Radek Krejci86d106e2018-10-18 09:53:19 +020015
16#include <ctype.h>
Radek Krejci9ed7a192018-10-31 16:23:51 +010017#include <dirent.h>
18#include <errno.h>
19#include <fcntl.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020020#include <limits.h>
Radek Krejci9ed7a192018-10-31 16:23:51 +010021#include <stdlib.h>
22#include <sys/stat.h>
23#include <sys/types.h>
24#include <unistd.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020025#include <time.h>
26
27#include "libyang.h"
Radek Krejci86d106e2018-10-18 09:53:19 +020028#include "tree_schema_internal.h"
29
Radek Krejcia3045382018-11-22 14:30:31 +010030/**
31 * @brief Parse an identifier.
32 *
33 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
34 * identifier = (ALPHA / "_")
35 * *(ALPHA / DIGIT / "_" / "-" / ".")
36 *
37 * @param[in,out] id Identifier to parse. When returned, it points to the first character which is not part of the identifier.
38 * @return LY_ERR value: LY_SUCCESS or LY_EINVAL in case of invalid starting character.
39 */
40static LY_ERR
41lys_parse_id(const char **id)
42{
43 assert(id && *id);
44
Radek Krejcia9026eb2018-12-12 16:04:47 +010045 if (!is_yangidentstartchar(**id)) {
Radek Krejcia3045382018-11-22 14:30:31 +010046 return LY_EINVAL;
47 }
48 ++(*id);
49
Radek Krejcia9026eb2018-12-12 16:04:47 +010050 while (is_yangidentchar(**id)) {
Radek Krejcia3045382018-11-22 14:30:31 +010051 ++(*id);
52 }
53 return LY_SUCCESS;
54}
55
56LY_ERR
57lys_parse_nodeid(const char **id, const char **prefix, size_t *prefix_len, const char **name, size_t *name_len)
58{
59 assert(id && *id);
60 assert(prefix && prefix_len);
61 assert(name && name_len);
62
63 *prefix = *id;
64 *prefix_len = 0;
65 *name = NULL;
66 *name_len = 0;
67
68 LY_CHECK_RET(lys_parse_id(id));
69 if (**id == ':') {
70 /* there is prefix */
71 *prefix_len = *id - *prefix;
72 ++(*id);
73 *name = *id;
74
75 LY_CHECK_RET(lys_parse_id(id));
76 *name_len = *id - *name;
77 } else {
78 /* there is no prefix, so what we have as prefix now is actually the name */
79 *name = *prefix;
80 *name_len = *id - *name;
81 *prefix = NULL;
82 }
83
84 return LY_SUCCESS;
85}
86
Radek Krejci86d106e2018-10-18 09:53:19 +020087LY_ERR
Radek Krejci9bb94eb2018-12-04 16:48:35 +010088lys_resolve_descendant_schema_nodeid(struct lysc_ctx *ctx, const char *nodeid, size_t nodeid_len, const struct lysc_node *context_node,
89 int nodetype, const struct lysc_node **target)
90{
91 LY_ERR ret = LY_EVALID;
92 const char *name, *prefix, *id;
93 const struct lysc_node *context;
94 size_t name_len, prefix_len;
95 const struct lys_module *mod;
96
97 assert(nodeid);
98 assert(context_node);
99 assert(target);
100 *target = NULL;
101
102 id = nodeid;
103 context = context_node;
104 while (*id && (ret = lys_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len)) == LY_SUCCESS) {
105 if (prefix) {
106 mod = lys_module_find_prefix(context_node->module, prefix, prefix_len);
107 if (!mod) {
108 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
109 "Invalid descendant-schema-nodeid value \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
110 id - nodeid, nodeid, prefix_len, prefix, context_node->module->compiled->name);
111 return LY_ENOTFOUND;
112 }
113 } else {
114 mod = context_node->module;
115 }
Radek Krejcia9026eb2018-12-12 16:04:47 +0100116 context = lys_child(context, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100117 if (!context) {
118 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
119 "Invalid descendant-schema-nodeid value \"%.*s\" - target node not found.", id - nodeid, nodeid);
120 return LY_ENOTFOUND;
121 }
Radek Krejci01342af2019-01-03 15:18:08 +0100122 if (!*id || (nodeid_len && ((size_t)(id - nodeid) >= nodeid_len))) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100123 break;
124 }
Radek Krejci01342af2019-01-03 15:18:08 +0100125 if (*id != '/') {
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100126 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
127 "Invalid descendant-schema-nodeid value \"%.*s\" - missing \"/\" as node-identifier separator.",
Radek Krejci665421c2018-12-05 08:03:39 +0100128 id - nodeid + 1, nodeid);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100129 return LY_EVALID;
130 }
131 ++id;
132 }
133
134 if (ret == LY_SUCCESS) {
135 *target = context;
136 if (nodetype && !(context->nodetype & nodetype)) {
137 return LY_EDENIED;
138 }
139 }
140
141 return ret;
142}
143
144LY_ERR
Radek Krejci86d106e2018-10-18 09:53:19 +0200145lysp_check_prefix(struct ly_parser_ctx *ctx, struct lysp_module *module, const char **value)
146{
147 struct lysp_import *i;
148
149 if (module->prefix && &module->prefix != value && !strcmp(module->prefix, *value)) {
150 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE,
151 "Prefix \"%s\" already used as module prefix.", *value);
152 return LY_EEXIST;
153 }
154 if (module->imports) {
155 LY_ARRAY_FOR(module->imports, struct lysp_import, i) {
156 if (i->prefix && &i->prefix != value && !strcmp(i->prefix, *value)) {
157 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE,
158 "Prefix \"%s\" already used to import \"%s\" module.", *value, i->name);
159 return LY_EEXIST;
160 }
161 }
162 }
163 return LY_SUCCESS;
164}
165
166LY_ERR
Radek Krejci4f28eda2018-11-12 11:46:16 +0100167lysc_check_status(struct lysc_ctx *ctx,
168 uint16_t flags1, void *mod1, const char *name1,
169 uint16_t flags2, void *mod2, const char *name2)
170{
171 uint16_t flg1, flg2;
172
173 flg1 = (flags1 & LYS_STATUS_MASK) ? (flags1 & LYS_STATUS_MASK) : LYS_STATUS_CURR;
174 flg2 = (flags2 & LYS_STATUS_MASK) ? (flags2 & LYS_STATUS_MASK) : LYS_STATUS_CURR;
175
176 if ((flg1 < flg2) && (mod1 == mod2)) {
177 if (ctx) {
178 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
179 "A %s definition \"%s\" is not allowed to reference %s definition \"%s\".",
180 flg1 == LYS_STATUS_CURR ? "current" : "deprecated", name1,
181 flg2 == LYS_STATUS_OBSLT ? "obsolete" : "deprecated", name2);
182 }
183 return LY_EVALID;
184 }
185
186 return LY_SUCCESS;
187}
188
189LY_ERR
Radek Krejcibbe09a92018-11-08 09:36:54 +0100190lysp_check_date(struct ly_parser_ctx *ctx, const char *date, int date_len, const char *stmt)
Radek Krejci86d106e2018-10-18 09:53:19 +0200191{
192 int i;
193 struct tm tm, tm_;
194 char *r;
195
Radek Krejcibbe09a92018-11-08 09:36:54 +0100196 LY_CHECK_ARG_RET(ctx ? ctx->ctx : NULL, date, LY_EINVAL);
197 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 +0200198
199 /* check format */
200 for (i = 0; i < date_len; i++) {
201 if (i == 4 || i == 7) {
202 if (date[i] != '-') {
203 goto error;
204 }
205 } else if (!isdigit(date[i])) {
206 goto error;
207 }
208 }
209
210 /* check content, e.g. 2018-02-31 */
211 memset(&tm, 0, sizeof tm);
212 r = strptime(date, "%Y-%m-%d", &tm);
213 if (!r || r != &date[LY_REV_SIZE - 1]) {
214 goto error;
215 }
216 memcpy(&tm_, &tm, sizeof tm);
217 mktime(&tm_); /* mktime modifies tm_ if it refers invalid date */
218 if (tm.tm_mday != tm_.tm_mday) { /* e.g 2018-02-29 -> 2018-03-01 */
219 /* checking days is enough, since other errors
220 * have been checked by strptime() */
221 goto error;
222 }
223
224 return LY_SUCCESS;
225
226error:
Radek Krejcid33273d2018-10-25 14:55:52 +0200227 if (stmt) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100228 if (ctx) {
229 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LY_VCODE_INVAL, date_len, date, stmt);
230 } else {
231 LOGVAL(NULL, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, date_len, date, stmt);
232 }
Radek Krejcid33273d2018-10-25 14:55:52 +0200233 }
Radek Krejci86d106e2018-10-18 09:53:19 +0200234 return LY_EINVAL;
235}
236
237void
238lysp_sort_revisions(struct lysp_revision *revs)
239{
240 uint8_t i, r;
241 struct lysp_revision rev;
242
243 for (i = 1, r = 0; revs && i < LY_ARRAY_SIZE(revs); i++) {
Radek Krejcib7db73a2018-10-24 14:18:40 +0200244 if (strcmp(revs[i].date, revs[r].date) > 0) {
Radek Krejci86d106e2018-10-18 09:53:19 +0200245 r = i;
246 }
247 }
248
249 if (r) {
250 /* the newest revision is not on position 0, switch them */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200251 memcpy(&rev, &revs[0], sizeof rev);
252 memcpy(&revs[0], &revs[r], sizeof rev);
253 memcpy(&revs[r], &rev, sizeof rev);
Radek Krejci86d106e2018-10-18 09:53:19 +0200254 }
255}
Radek Krejci151a5b72018-10-19 14:21:44 +0200256
Radek Krejcibbe09a92018-11-08 09:36:54 +0100257static const struct lysp_tpdf *
258lysp_type_match(const char *name, struct lysp_node *node)
259{
Radek Krejci0fb28562018-12-13 15:17:37 +0100260 const struct lysp_tpdf *typedefs;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100261 unsigned int u;
262
Radek Krejci0fb28562018-12-13 15:17:37 +0100263 typedefs = lysp_node_typedefs(node);
264 LY_ARRAY_FOR(typedefs, u) {
265 if (!strcmp(name, typedefs[u].name)) {
266 /* match */
267 return &typedefs[u];
Radek Krejcibbe09a92018-11-08 09:36:54 +0100268 }
269 }
270
271 return NULL;
272}
273
Radek Krejci4f28eda2018-11-12 11:46:16 +0100274static LY_DATA_TYPE
275lysp_type_str2builtin(const char *name, size_t len)
276{
277 if (len >= 4) { /* otherwise it does not match any built-in type */
278 if (name[0] == 'b') {
279 if (name[1] == 'i') {
280 if (len == 6 && !strncmp(&name[2], "nary", 4)) {
281 return LY_TYPE_BINARY;
282 } else if (len == 4 && !strncmp(&name[2], "ts", 2)) {
283 return LY_TYPE_BITS;
284 }
285 } else if (len == 7 && !strncmp(&name[1], "oolean", 6)) {
286 return LY_TYPE_BOOL;
287 }
288 } else if (name[0] == 'd') {
289 if (len == 9 && !strncmp(&name[1], "ecimal64", 8)) {
290 return LY_TYPE_DEC64;
291 }
292 } else if (name[0] == 'e') {
293 if (len == 5 && !strncmp(&name[1], "mpty", 4)) {
294 return LY_TYPE_EMPTY;
295 } else if (len == 11 && !strncmp(&name[1], "numeration", 10)) {
296 return LY_TYPE_ENUM;
297 }
298 } else if (name[0] == 'i') {
299 if (name[1] == 'n') {
300 if (len == 4 && !strncmp(&name[2], "t8", 2)) {
301 return LY_TYPE_INT8;
302 } else if (len == 5) {
303 if (!strncmp(&name[2], "t16", 3)) {
304 return LY_TYPE_INT16;
305 } else if (!strncmp(&name[2], "t32", 3)) {
306 return LY_TYPE_INT32;
307 } else if (!strncmp(&name[2], "t64", 3)) {
308 return LY_TYPE_INT64;
309 }
310 } else if (len == 19 && !strncmp(&name[2], "stance-identifier", 17)) {
311 return LY_TYPE_INST;
312 }
313 } else if (len == 11 && !strncmp(&name[1], "dentityref", 10)) {
314 return LY_TYPE_IDENT;
315 }
316 } else if (name[0] == 'l') {
317 if (len == 7 && !strncmp(&name[1], "eafref", 6)) {
318 return LY_TYPE_LEAFREF;
319 }
320 } else if (name[0] == 's') {
321 if (len == 6 && !strncmp(&name[1], "tring", 5)) {
322 return LY_TYPE_STRING;
323 }
324 } else if (name[0] == 'u') {
325 if (name[1] == 'n') {
326 if (len == 5 && !strncmp(&name[2], "ion", 3)) {
327 return LY_TYPE_UNION;
328 }
329 } else if (name[1] == 'i' && name[2] == 'n' && name[3] == 't') {
330 if (len == 5 && name[4] == '8') {
331 return LY_TYPE_UINT8;
332 } else if (len == 6) {
333 if (!strncmp(&name[4], "16", 2)) {
334 return LY_TYPE_UINT16;
335 } else if (!strncmp(&name[4], "32", 2)) {
336 return LY_TYPE_UINT32;
337 } else if (!strncmp(&name[4], "64", 2)) {
338 return LY_TYPE_UINT64;
339 }
340 }
341 }
342 }
343 }
344
345 return LY_TYPE_UNKNOWN;
346}
347
Radek Krejcibbe09a92018-11-08 09:36:54 +0100348LY_ERR
349lysp_type_find(const char *id, struct lysp_node *start_node, struct lysp_module *start_module,
Radek Krejci4f28eda2018-11-12 11:46:16 +0100350 LY_DATA_TYPE *type, const struct lysp_tpdf **tpdf, struct lysp_node **node, struct lysp_module **module)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100351{
352 const char *str, *name;
353 struct lysp_tpdf *typedefs;
354 unsigned int u, v;
355
356 assert(id);
357 assert(start_module);
358 assert(tpdf);
359 assert(node);
360 assert(module);
361
Radek Krejci4f28eda2018-11-12 11:46:16 +0100362 *node = NULL;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100363 str = strchr(id, ':');
364 if (str) {
365 *module = lysp_module_find_prefix(start_module, id, str - id);
366 name = str + 1;
Radek Krejci4f28eda2018-11-12 11:46:16 +0100367 *type = LY_TYPE_UNKNOWN;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100368 } else {
369 *module = start_module;
370 name = id;
Radek Krejci4f28eda2018-11-12 11:46:16 +0100371
372 /* check for built-in types */
373 *type = lysp_type_str2builtin(name, strlen(name));
374 if (*type) {
375 *tpdf = NULL;
376 return LY_SUCCESS;
377 }
Radek Krejcibbe09a92018-11-08 09:36:54 +0100378 }
379 LY_CHECK_RET(!(*module), LY_ENOTFOUND);
380
381 if (start_node && *module == start_module) {
382 /* search typedefs in parent's nodes */
383 *node = start_node;
384 while (*node) {
385 *tpdf = lysp_type_match(name, *node);
386 if (*tpdf) {
387 /* match */
388 return LY_SUCCESS;
389 }
390 *node = (*node)->parent;
391 }
392 }
393
394 /* search in top-level typedefs */
395 if ((*module)->typedefs) {
396 LY_ARRAY_FOR((*module)->typedefs, u) {
397 if (!strcmp(name, (*module)->typedefs[u].name)) {
398 /* match */
399 *tpdf = &(*module)->typedefs[u];
400 return LY_SUCCESS;
401 }
402 }
403 }
404
405 /* search in submodules' typedefs */
406 LY_ARRAY_FOR((*module)->includes, u) {
407 typedefs = (*module)->includes[u].submodule->typedefs;
Radek Krejci76b3e962018-12-14 17:01:25 +0100408 LY_ARRAY_FOR(typedefs, v) {
409 if (!strcmp(name, typedefs[v].name)) {
410 /* match */
411 *tpdf = &typedefs[v];
412 return LY_SUCCESS;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100413 }
414 }
415 }
416
417 return LY_ENOTFOUND;
418}
419
420/*
421 * @brief Check name of a new type to avoid name collisions.
422 *
423 * @param[in] ctx Parser context, module where the type is being defined is taken from here.
424 * @param[in] node Schema node where the type is being defined, NULL in case of a top-level typedef.
425 * @param[in] tpdf Typedef definition to check.
426 * @param[in,out] tpdfs_global Initialized hash table to store temporary data between calls. When the module's
427 * typedefs are checked, caller is supposed to free the table.
428 * @param[in,out] tpdfs_global Initialized hash table to store temporary data between calls. When the module's
429 * typedefs are checked, caller is supposed to free the table.
430 * @return LY_EEXIST in case of collision, LY_SUCCESS otherwise.
431 */
432static LY_ERR
Radek Krejci0fb28562018-12-13 15:17:37 +0100433lysp_check_typedef(struct ly_parser_ctx *ctx, struct lysp_node *node, const struct lysp_tpdf *tpdf,
Radek Krejcibbe09a92018-11-08 09:36:54 +0100434 struct hash_table *tpdfs_global, struct hash_table *tpdfs_scoped)
435{
436 struct lysp_node *parent;
437 uint32_t hash;
438 size_t name_len;
439 const char *name;
440 unsigned int u;
Radek Krejci0fb28562018-12-13 15:17:37 +0100441 const struct lysp_tpdf *typedefs;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100442
443 assert(ctx);
444 assert(tpdf);
445
446 name = tpdf->name;
447 name_len = strlen(name);
448
Radek Krejci4f28eda2018-11-12 11:46:16 +0100449 if (lysp_type_str2builtin(name, name_len)) {
450 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
451 "Invalid name \"%s\" of typedef - name collision with a built-in type.", name);
452 return LY_EEXIST;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100453 }
454
455 /* check locally scoped typedefs (avoid name shadowing) */
456 if (node) {
Radek Krejci0fb28562018-12-13 15:17:37 +0100457 typedefs = lysp_node_typedefs(node);
458 LY_ARRAY_FOR(typedefs, u) {
459 if (&typedefs[u] == tpdf) {
460 break;
461 }
462 if (!strcmp(name, typedefs[u].name)) {
463 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
464 "Invalid name \"%s\" of typedef - name collision with sibling type.", name);
465 return LY_EEXIST;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100466 }
467 }
468 /* search typedefs in parent's nodes */
469 for (parent = node->parent; parent; parent = node->parent) {
470 if (lysp_type_match(name, parent)) {
471 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
472 "Invalid name \"%s\" of typedef - name collision with another scoped type.", name);
473 return LY_EEXIST;
474 }
475 }
476 }
477
478 /* check collision with the top-level typedefs */
479 hash = dict_hash(name, name_len);
480 if (node) {
481 lyht_insert(tpdfs_scoped, &name, hash, NULL);
482 if (!lyht_find(tpdfs_global, &name, hash, NULL)) {
483 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
484 "Invalid name \"%s\" of typedef - scoped type collide with a top-level type.", name);
485 return LY_EEXIST;
486 }
487 } else {
488 if (lyht_insert(tpdfs_global, &name, hash, NULL)) {
489 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
490 "Invalid name \"%s\" of typedef - name collision with another top-level type.", name);
491 return LY_EEXIST;
492 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100493 /* it is not necessary to test collision with the scoped types - in lysp_check_typedefs, all the
494 * top-level typedefs are inserted into the tables before the scoped typedefs, so the collision
495 * is detected in the first branch few lines above */
Radek Krejcibbe09a92018-11-08 09:36:54 +0100496 }
497
498 return LY_SUCCESS;
499}
500
501static int
502lysp_id_cmp(void *val1, void *val2, int UNUSED(mod), void *UNUSED(cb_data))
503{
504 return !strcmp(val1, val2);
505}
506
507LY_ERR
508lysp_check_typedefs(struct ly_parser_ctx *ctx)
509{
510 struct hash_table *ids_global;
511 struct hash_table *ids_scoped;
Radek Krejci0fb28562018-12-13 15:17:37 +0100512 const struct lysp_tpdf *typedefs;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100513 unsigned int i, u;
514 LY_ERR ret = LY_EVALID;
515
516 /* check name collisions - typedefs and groupings */
517 ids_global = lyht_new(8, sizeof(char*), lysp_id_cmp, NULL, 1);
518 ids_scoped = lyht_new(8, sizeof(char*), lysp_id_cmp, NULL, 1);
519 LY_ARRAY_FOR(ctx->mod->typedefs, i) {
520 if (lysp_check_typedef(ctx, NULL, &ctx->mod->typedefs[i], ids_global, ids_scoped)) {
521 goto cleanup;
522 }
523 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100524 LY_ARRAY_FOR(ctx->mod->includes, i) {
525 LY_ARRAY_FOR(ctx->mod->includes[i].submodule->typedefs, u) {
526 if (lysp_check_typedef(ctx, NULL, &ctx->mod->includes[i].submodule->typedefs[u], ids_global, ids_scoped)) {
527 goto cleanup;
528 }
529 }
530 }
Radek Krejcibbe09a92018-11-08 09:36:54 +0100531 for (u = 0; u < ctx->tpdfs_nodes.count; ++u) {
Radek Krejci0fb28562018-12-13 15:17:37 +0100532 typedefs = lysp_node_typedefs((struct lysp_node *)ctx->tpdfs_nodes.objs[u]);
533 LY_ARRAY_FOR(typedefs, i) {
534 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 +0100535 goto cleanup;
536 }
537 }
538 }
539 ret = LY_SUCCESS;
540cleanup:
541 lyht_free(ids_global);
542 lyht_free(ids_scoped);
543 ly_set_erase(&ctx->tpdfs_nodes, NULL);
544
545 return ret;
546}
547
Radek Krejci086c7132018-10-26 15:29:04 +0200548void
549lys_module_implement(struct lys_module *mod)
550{
551 assert(mod);
552 if (mod->parsed) {
553 mod->parsed->implemented = 1;
554 }
555 if (mod->compiled) {
556 mod->compiled->implemented = 1;
557 }
558}
559
Radek Krejci9ed7a192018-10-31 16:23:51 +0100560struct lysp_load_module_check_data {
561 const char *name;
562 const char *revision;
563 const char *path;
564 const char* submoduleof;
565};
566
567static LY_ERR
568lysp_load_module_check(struct ly_ctx *ctx, struct lysp_module *mod, void *data)
569{
570 struct lysp_load_module_check_data *info = data;
571 const char *filename, *dot, *rev;
572 size_t len;
573
574 if (info->name) {
575 /* check name of the parsed model */
576 if (strcmp(info->name, mod->name)) {
577 LOGERR(ctx, LY_EINVAL, "Unexpected module \"%s\" parsed instead of \"%s\").", mod->name, info->name);
578 return LY_EINVAL;
579 }
580 }
581 if (info->revision) {
582 /* check revision of the parsed model */
583 if (!mod->revs || strcmp(info->revision, mod->revs[0].date)) {
584 LOGERR(ctx, LY_EINVAL, "Module \"%s\" parsed with the wrong revision (\"%s\" instead \"%s\").", mod->name,
585 mod->revs[0].date, info->revision);
586 return LY_EINVAL;
587 }
588 }
589 if (info->submoduleof) {
590 /* check that we have really a submodule */
591 if (!mod->submodule) {
592 /* submodule is not a submodule */
593 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Included \"%s\" schema from \"%s\" is actually not a submodule.",
594 mod->name, info->submoduleof);
595 return LY_EVALID;
596 }
597 /* check that the submodule belongs-to our module */
598 if (strcmp(info->submoduleof, mod->belongsto)) {
599 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Included \"%s\" submodule from \"%s\" belongs-to a different module \"%s\".",
600 mod->name, info->submoduleof, mod->belongsto);
601 return LY_EVALID;
602 }
603 /* check circular dependency */
604 if (mod->parsing) {
605 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (include) for module \"%s\".", mod->name);
606 return LY_EVALID;
607 }
608 }
609 if (info->path) {
610 /* check that name and revision match filename */
611 filename = strrchr(info->path, '/');
612 if (!filename) {
613 filename = info->path;
614 } else {
615 filename++;
616 }
617 /* name */
618 len = strlen(mod->name);
619 rev = strchr(filename, '@');
620 dot = strrchr(info->path, '.');
621 if (strncmp(filename, mod->name, len) ||
622 ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
623 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, mod->name);
624 }
625 /* revision */
626 if (rev) {
627 len = dot - ++rev;
628 if (!mod->revs || len != 10 || strncmp(mod->revs[0].date, rev, len)) {
629 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
630 mod->revs ? mod->revs[0].date : "none");
631 }
632 }
633 }
634 return LY_SUCCESS;
635}
636
637LY_ERR
Radek Krejci3b1f9292018-11-08 10:58:35 +0100638lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct ly_parser_ctx *main_ctx,
Radek Krejci9ed7a192018-10-31 16:23:51 +0100639 struct lys_module **result)
640{
641 int fd;
642 char *filepath = NULL;
643 LYS_INFORMAT format;
644 struct lys_module *mod = NULL;
645 LY_ERR ret = LY_SUCCESS;
646 struct lysp_load_module_check_data check_data = {0};
647
648 LY_CHECK_RET(lys_search_localfile(ly_ctx_get_searchdirs(ctx), !(ctx->flags & LY_CTX_DISABLE_SEARCHDIR_CWD), name, revision,
649 &filepath, &format));
650 LY_CHECK_ERR_RET(!filepath, LOGERR(ctx, LY_ENOTFOUND, "Data model \"%s%s%s\" not found in local searchdirs.",
651 name, revision ? "@" : "", revision ? revision : ""), LY_ENOTFOUND);
652
653
654 LOGVRB("Loading schema from \"%s\" file.", filepath);
655
656 /* open the file */
657 fd = open(filepath, O_RDONLY);
658 LY_CHECK_ERR_GOTO(fd < 0, LOGERR(ctx, LY_ESYS, "Unable to open data model file \"%s\" (%s).",
659 filepath, strerror(errno)); ret = LY_ESYS, cleanup);
660
661 check_data.name = name;
662 check_data.revision = revision;
663 check_data.path = filepath;
Radek Krejci3b1f9292018-11-08 10:58:35 +0100664 mod = lys_parse_fd_(ctx, fd, format, implement, main_ctx,
Radek Krejci9ed7a192018-10-31 16:23:51 +0100665 lysp_load_module_check, &check_data);
666 close(fd);
667 LY_CHECK_ERR_GOTO(!mod, ly_errcode(ctx), cleanup);
668
669 if (!mod->parsed->filepath) {
670 char rpath[PATH_MAX];
671 if (realpath(filepath, rpath) != NULL) {
672 mod->parsed->filepath = lydict_insert(ctx, rpath, 0);
673 } else {
674 mod->parsed->filepath = lydict_insert(ctx, filepath, 0);
675 }
676 }
677
678 *result = mod;
679
680 /* success */
681cleanup:
682 free(filepath);
683 return ret;
684}
685
Radek Krejcid33273d2018-10-25 14:55:52 +0200686LY_ERR
Radek Krejci6d6e4e42018-10-29 13:28:19 +0100687lysp_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 +0200688{
Radek Krejci9ed7a192018-10-31 16:23:51 +0100689 const char *module_data = NULL;
Radek Krejci086c7132018-10-26 15:29:04 +0200690 LYS_INFORMAT format = LYS_IN_UNKNOWN;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100691 void (*module_data_free)(void *module_data, void *user_data) = NULL;
692 struct lysp_load_module_check_data check_data = {0};
Radek Krejci086c7132018-10-26 15:29:04 +0200693
694 /* try to get the module from the context */
695 if (revision) {
696 *mod = (struct lys_module*)ly_ctx_get_module(ctx, name, revision);
697 } else {
698 *mod = (struct lys_module*)ly_ctx_get_module_latest(ctx, name);
699 }
700
Radek Krejci6d6e4e42018-10-29 13:28:19 +0100701 if (!(*mod) || (require_parsed && !(*mod)->parsed)) {
702 (*mod) = NULL;
703
Radek Krejci086c7132018-10-26 15:29:04 +0200704 /* check collision with other implemented revision */
705 if (implement && ly_ctx_get_module_implemented(ctx, name)) {
706 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
707 "Module \"%s\" is already present in other implemented revision.", name);
708 return LY_EDENIED;
709 }
710
Radek Krejci9ed7a192018-10-31 16:23:51 +0100711 /* module not present in the context, get the input data and parse it */
Radek Krejci086c7132018-10-26 15:29:04 +0200712 if (!(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
713search_clb:
714 if (ctx->imp_clb) {
715 if (ctx->imp_clb(name, revision, NULL, NULL, ctx->imp_clb_data,
Radek Krejci9ed7a192018-10-31 16:23:51 +0100716 &format, &module_data, &module_data_free) == LY_SUCCESS) {
717 check_data.name = name;
718 check_data.revision = revision;
Radek Krejci3b1f9292018-11-08 10:58:35 +0100719 *mod = lys_parse_mem_(ctx, module_data, format, implement, NULL,
Radek Krejci9ed7a192018-10-31 16:23:51 +0100720 lysp_load_module_check, &check_data);
721 if (module_data_free) {
722 module_data_free((void*)module_data, ctx->imp_clb_data);
723 }
Radek Krejci086c7132018-10-26 15:29:04 +0200724 }
725 }
726 if (!(*mod) && !(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
727 goto search_file;
728 }
729 } else {
730search_file:
731 if (!(ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
732 /* module was not received from the callback or there is no callback set */
Radek Krejci3b1f9292018-11-08 10:58:35 +0100733 lys_module_localfile(ctx, name, revision, implement, NULL, mod);
Radek Krejci086c7132018-10-26 15:29:04 +0200734 }
735 if (!(*mod) && (ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
736 goto search_clb;
737 }
738 }
Radek Krejci9ed7a192018-10-31 16:23:51 +0100739
Radek Krejcid14e9692018-11-01 11:00:37 +0100740 if ((*mod) && !revision && ((*mod)->parsed->latest_revision == 1)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100741 /* update the latest_revision flag - here we have selected the latest available schema,
742 * consider that even the callback provides correct latest revision */
743 (*mod)->parsed->latest_revision = 2;
744 }
Radek Krejci086c7132018-10-26 15:29:04 +0200745 } else {
746 /* we have module from the current context */
747 if (implement && (ly_ctx_get_module_implemented(ctx, name) != *mod)) {
748 /* check collision with other implemented revision */
749 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
750 "Module \"%s\" is already present in other implemented revision.", name);
751 *mod = NULL;
752 return LY_EDENIED;
753 }
754
755 /* circular check */
Radek Krejcif8f882a2018-10-31 14:51:15 +0100756 if ((*mod)->parsed && (*mod)->parsed->parsing) {
Radek Krejci086c7132018-10-26 15:29:04 +0200757 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (import) for module \"%s\".", name);
758 *mod = NULL;
759 return LY_EVALID;
760 }
761 }
762 if (!(*mod)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100763 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "%s \"%s\" module failed.", implement ? "Loading" : "Importing", name);
Radek Krejci086c7132018-10-26 15:29:04 +0200764 return LY_EVALID;
765 }
766
767 if (implement) {
768 /* mark the module implemented, check for collision was already done */
769 lys_module_implement(*mod);
770 }
Radek Krejci086c7132018-10-26 15:29:04 +0200771
772 return LY_SUCCESS;
773}
774
775LY_ERR
Radek Krejci3b1f9292018-11-08 10:58:35 +0100776lysp_load_submodule(struct ly_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc)
Radek Krejcid33273d2018-10-25 14:55:52 +0200777{
778 struct lys_module *submod;
779 const char *submodule_data = NULL;
780 LYS_INFORMAT format = LYS_IN_UNKNOWN;
781 void (*submodule_data_free)(void *module_data, void *user_data) = NULL;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100782 struct lysp_load_module_check_data check_data = {0};
Radek Krejcid33273d2018-10-25 14:55:52 +0200783
Radek Krejcibbe09a92018-11-08 09:36:54 +0100784 /* submodule not present in the context, get the input data and parse it */
Radek Krejci3b1f9292018-11-08 10:58:35 +0100785 if (!(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcid33273d2018-10-25 14:55:52 +0200786search_clb:
Radek Krejci3b1f9292018-11-08 10:58:35 +0100787 if (ctx->ctx->imp_clb) {
788 if (ctx->ctx->imp_clb(mod->name, NULL, inc->name, inc->rev[0] ? inc->rev : NULL, ctx->ctx->imp_clb_data,
Radek Krejcibbe09a92018-11-08 09:36:54 +0100789 &format, &submodule_data, &submodule_data_free) == LY_SUCCESS) {
790 check_data.name = inc->name;
791 check_data.revision = inc->rev[0] ? inc->rev : NULL;
792 check_data.submoduleof = mod->name;
Radek Krejci3b1f9292018-11-08 10:58:35 +0100793 submod = lys_parse_mem_(ctx->ctx, submodule_data, format, mod->implemented, ctx,
Radek Krejcibbe09a92018-11-08 09:36:54 +0100794 lysp_load_module_check, &check_data);
795 if (submodule_data_free) {
Radek Krejci3b1f9292018-11-08 10:58:35 +0100796 submodule_data_free((void*)submodule_data, ctx->ctx->imp_clb_data);
Radek Krejcid33273d2018-10-25 14:55:52 +0200797 }
798 }
Radek Krejcid33273d2018-10-25 14:55:52 +0200799 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100800 if (!submod && !(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100801 goto search_file;
Radek Krejcid33273d2018-10-25 14:55:52 +0200802 }
Radek Krejci2d31ea72018-10-25 15:46:42 +0200803 } else {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100804search_file:
Radek Krejci3b1f9292018-11-08 10:58:35 +0100805 if (!(ctx->ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100806 /* module was not received from the callback or there is no callback set */
Radek Krejci3b1f9292018-11-08 10:58:35 +0100807 lys_module_localfile(ctx->ctx, inc->name, inc->rev[0] ? inc->rev : NULL, mod->implemented, ctx, &submod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100808 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100809 if (!submod && (ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100810 goto search_clb;
811 }
812 }
813 if (submod) {
814 if (!inc->rev[0] && (submod->parsed->latest_revision == 1)) {
815 /* update the latest_revision flag - here we have selected the latest available schema,
816 * consider that even the callback provides correct latest revision */
817 submod->parsed->latest_revision = 2;
818 }
819
820 inc->submodule = submod->parsed;
821 free(submod);
Radek Krejcid33273d2018-10-25 14:55:52 +0200822 }
823 if (!inc->submodule) {
Radek Krejci3b1f9292018-11-08 10:58:35 +0100824 LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Including \"%s\" submodule into \"%s\" failed.", inc->name, mod->name);
Radek Krejcid33273d2018-10-25 14:55:52 +0200825 return LY_EVALID;
826 }
827
828 return LY_SUCCESS;
829}
830
Radek Krejci01342af2019-01-03 15:18:08 +0100831#define FIND_MODULE(TYPE, MOD) \
Radek Krejcice8c1592018-10-29 15:35:51 +0100832 TYPE *imp; \
833 if (!strncmp((MOD)->prefix, prefix, len) && (MOD)->prefix[len] == '\0') { \
834 /* it is the prefix of the module itself */ \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100835 m = ly_ctx_get_module((MOD)->ctx, (MOD)->name, ((struct lysc_module*)(MOD))->revision); \
Radek Krejcice8c1592018-10-29 15:35:51 +0100836 } \
837 /* search in imports */ \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100838 if (!m) { \
839 LY_ARRAY_FOR((MOD)->imports, TYPE, imp) { \
Radek Krejci01342af2019-01-03 15:18:08 +0100840 if (!strncmp(imp->prefix, prefix, len) && imp->prefix[len] == '\0') { \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100841 m = imp->module; \
842 break; \
843 } \
Radek Krejcice8c1592018-10-29 15:35:51 +0100844 } \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100845 }
Radek Krejcice8c1592018-10-29 15:35:51 +0100846
Radek Krejcibbe09a92018-11-08 09:36:54 +0100847struct lysc_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100848lysc_module_find_prefix(const struct lysc_module *mod, const char *prefix, size_t len)
Radek Krejci151a5b72018-10-19 14:21:44 +0200849{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100850 const struct lys_module *m = NULL;
851
Radek Krejci01342af2019-01-03 15:18:08 +0100852 FIND_MODULE(struct lysc_import, mod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100853 return m ? m->compiled : NULL;
Radek Krejcice8c1592018-10-29 15:35:51 +0100854}
Radek Krejci151a5b72018-10-19 14:21:44 +0200855
Radek Krejcibbe09a92018-11-08 09:36:54 +0100856struct lysp_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100857lysp_module_find_prefix(const struct lysp_module *mod, const char *prefix, size_t len)
Radek Krejcice8c1592018-10-29 15:35:51 +0100858{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100859 const struct lys_module *m = NULL;
860
Radek Krejci01342af2019-01-03 15:18:08 +0100861 FIND_MODULE(struct lysp_import, mod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100862 return m ? m->parsed : NULL;
Radek Krejcice8c1592018-10-29 15:35:51 +0100863}
Radek Krejci151a5b72018-10-19 14:21:44 +0200864
Radek Krejcice8c1592018-10-29 15:35:51 +0100865struct lys_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100866lys_module_find_prefix(const struct lys_module *mod, const char *prefix, size_t len)
Radek Krejcice8c1592018-10-29 15:35:51 +0100867{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100868 const struct lys_module *m = NULL;
869
Radek Krejcice8c1592018-10-29 15:35:51 +0100870 if (mod->compiled) {
Radek Krejci01342af2019-01-03 15:18:08 +0100871 FIND_MODULE(struct lysc_import, mod->compiled);
Radek Krejcice8c1592018-10-29 15:35:51 +0100872 } else {
Radek Krejci01342af2019-01-03 15:18:08 +0100873 FIND_MODULE(struct lysp_import, mod->parsed);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100874 }
875 return (struct lys_module*)m;
876}
877
Radek Krejcia3045382018-11-22 14:30:31 +0100878const char *
879lys_nodetype2str(uint16_t nodetype)
880{
881 switch(nodetype) {
882 case LYS_CONTAINER:
883 return "container";
884 case LYS_CHOICE:
885 return "choice";
886 case LYS_LEAF:
887 return "leaf";
888 case LYS_LEAFLIST:
889 return "leaf-list";
890 case LYS_LIST:
891 return "list";
892 case LYS_ANYXML:
893 return "anyxml";
894 case LYS_ANYDATA:
895 return "anydata";
896 default:
897 return "unknown";
898 }
899}
900
Radek Krejci056d0a82018-12-06 16:57:25 +0100901API const struct lysp_tpdf *
902lysp_node_typedefs(const struct lysp_node *node)
903{
Radek Krejci0fb28562018-12-13 15:17:37 +0100904 switch (node->nodetype) {
905 case LYS_CONTAINER:
906 return ((struct lysp_node_container*)node)->typedefs;
907 case LYS_LIST:
908 return ((struct lysp_node_list*)node)->typedefs;
909 case LYS_GROUPING:
910 return ((struct lysp_grp*)node)->typedefs;
911 case LYS_ACTION:
912 return ((struct lysp_action*)node)->typedefs;
913 case LYS_INOUT:
914 return ((struct lysp_action_inout*)node)->typedefs;
915 case LYS_NOTIF:
916 return ((struct lysp_notif*)node)->typedefs;
917 default:
Radek Krejci056d0a82018-12-06 16:57:25 +0100918 return NULL;
919 }
920}
921
Radek Krejci53ea6152018-12-13 15:21:15 +0100922API const struct lysp_grp *
923lysp_node_groupings(const struct lysp_node *node)
924{
925 switch (node->nodetype) {
926 case LYS_CONTAINER:
927 return ((struct lysp_node_container*)node)->groupings;
928 case LYS_LIST:
929 return ((struct lysp_node_list*)node)->groupings;
930 case LYS_GROUPING:
931 return ((struct lysp_grp*)node)->groupings;
932 case LYS_ACTION:
933 return ((struct lysp_action*)node)->groupings;
934 case LYS_INOUT:
935 return ((struct lysp_action_inout*)node)->groupings;
936 case LYS_NOTIF:
937 return ((struct lysp_notif*)node)->groupings;
938 default:
939 return NULL;
940 }
941}
942
Radek Krejcibbe09a92018-11-08 09:36:54 +0100943struct lysp_action **
Radek Krejci056d0a82018-12-06 16:57:25 +0100944lysp_node_actions_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100945{
946 assert(node);
947 switch (node->nodetype) {
948 case LYS_CONTAINER:
949 return &((struct lysp_node_container*)node)->actions;
950 case LYS_LIST:
951 return &((struct lysp_node_list*)node)->actions;
952 case LYS_GROUPING:
953 return &((struct lysp_grp*)node)->actions;
954 case LYS_AUGMENT:
955 return &((struct lysp_augment*)node)->actions;
956 default:
957 return NULL;
958 }
959}
960
Radek Krejci056d0a82018-12-06 16:57:25 +0100961API const struct lysp_action *
962lysp_node_actions(const struct lysp_node *node)
963{
964 struct lysp_action **actions;
965 actions = lysp_node_actions_p((struct lysp_node*)node);
966 if (actions) {
967 return *actions;
968 } else {
969 return NULL;
970 }
971}
972
Radek Krejcibbe09a92018-11-08 09:36:54 +0100973struct lysp_notif **
Radek Krejci056d0a82018-12-06 16:57:25 +0100974lysp_node_notifs_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100975{
976 assert(node);
977 switch (node->nodetype) {
978 case LYS_CONTAINER:
979 return &((struct lysp_node_container*)node)->notifs;
980 case LYS_LIST:
981 return &((struct lysp_node_list*)node)->notifs;
982 case LYS_GROUPING:
983 return &((struct lysp_grp*)node)->notifs;
984 case LYS_AUGMENT:
985 return &((struct lysp_augment*)node)->notifs;
986 default:
987 return NULL;
988 }
989}
990
Radek Krejci056d0a82018-12-06 16:57:25 +0100991API const struct lysp_notif *
992lysp_node_notifs(const struct lysp_node *node)
993{
994 struct lysp_notif **notifs;
995 notifs = lysp_node_notifs_p((struct lysp_node*)node);
996 if (notifs) {
997 return *notifs;
998 } else {
999 return NULL;
1000 }
1001}
1002
Radek Krejcibbe09a92018-11-08 09:36:54 +01001003struct lysp_node **
Radek Krejci056d0a82018-12-06 16:57:25 +01001004lysp_node_children_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001005{
1006 assert(node);
1007 switch (node->nodetype) {
1008 case LYS_CONTAINER:
1009 return &((struct lysp_node_container*)node)->child;
1010 case LYS_CHOICE:
1011 return &((struct lysp_node_choice*)node)->child;
1012 case LYS_LIST:
1013 return &((struct lysp_node_list*)node)->child;
1014 case LYS_CASE:
1015 return &((struct lysp_node_case*)node)->child;
1016 case LYS_GROUPING:
1017 return &((struct lysp_grp*)node)->data;
1018 case LYS_AUGMENT:
1019 return &((struct lysp_augment*)node)->child;
1020 case LYS_INOUT:
1021 return &((struct lysp_action_inout*)node)->data;
1022 case LYS_NOTIF:
1023 return &((struct lysp_notif*)node)->data;
1024 default:
1025 return NULL;
1026 }
1027}
1028
Radek Krejci056d0a82018-12-06 16:57:25 +01001029API const struct lysp_node *
1030lysp_node_children(const struct lysp_node *node)
1031{
1032 struct lysp_node **children;
1033 children = lysp_node_children_p((struct lysp_node*)node);
1034 if (children) {
1035 return *children;
1036 } else {
1037 return NULL;
1038 }
1039}
1040
1041struct lysc_action **
1042lysc_node_actions_p(struct lysc_node *node)
1043{
1044 assert(node);
1045 switch (node->nodetype) {
1046 case LYS_CONTAINER:
1047 return &((struct lysc_node_container*)node)->actions;
1048 case LYS_LIST:
1049 return &((struct lysc_node_list*)node)->actions;
1050 default:
1051 return NULL;
1052 }
1053}
1054
1055API const struct lysc_action *
1056lysc_node_actions(const struct lysc_node *node)
1057{
1058 struct lysc_action **actions;
1059 actions = lysc_node_actions_p((struct lysc_node*)node);
1060 if (actions) {
1061 return *actions;
1062 } else {
1063 return NULL;
1064 }
1065}
1066
1067struct lysc_notif **
1068lysc_node_notifs_p(struct lysc_node *node)
1069{
1070 assert(node);
1071 switch (node->nodetype) {
1072 case LYS_CONTAINER:
1073 return &((struct lysc_node_container*)node)->notifs;
1074 case LYS_LIST:
1075 return &((struct lysc_node_list*)node)->notifs;
1076 default:
1077 return NULL;
1078 }
1079}
1080
1081API const struct lysc_notif *
1082lysc_node_notifs(const struct lysc_node *node)
1083{
1084 struct lysc_notif **notifs;
1085 notifs = lysc_node_notifs_p((struct lysc_node*)node);
1086 if (notifs) {
1087 return *notifs;
1088 } else {
1089 return NULL;
1090 }
1091}
1092
Radek Krejcibbe09a92018-11-08 09:36:54 +01001093struct lysc_node **
Radek Krejci056d0a82018-12-06 16:57:25 +01001094lysc_node_children_p(const struct lysc_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001095{
1096 assert(node);
1097 switch (node->nodetype) {
1098 case LYS_CONTAINER:
1099 return &((struct lysc_node_container*)node)->child;
1100 case LYS_CHOICE:
Radek Krejcia3045382018-11-22 14:30:31 +01001101 if (((struct lysc_node_choice*)node)->cases) {
1102 return &((struct lysc_node_choice*)node)->cases[0].child;
1103 } else {
1104 return NULL;
1105 }
Radek Krejci01342af2019-01-03 15:18:08 +01001106 case LYS_CASE:
1107 return &((struct lysc_node_case*)node)->child;
Radek Krejcibbe09a92018-11-08 09:36:54 +01001108 case LYS_LIST:
1109 return &((struct lysc_node_list*)node)->child;
Radek Krejcibbe09a92018-11-08 09:36:54 +01001110/* TODO
1111 case LYS_INOUT:
1112 return &((struct lysc_action_inout*)node)->child;
1113 case LYS_NOTIF:
1114 return &((struct lysc_notif*)node)->child;
1115*/
1116 default:
1117 return NULL;
1118 }
1119}
1120
Radek Krejci056d0a82018-12-06 16:57:25 +01001121API const struct lysc_node *
1122lysc_node_children(const struct lysc_node *node)
Radek Krejcia3045382018-11-22 14:30:31 +01001123{
Radek Krejci056d0a82018-12-06 16:57:25 +01001124 struct lysc_node **children;
1125 children = lysc_node_children_p((struct lysc_node*)node);
1126 if (children) {
1127 return *children;
1128 } else {
Radek Krejcia3045382018-11-22 14:30:31 +01001129 return NULL;
1130 }
1131}
1132
Radek Krejci96a0bfd2018-11-22 15:25:06 +01001133struct lys_module *
1134lysp_find_module(struct ly_ctx *ctx, const struct lysp_module *mod)
1135{
1136 unsigned int u;
1137
1138 for (u = 0; u < ctx->list.count; ++u) {
1139 if (((struct lys_module*)ctx->list.objs[u])->parsed == mod) {
1140 return ((struct lys_module*)ctx->list.objs[u]);
1141 }
1142 }
1143 return NULL;
1144}
1145