blob: 6b89cb3541565c7f9156249c41c1893382bf58b3 [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 Krejci6eeb58f2019-02-22 16:29:37 +010089 const struct lys_module *context_module, int nodetype, int implement,
90 const struct lysc_node **target, uint16_t *result_flag)
Radek Krejci9bb94eb2018-12-04 16:48:35 +010091{
92 LY_ERR ret = LY_EVALID;
93 const char *name, *prefix, *id;
Radek Krejci9bb94eb2018-12-04 16:48:35 +010094 size_t name_len, prefix_len;
Radek Krejci7af64242019-02-18 13:07:53 +010095 const struct lys_module *mod;
Radek Krejci95710c92019-02-11 15:49:55 +010096 const char *nodeid_type;
Radek Krejci6eeb58f2019-02-22 16:29:37 +010097 int getnext_extra_flag = 0;
Radek Krejci9bb94eb2018-12-04 16:48:35 +010098
99 assert(nodeid);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100100 assert(target);
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100101 assert(result_flag);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100102 *target = NULL;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100103 *result_flag = 0;
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100104
105 id = nodeid;
Radek Krejci95710c92019-02-11 15:49:55 +0100106
107 if (context_node) {
108 /* descendant-schema-nodeid */
109 nodeid_type = "descendant";
Radek Krejci3641f562019-02-13 15:38:40 +0100110
111 if (*id == '/') {
112 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
113 "Invalid descendant-schema-nodeid value \"%.*s\" - absolute-schema-nodeid used.",
114 nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
115 return LY_EVALID;
116 }
Radek Krejci95710c92019-02-11 15:49:55 +0100117 } else {
118 /* absolute-schema-nodeid */
119 nodeid_type = "absolute";
Radek Krejci95710c92019-02-11 15:49:55 +0100120
121 if (*id != '/') {
122 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
123 "Invalid absolute-schema-nodeid value \"%.*s\" - missing starting \"/\".",
Radek Krejci3641f562019-02-13 15:38:40 +0100124 nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
Radek Krejci95710c92019-02-11 15:49:55 +0100125 return LY_EVALID;
126 }
127 ++id;
128 }
129
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100130 while (*id && (ret = lys_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len)) == LY_SUCCESS) {
131 if (prefix) {
Radek Krejci95710c92019-02-11 15:49:55 +0100132 mod = lys_module_find_prefix(context_module, prefix, prefix_len);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100133 if (!mod) {
134 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Radek Krejci95710c92019-02-11 15:49:55 +0100135 "Invalid %s-schema-nodeid value \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
136 nodeid_type, id - nodeid, nodeid, prefix_len, prefix, context_module->name);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100137 return LY_ENOTFOUND;
138 }
139 } else {
Radek Krejci95710c92019-02-11 15:49:55 +0100140 mod = context_module;
141 }
142 if (implement && !mod->implemented) {
143 /* make the module implemented */
144 ly_ctx_module_implement_internal(ctx->ctx, (struct lys_module*)mod, 2);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100145 }
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100146 if (context_node && context_node->nodetype == LYS_ACTION) {
147 /* move through input/output manually */
148 if (!strncmp("input", name, name_len)) {
149 (*result_flag) |= LYSC_OPT_RPC_INPUT;
150 } else if (!strncmp("input", name, name_len)) {
151 (*result_flag) |= LYSC_OPT_RPC_OUTPUT;
152 getnext_extra_flag = LYS_GETNEXT_OUTPUT;
153 }
154 } else {
155 context_node = lys_child(context_node, mod, name, name_len, 0,
156 getnext_extra_flag | LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE);
157 if (!context_node) {
158 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
159 "Invalid %s-schema-nodeid value \"%.*s\" - target node not found.", nodeid_type, id - nodeid, nodeid);
160 return LY_ENOTFOUND;
161 }
162 getnext_extra_flag = 0;
163
164 if (context_node->nodetype == LYS_NOTIF) {
165 (*result_flag) |= LYSC_OPT_NOTIFICATION;
166 }
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100167 }
Radek Krejci01342af2019-01-03 15:18:08 +0100168 if (!*id || (nodeid_len && ((size_t)(id - nodeid) >= nodeid_len))) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100169 break;
170 }
Radek Krejci01342af2019-01-03 15:18:08 +0100171 if (*id != '/') {
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100172 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Radek Krejci95710c92019-02-11 15:49:55 +0100173 "Invalid %s-schema-nodeid value \"%.*s\" - missing \"/\" as node-identifier separator.",
174 nodeid_type, id - nodeid + 1, nodeid);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100175 return LY_EVALID;
176 }
177 ++id;
178 }
179
180 if (ret == LY_SUCCESS) {
Radek Krejci7af64242019-02-18 13:07:53 +0100181 *target = context_node;
182 if (nodetype && !(context_node->nodetype & nodetype)) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100183 return LY_EDENIED;
184 }
Radek Krejci95710c92019-02-11 15:49:55 +0100185 } else {
186 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
187 "Invalid %s-schema-nodeid value \"%.*s\" - unexpected end of expression.",
Radek Krejci3641f562019-02-13 15:38:40 +0100188 nodeid_type, nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100189 }
190
191 return ret;
192}
193
194LY_ERR
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100195lysp_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 +0200196{
197 struct lysp_import *i;
198
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100199 if (module_prefix && &module_prefix != value && !strcmp(module_prefix, *value)) {
Radek Krejci86d106e2018-10-18 09:53:19 +0200200 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE,
201 "Prefix \"%s\" already used as module prefix.", *value);
202 return LY_EEXIST;
203 }
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100204 LY_ARRAY_FOR(imports, struct lysp_import, i) {
205 if (i->prefix && &i->prefix != value && !strcmp(i->prefix, *value)) {
206 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Prefix \"%s\" already used to import \"%s\" module.",
207 *value, i->name);
208 return LY_EEXIST;
Radek Krejci86d106e2018-10-18 09:53:19 +0200209 }
210 }
211 return LY_SUCCESS;
212}
213
214LY_ERR
Radek Krejci4f28eda2018-11-12 11:46:16 +0100215lysc_check_status(struct lysc_ctx *ctx,
216 uint16_t flags1, void *mod1, const char *name1,
217 uint16_t flags2, void *mod2, const char *name2)
218{
219 uint16_t flg1, flg2;
220
221 flg1 = (flags1 & LYS_STATUS_MASK) ? (flags1 & LYS_STATUS_MASK) : LYS_STATUS_CURR;
222 flg2 = (flags2 & LYS_STATUS_MASK) ? (flags2 & LYS_STATUS_MASK) : LYS_STATUS_CURR;
223
224 if ((flg1 < flg2) && (mod1 == mod2)) {
225 if (ctx) {
226 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
227 "A %s definition \"%s\" is not allowed to reference %s definition \"%s\".",
228 flg1 == LYS_STATUS_CURR ? "current" : "deprecated", name1,
229 flg2 == LYS_STATUS_OBSLT ? "obsolete" : "deprecated", name2);
230 }
231 return LY_EVALID;
232 }
233
234 return LY_SUCCESS;
235}
236
237LY_ERR
Radek Krejcibbe09a92018-11-08 09:36:54 +0100238lysp_check_date(struct ly_parser_ctx *ctx, const char *date, int date_len, const char *stmt)
Radek Krejci86d106e2018-10-18 09:53:19 +0200239{
240 int i;
241 struct tm tm, tm_;
242 char *r;
243
Radek Krejcibbe09a92018-11-08 09:36:54 +0100244 LY_CHECK_ARG_RET(ctx ? ctx->ctx : NULL, date, LY_EINVAL);
245 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 +0200246
247 /* check format */
248 for (i = 0; i < date_len; i++) {
249 if (i == 4 || i == 7) {
250 if (date[i] != '-') {
251 goto error;
252 }
253 } else if (!isdigit(date[i])) {
254 goto error;
255 }
256 }
257
258 /* check content, e.g. 2018-02-31 */
259 memset(&tm, 0, sizeof tm);
260 r = strptime(date, "%Y-%m-%d", &tm);
261 if (!r || r != &date[LY_REV_SIZE - 1]) {
262 goto error;
263 }
264 memcpy(&tm_, &tm, sizeof tm);
265 mktime(&tm_); /* mktime modifies tm_ if it refers invalid date */
266 if (tm.tm_mday != tm_.tm_mday) { /* e.g 2018-02-29 -> 2018-03-01 */
267 /* checking days is enough, since other errors
268 * have been checked by strptime() */
269 goto error;
270 }
271
272 return LY_SUCCESS;
273
274error:
Radek Krejcid33273d2018-10-25 14:55:52 +0200275 if (stmt) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100276 if (ctx) {
277 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LY_VCODE_INVAL, date_len, date, stmt);
278 } else {
279 LOGVAL(NULL, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, date_len, date, stmt);
280 }
Radek Krejcid33273d2018-10-25 14:55:52 +0200281 }
Radek Krejci86d106e2018-10-18 09:53:19 +0200282 return LY_EINVAL;
283}
284
285void
286lysp_sort_revisions(struct lysp_revision *revs)
287{
288 uint8_t i, r;
289 struct lysp_revision rev;
290
291 for (i = 1, r = 0; revs && i < LY_ARRAY_SIZE(revs); i++) {
Radek Krejcib7db73a2018-10-24 14:18:40 +0200292 if (strcmp(revs[i].date, revs[r].date) > 0) {
Radek Krejci86d106e2018-10-18 09:53:19 +0200293 r = i;
294 }
295 }
296
297 if (r) {
298 /* the newest revision is not on position 0, switch them */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200299 memcpy(&rev, &revs[0], sizeof rev);
300 memcpy(&revs[0], &revs[r], sizeof rev);
301 memcpy(&revs[r], &rev, sizeof rev);
Radek Krejci86d106e2018-10-18 09:53:19 +0200302 }
303}
Radek Krejci151a5b72018-10-19 14:21:44 +0200304
Radek Krejcibbe09a92018-11-08 09:36:54 +0100305static const struct lysp_tpdf *
306lysp_type_match(const char *name, struct lysp_node *node)
307{
Radek Krejci0fb28562018-12-13 15:17:37 +0100308 const struct lysp_tpdf *typedefs;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100309 unsigned int u;
310
Radek Krejci0fb28562018-12-13 15:17:37 +0100311 typedefs = lysp_node_typedefs(node);
312 LY_ARRAY_FOR(typedefs, u) {
313 if (!strcmp(name, typedefs[u].name)) {
314 /* match */
315 return &typedefs[u];
Radek Krejcibbe09a92018-11-08 09:36:54 +0100316 }
317 }
318
319 return NULL;
320}
321
Radek Krejci4f28eda2018-11-12 11:46:16 +0100322static LY_DATA_TYPE
323lysp_type_str2builtin(const char *name, size_t len)
324{
325 if (len >= 4) { /* otherwise it does not match any built-in type */
326 if (name[0] == 'b') {
327 if (name[1] == 'i') {
328 if (len == 6 && !strncmp(&name[2], "nary", 4)) {
329 return LY_TYPE_BINARY;
330 } else if (len == 4 && !strncmp(&name[2], "ts", 2)) {
331 return LY_TYPE_BITS;
332 }
333 } else if (len == 7 && !strncmp(&name[1], "oolean", 6)) {
334 return LY_TYPE_BOOL;
335 }
336 } else if (name[0] == 'd') {
337 if (len == 9 && !strncmp(&name[1], "ecimal64", 8)) {
338 return LY_TYPE_DEC64;
339 }
340 } else if (name[0] == 'e') {
341 if (len == 5 && !strncmp(&name[1], "mpty", 4)) {
342 return LY_TYPE_EMPTY;
343 } else if (len == 11 && !strncmp(&name[1], "numeration", 10)) {
344 return LY_TYPE_ENUM;
345 }
346 } else if (name[0] == 'i') {
347 if (name[1] == 'n') {
348 if (len == 4 && !strncmp(&name[2], "t8", 2)) {
349 return LY_TYPE_INT8;
350 } else if (len == 5) {
351 if (!strncmp(&name[2], "t16", 3)) {
352 return LY_TYPE_INT16;
353 } else if (!strncmp(&name[2], "t32", 3)) {
354 return LY_TYPE_INT32;
355 } else if (!strncmp(&name[2], "t64", 3)) {
356 return LY_TYPE_INT64;
357 }
358 } else if (len == 19 && !strncmp(&name[2], "stance-identifier", 17)) {
359 return LY_TYPE_INST;
360 }
361 } else if (len == 11 && !strncmp(&name[1], "dentityref", 10)) {
362 return LY_TYPE_IDENT;
363 }
364 } else if (name[0] == 'l') {
365 if (len == 7 && !strncmp(&name[1], "eafref", 6)) {
366 return LY_TYPE_LEAFREF;
367 }
368 } else if (name[0] == 's') {
369 if (len == 6 && !strncmp(&name[1], "tring", 5)) {
370 return LY_TYPE_STRING;
371 }
372 } else if (name[0] == 'u') {
373 if (name[1] == 'n') {
374 if (len == 5 && !strncmp(&name[2], "ion", 3)) {
375 return LY_TYPE_UNION;
376 }
377 } else if (name[1] == 'i' && name[2] == 'n' && name[3] == 't') {
378 if (len == 5 && name[4] == '8') {
379 return LY_TYPE_UINT8;
380 } else if (len == 6) {
381 if (!strncmp(&name[4], "16", 2)) {
382 return LY_TYPE_UINT16;
383 } else if (!strncmp(&name[4], "32", 2)) {
384 return LY_TYPE_UINT32;
385 } else if (!strncmp(&name[4], "64", 2)) {
386 return LY_TYPE_UINT64;
387 }
388 }
389 }
390 }
391 }
392
393 return LY_TYPE_UNKNOWN;
394}
395
Radek Krejcibbe09a92018-11-08 09:36:54 +0100396LY_ERR
397lysp_type_find(const char *id, struct lysp_node *start_node, struct lysp_module *start_module,
Radek Krejci4f28eda2018-11-12 11:46:16 +0100398 LY_DATA_TYPE *type, const struct lysp_tpdf **tpdf, struct lysp_node **node, struct lysp_module **module)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100399{
400 const char *str, *name;
401 struct lysp_tpdf *typedefs;
402 unsigned int u, v;
403
404 assert(id);
405 assert(start_module);
406 assert(tpdf);
407 assert(node);
408 assert(module);
409
Radek Krejci4f28eda2018-11-12 11:46:16 +0100410 *node = NULL;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100411 str = strchr(id, ':');
412 if (str) {
413 *module = lysp_module_find_prefix(start_module, id, str - id);
414 name = str + 1;
Radek Krejci4f28eda2018-11-12 11:46:16 +0100415 *type = LY_TYPE_UNKNOWN;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100416 } else {
417 *module = start_module;
418 name = id;
Radek Krejci4f28eda2018-11-12 11:46:16 +0100419
420 /* check for built-in types */
421 *type = lysp_type_str2builtin(name, strlen(name));
422 if (*type) {
423 *tpdf = NULL;
424 return LY_SUCCESS;
425 }
Radek Krejcibbe09a92018-11-08 09:36:54 +0100426 }
427 LY_CHECK_RET(!(*module), LY_ENOTFOUND);
428
429 if (start_node && *module == start_module) {
430 /* search typedefs in parent's nodes */
431 *node = start_node;
432 while (*node) {
433 *tpdf = lysp_type_match(name, *node);
434 if (*tpdf) {
435 /* match */
436 return LY_SUCCESS;
437 }
438 *node = (*node)->parent;
439 }
440 }
441
442 /* search in top-level typedefs */
443 if ((*module)->typedefs) {
444 LY_ARRAY_FOR((*module)->typedefs, u) {
445 if (!strcmp(name, (*module)->typedefs[u].name)) {
446 /* match */
447 *tpdf = &(*module)->typedefs[u];
448 return LY_SUCCESS;
449 }
450 }
451 }
452
453 /* search in submodules' typedefs */
454 LY_ARRAY_FOR((*module)->includes, u) {
455 typedefs = (*module)->includes[u].submodule->typedefs;
Radek Krejci76b3e962018-12-14 17:01:25 +0100456 LY_ARRAY_FOR(typedefs, v) {
457 if (!strcmp(name, typedefs[v].name)) {
458 /* match */
459 *tpdf = &typedefs[v];
460 return LY_SUCCESS;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100461 }
462 }
463 }
464
465 return LY_ENOTFOUND;
466}
467
468/*
469 * @brief Check name of a new type to avoid name collisions.
470 *
471 * @param[in] ctx Parser context, module where the type is being defined is taken from here.
472 * @param[in] node Schema node where the type is being defined, NULL in case of a top-level typedef.
473 * @param[in] tpdf Typedef definition to check.
474 * @param[in,out] tpdfs_global Initialized hash table to store temporary data between calls. When the module's
475 * typedefs are checked, caller is supposed to free the table.
476 * @param[in,out] tpdfs_global Initialized hash table to store temporary data between calls. When the module's
477 * typedefs are checked, caller is supposed to free the table.
478 * @return LY_EEXIST in case of collision, LY_SUCCESS otherwise.
479 */
480static LY_ERR
Radek Krejci0fb28562018-12-13 15:17:37 +0100481lysp_check_typedef(struct ly_parser_ctx *ctx, struct lysp_node *node, const struct lysp_tpdf *tpdf,
Radek Krejcibbe09a92018-11-08 09:36:54 +0100482 struct hash_table *tpdfs_global, struct hash_table *tpdfs_scoped)
483{
484 struct lysp_node *parent;
485 uint32_t hash;
486 size_t name_len;
487 const char *name;
488 unsigned int u;
Radek Krejci0fb28562018-12-13 15:17:37 +0100489 const struct lysp_tpdf *typedefs;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100490
491 assert(ctx);
492 assert(tpdf);
493
494 name = tpdf->name;
495 name_len = strlen(name);
496
Radek Krejci4f28eda2018-11-12 11:46:16 +0100497 if (lysp_type_str2builtin(name, name_len)) {
498 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
499 "Invalid name \"%s\" of typedef - name collision with a built-in type.", name);
500 return LY_EEXIST;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100501 }
502
503 /* check locally scoped typedefs (avoid name shadowing) */
504 if (node) {
Radek Krejci0fb28562018-12-13 15:17:37 +0100505 typedefs = lysp_node_typedefs(node);
506 LY_ARRAY_FOR(typedefs, u) {
507 if (&typedefs[u] == tpdf) {
508 break;
509 }
510 if (!strcmp(name, typedefs[u].name)) {
511 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
512 "Invalid name \"%s\" of typedef - name collision with sibling type.", name);
513 return LY_EEXIST;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100514 }
515 }
516 /* search typedefs in parent's nodes */
517 for (parent = node->parent; parent; parent = node->parent) {
518 if (lysp_type_match(name, parent)) {
519 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
520 "Invalid name \"%s\" of typedef - name collision with another scoped type.", name);
521 return LY_EEXIST;
522 }
523 }
524 }
525
526 /* check collision with the top-level typedefs */
527 hash = dict_hash(name, name_len);
528 if (node) {
529 lyht_insert(tpdfs_scoped, &name, hash, NULL);
530 if (!lyht_find(tpdfs_global, &name, hash, NULL)) {
531 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
532 "Invalid name \"%s\" of typedef - scoped type collide with a top-level type.", name);
533 return LY_EEXIST;
534 }
535 } else {
536 if (lyht_insert(tpdfs_global, &name, hash, NULL)) {
537 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
538 "Invalid name \"%s\" of typedef - name collision with another top-level type.", name);
539 return LY_EEXIST;
540 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100541 /* it is not necessary to test collision with the scoped types - in lysp_check_typedefs, all the
542 * top-level typedefs are inserted into the tables before the scoped typedefs, so the collision
543 * is detected in the first branch few lines above */
Radek Krejcibbe09a92018-11-08 09:36:54 +0100544 }
545
546 return LY_SUCCESS;
547}
548
549static int
550lysp_id_cmp(void *val1, void *val2, int UNUSED(mod), void *UNUSED(cb_data))
551{
552 return !strcmp(val1, val2);
553}
554
555LY_ERR
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100556lysp_check_typedefs(struct ly_parser_ctx *ctx, struct lysp_module *mod)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100557{
558 struct hash_table *ids_global;
559 struct hash_table *ids_scoped;
Radek Krejci0fb28562018-12-13 15:17:37 +0100560 const struct lysp_tpdf *typedefs;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100561 unsigned int i, u;
562 LY_ERR ret = LY_EVALID;
563
564 /* check name collisions - typedefs and groupings */
565 ids_global = lyht_new(8, sizeof(char*), lysp_id_cmp, NULL, 1);
566 ids_scoped = lyht_new(8, sizeof(char*), lysp_id_cmp, NULL, 1);
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100567 LY_ARRAY_FOR(mod->typedefs, i) {
568 if (lysp_check_typedef(ctx, NULL, &mod->typedefs[i], ids_global, ids_scoped)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100569 goto cleanup;
570 }
571 }
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100572 LY_ARRAY_FOR(mod->includes, i) {
573 LY_ARRAY_FOR(mod->includes[i].submodule->typedefs, u) {
574 if (lysp_check_typedef(ctx, NULL, &mod->includes[i].submodule->typedefs[u], ids_global, ids_scoped)) {
Radek Krejci3b1f9292018-11-08 10:58:35 +0100575 goto cleanup;
576 }
577 }
578 }
Radek Krejcibbe09a92018-11-08 09:36:54 +0100579 for (u = 0; u < ctx->tpdfs_nodes.count; ++u) {
Radek Krejci0fb28562018-12-13 15:17:37 +0100580 typedefs = lysp_node_typedefs((struct lysp_node *)ctx->tpdfs_nodes.objs[u]);
581 LY_ARRAY_FOR(typedefs, i) {
582 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 +0100583 goto cleanup;
584 }
585 }
586 }
587 ret = LY_SUCCESS;
588cleanup:
589 lyht_free(ids_global);
590 lyht_free(ids_scoped);
591 ly_set_erase(&ctx->tpdfs_nodes, NULL);
592
593 return ret;
594}
595
Radek Krejci9ed7a192018-10-31 16:23:51 +0100596struct lysp_load_module_check_data {
597 const char *name;
598 const char *revision;
599 const char *path;
600 const char* submoduleof;
601};
602
603static LY_ERR
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100604lysp_load_module_check(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data)
Radek Krejci9ed7a192018-10-31 16:23:51 +0100605{
606 struct lysp_load_module_check_data *info = data;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100607 const char *filename, *dot, *rev, *name;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100608 size_t len;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100609 struct lysp_revision *revs;
610
611 name = mod ? mod->mod->name : submod->name;
612 revs = mod ? mod->revs : submod->revs;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100613
614 if (info->name) {
615 /* check name of the parsed model */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100616 if (strcmp(info->name, name)) {
617 LOGERR(ctx, LY_EINVAL, "Unexpected module \"%s\" parsed instead of \"%s\").", name, info->name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100618 return LY_EINVAL;
619 }
620 }
621 if (info->revision) {
622 /* check revision of the parsed model */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100623 if (!revs || strcmp(info->revision, revs[0].date)) {
624 LOGERR(ctx, LY_EINVAL, "Module \"%s\" parsed with the wrong revision (\"%s\" instead \"%s\").", name,
625 revs[0].date, info->revision);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100626 return LY_EINVAL;
627 }
628 }
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100629 if (submod) {
630 assert(info->submoduleof);
631
Radek Krejci9ed7a192018-10-31 16:23:51 +0100632 /* check that the submodule belongs-to our module */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100633 if (strcmp(info->submoduleof, submod->belongsto)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100634 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 +0100635 submod->name, info->submoduleof, submod->belongsto);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100636 return LY_EVALID;
637 }
638 /* check circular dependency */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100639 if (submod->parsing) {
640 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (include) for module \"%s\".", submod->name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100641 return LY_EVALID;
642 }
643 }
644 if (info->path) {
645 /* check that name and revision match filename */
646 filename = strrchr(info->path, '/');
647 if (!filename) {
648 filename = info->path;
649 } else {
650 filename++;
651 }
652 /* name */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100653 len = strlen(name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100654 rev = strchr(filename, '@');
655 dot = strrchr(info->path, '.');
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100656 if (strncmp(filename, name, len) ||
Radek Krejci9ed7a192018-10-31 16:23:51 +0100657 ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100658 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100659 }
660 /* revision */
661 if (rev) {
662 len = dot - ++rev;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100663 if (!revs || len != 10 || strncmp(revs[0].date, rev, len)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100664 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100665 revs ? revs[0].date : "none");
Radek Krejci9ed7a192018-10-31 16:23:51 +0100666 }
667 }
668 }
669 return LY_SUCCESS;
670}
671
672LY_ERR
Radek Krejci3b1f9292018-11-08 10:58:35 +0100673lys_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 +0100674 void **result)
Radek Krejci9ed7a192018-10-31 16:23:51 +0100675{
676 int fd;
677 char *filepath = NULL;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100678 const char **fp;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100679 LYS_INFORMAT format;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100680 void *mod = NULL;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100681 LY_ERR ret = LY_SUCCESS;
682 struct lysp_load_module_check_data check_data = {0};
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100683 char rpath[PATH_MAX];
Radek Krejci9ed7a192018-10-31 16:23:51 +0100684
685 LY_CHECK_RET(lys_search_localfile(ly_ctx_get_searchdirs(ctx), !(ctx->flags & LY_CTX_DISABLE_SEARCHDIR_CWD), name, revision,
686 &filepath, &format));
687 LY_CHECK_ERR_RET(!filepath, LOGERR(ctx, LY_ENOTFOUND, "Data model \"%s%s%s\" not found in local searchdirs.",
688 name, revision ? "@" : "", revision ? revision : ""), LY_ENOTFOUND);
689
690
691 LOGVRB("Loading schema from \"%s\" file.", filepath);
692
693 /* open the file */
694 fd = open(filepath, O_RDONLY);
695 LY_CHECK_ERR_GOTO(fd < 0, LOGERR(ctx, LY_ESYS, "Unable to open data model file \"%s\" (%s).",
696 filepath, strerror(errno)); ret = LY_ESYS, cleanup);
697
698 check_data.name = name;
699 check_data.revision = revision;
700 check_data.path = filepath;
Radek Krejci3b1f9292018-11-08 10:58:35 +0100701 mod = lys_parse_fd_(ctx, fd, format, implement, main_ctx,
Radek Krejci9ed7a192018-10-31 16:23:51 +0100702 lysp_load_module_check, &check_data);
703 close(fd);
704 LY_CHECK_ERR_GOTO(!mod, ly_errcode(ctx), cleanup);
705
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100706 if (main_ctx) {
707 fp = &((struct lysp_submodule*)mod)->filepath;
708 } else {
709 fp = &((struct lys_module*)mod)->filepath;
710 }
711 if (!(*fp)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100712 if (realpath(filepath, rpath) != NULL) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100713 (*fp) = lydict_insert(ctx, rpath, 0);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100714 } else {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100715 (*fp) = lydict_insert(ctx, filepath, 0);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100716 }
717 }
718
719 *result = mod;
720
721 /* success */
722cleanup:
723 free(filepath);
724 return ret;
725}
726
Radek Krejcid33273d2018-10-25 14:55:52 +0200727LY_ERR
Radek Krejci6d6e4e42018-10-29 13:28:19 +0100728lysp_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 +0200729{
Radek Krejci9ed7a192018-10-31 16:23:51 +0100730 const char *module_data = NULL;
Radek Krejci086c7132018-10-26 15:29:04 +0200731 LYS_INFORMAT format = LYS_IN_UNKNOWN;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100732 void (*module_data_free)(void *module_data, void *user_data) = NULL;
733 struct lysp_load_module_check_data check_data = {0};
Radek Krejci0af46292019-01-11 16:02:31 +0100734 struct lys_module *m;
Radek Krejci086c7132018-10-26 15:29:04 +0200735
Radek Krejci0af46292019-01-11 16:02:31 +0100736 assert(mod);
737
738 if (!*mod) {
739 /* try to get the module from the context */
740 if (revision) {
741 *mod = (struct lys_module*)ly_ctx_get_module(ctx, name, revision);
742 } else {
743 *mod = (struct lys_module*)ly_ctx_get_module_latest(ctx, name);
744 }
Radek Krejci086c7132018-10-26 15:29:04 +0200745 }
746
Radek Krejci6d6e4e42018-10-29 13:28:19 +0100747 if (!(*mod) || (require_parsed && !(*mod)->parsed)) {
748 (*mod) = NULL;
749
Radek Krejci086c7132018-10-26 15:29:04 +0200750 /* check collision with other implemented revision */
751 if (implement && ly_ctx_get_module_implemented(ctx, name)) {
752 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
753 "Module \"%s\" is already present in other implemented revision.", name);
754 return LY_EDENIED;
755 }
756
Radek Krejci9ed7a192018-10-31 16:23:51 +0100757 /* module not present in the context, get the input data and parse it */
Radek Krejci086c7132018-10-26 15:29:04 +0200758 if (!(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
759search_clb:
760 if (ctx->imp_clb) {
761 if (ctx->imp_clb(name, revision, NULL, NULL, ctx->imp_clb_data,
Radek Krejci9ed7a192018-10-31 16:23:51 +0100762 &format, &module_data, &module_data_free) == LY_SUCCESS) {
763 check_data.name = name;
764 check_data.revision = revision;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100765 *mod = lys_parse_mem_module(ctx, module_data, format, implement,
766 lysp_load_module_check, &check_data);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100767 if (module_data_free) {
768 module_data_free((void*)module_data, ctx->imp_clb_data);
769 }
Radek Krejci096235c2019-01-11 11:12:19 +0100770 if (*mod && implement && lys_compile(*mod, 0)) {
771 ly_set_rm(&ctx->list, *mod, NULL);
772 lys_module_free(*mod, NULL);
773 *mod = NULL;
774 }
Radek Krejci086c7132018-10-26 15:29:04 +0200775 }
776 }
777 if (!(*mod) && !(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
778 goto search_file;
779 }
780 } else {
781search_file:
782 if (!(ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
783 /* module was not received from the callback or there is no callback set */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100784 lys_module_localfile(ctx, name, revision, implement, NULL, (void **)mod);
Radek Krejci086c7132018-10-26 15:29:04 +0200785 }
786 if (!(*mod) && (ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
787 goto search_clb;
788 }
789 }
Radek Krejci9ed7a192018-10-31 16:23:51 +0100790
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100791 if ((*mod) && !revision && ((*mod)->latest_revision == 1)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100792 /* update the latest_revision flag - here we have selected the latest available schema,
793 * consider that even the callback provides correct latest revision */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100794 (*mod)->latest_revision = 2;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100795 }
Radek Krejci086c7132018-10-26 15:29:04 +0200796 } else {
797 /* we have module from the current context */
Radek Krejci0af46292019-01-11 16:02:31 +0100798 if (implement) {
799 m = ly_ctx_get_module_implemented(ctx, name);
800 if (m && m != *mod) {
801 /* check collision with other implemented revision */
802 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
803 "Module \"%s\" is already present in other implemented revision.", name);
804 *mod = NULL;
805 return LY_EDENIED;
806 }
Radek Krejci086c7132018-10-26 15:29:04 +0200807 }
808
809 /* circular check */
Radek Krejcif8f882a2018-10-31 14:51:15 +0100810 if ((*mod)->parsed && (*mod)->parsed->parsing) {
Radek Krejci086c7132018-10-26 15:29:04 +0200811 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (import) for module \"%s\".", name);
812 *mod = NULL;
813 return LY_EVALID;
814 }
815 }
816 if (!(*mod)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100817 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "%s \"%s\" module failed.", implement ? "Loading" : "Importing", name);
Radek Krejci086c7132018-10-26 15:29:04 +0200818 return LY_EVALID;
819 }
820
821 if (implement) {
822 /* mark the module implemented, check for collision was already done */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100823 (*mod)->implemented = 1;
Radek Krejci086c7132018-10-26 15:29:04 +0200824 }
Radek Krejci086c7132018-10-26 15:29:04 +0200825
826 return LY_SUCCESS;
827}
828
829LY_ERR
Radek Krejci3b1f9292018-11-08 10:58:35 +0100830lysp_load_submodule(struct ly_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc)
Radek Krejcid33273d2018-10-25 14:55:52 +0200831{
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100832 struct lysp_submodule *submod;
Radek Krejcid33273d2018-10-25 14:55:52 +0200833 const char *submodule_data = NULL;
834 LYS_INFORMAT format = LYS_IN_UNKNOWN;
835 void (*submodule_data_free)(void *module_data, void *user_data) = NULL;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100836 struct lysp_load_module_check_data check_data = {0};
Radek Krejcid33273d2018-10-25 14:55:52 +0200837
Radek Krejcibbe09a92018-11-08 09:36:54 +0100838 /* submodule not present in the context, get the input data and parse it */
Radek Krejci3b1f9292018-11-08 10:58:35 +0100839 if (!(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcid33273d2018-10-25 14:55:52 +0200840search_clb:
Radek Krejci3b1f9292018-11-08 10:58:35 +0100841 if (ctx->ctx->imp_clb) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100842 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 +0100843 &format, &submodule_data, &submodule_data_free) == LY_SUCCESS) {
844 check_data.name = inc->name;
845 check_data.revision = inc->rev[0] ? inc->rev : NULL;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100846 check_data.submoduleof = mod->mod->name;
847 submod = lys_parse_mem_submodule(ctx->ctx, submodule_data, format, ctx,
848 lysp_load_module_check, &check_data);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100849 if (submodule_data_free) {
Radek Krejci3b1f9292018-11-08 10:58:35 +0100850 submodule_data_free((void*)submodule_data, ctx->ctx->imp_clb_data);
Radek Krejcid33273d2018-10-25 14:55:52 +0200851 }
852 }
Radek Krejcid33273d2018-10-25 14:55:52 +0200853 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100854 if (!submod && !(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100855 goto search_file;
Radek Krejcid33273d2018-10-25 14:55:52 +0200856 }
Radek Krejci2d31ea72018-10-25 15:46:42 +0200857 } else {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100858search_file:
Radek Krejci3b1f9292018-11-08 10:58:35 +0100859 if (!(ctx->ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100860 /* submodule was not received from the callback or there is no callback set */
861 lys_module_localfile(ctx->ctx, inc->name, inc->rev[0] ? inc->rev : NULL, 0, ctx, (void**)&submod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100862 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100863 if (!submod && (ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100864 goto search_clb;
865 }
866 }
867 if (submod) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100868 if (!inc->rev[0] && (submod->latest_revision == 1)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100869 /* update the latest_revision flag - here we have selected the latest available schema,
870 * consider that even the callback provides correct latest revision */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100871 submod->latest_revision = 2;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100872 }
873
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100874 inc->submodule = submod;
Radek Krejcid33273d2018-10-25 14:55:52 +0200875 }
876 if (!inc->submodule) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100877 LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Including \"%s\" submodule into \"%s\" failed.",
878 inc->name, mod->mod->name);
Radek Krejcid33273d2018-10-25 14:55:52 +0200879 return LY_EVALID;
880 }
881
882 return LY_SUCCESS;
883}
884
Radek Krejci01342af2019-01-03 15:18:08 +0100885#define FIND_MODULE(TYPE, MOD) \
Radek Krejcice8c1592018-10-29 15:35:51 +0100886 TYPE *imp; \
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100887 if (!strncmp((MOD)->mod->prefix, prefix, len) && (MOD)->mod->prefix[len] == '\0') { \
Radek Krejcice8c1592018-10-29 15:35:51 +0100888 /* it is the prefix of the module itself */ \
Radek Krejci0af46292019-01-11 16:02:31 +0100889 m = ly_ctx_get_module((MOD)->mod->ctx, (MOD)->mod->name, (MOD)->mod->revision); \
Radek Krejcice8c1592018-10-29 15:35:51 +0100890 } \
891 /* search in imports */ \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100892 if (!m) { \
893 LY_ARRAY_FOR((MOD)->imports, TYPE, imp) { \
Radek Krejci01342af2019-01-03 15:18:08 +0100894 if (!strncmp(imp->prefix, prefix, len) && imp->prefix[len] == '\0') { \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100895 m = imp->module; \
896 break; \
897 } \
Radek Krejcice8c1592018-10-29 15:35:51 +0100898 } \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100899 }
Radek Krejcice8c1592018-10-29 15:35:51 +0100900
Radek Krejcibbe09a92018-11-08 09:36:54 +0100901struct lysc_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100902lysc_module_find_prefix(const struct lysc_module *mod, const char *prefix, size_t len)
Radek Krejci151a5b72018-10-19 14:21:44 +0200903{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100904 const struct lys_module *m = NULL;
905
Radek Krejci01342af2019-01-03 15:18:08 +0100906 FIND_MODULE(struct lysc_import, mod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100907 return m ? m->compiled : NULL;
Radek Krejcice8c1592018-10-29 15:35:51 +0100908}
Radek Krejci151a5b72018-10-19 14:21:44 +0200909
Radek Krejcibbe09a92018-11-08 09:36:54 +0100910struct lysp_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100911lysp_module_find_prefix(const struct lysp_module *mod, const char *prefix, size_t len)
Radek Krejcice8c1592018-10-29 15:35:51 +0100912{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100913 const struct lys_module *m = NULL;
914
Radek Krejci01342af2019-01-03 15:18:08 +0100915 FIND_MODULE(struct lysp_import, mod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100916 return m ? m->parsed : NULL;
Radek Krejcice8c1592018-10-29 15:35:51 +0100917}
Radek Krejci151a5b72018-10-19 14:21:44 +0200918
Radek Krejcice8c1592018-10-29 15:35:51 +0100919struct lys_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100920lys_module_find_prefix(const struct lys_module *mod, const char *prefix, size_t len)
Radek Krejcice8c1592018-10-29 15:35:51 +0100921{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100922 const struct lys_module *m = NULL;
923
Radek Krejcice8c1592018-10-29 15:35:51 +0100924 if (mod->compiled) {
Radek Krejci01342af2019-01-03 15:18:08 +0100925 FIND_MODULE(struct lysc_import, mod->compiled);
Radek Krejcice8c1592018-10-29 15:35:51 +0100926 } else {
Radek Krejci01342af2019-01-03 15:18:08 +0100927 FIND_MODULE(struct lysp_import, mod->parsed);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100928 }
929 return (struct lys_module*)m;
930}
931
Radek Krejcia3045382018-11-22 14:30:31 +0100932const char *
933lys_nodetype2str(uint16_t nodetype)
934{
935 switch(nodetype) {
936 case LYS_CONTAINER:
937 return "container";
938 case LYS_CHOICE:
939 return "choice";
940 case LYS_LEAF:
941 return "leaf";
942 case LYS_LEAFLIST:
943 return "leaf-list";
944 case LYS_LIST:
945 return "list";
946 case LYS_ANYXML:
947 return "anyxml";
948 case LYS_ANYDATA:
949 return "anydata";
Radek Krejcif12a1f02019-02-11 16:42:08 +0100950 case LYS_CASE:
951 return "case";
Radek Krejcia3045382018-11-22 14:30:31 +0100952 default:
953 return "unknown";
954 }
955}
956
Radek Krejci056d0a82018-12-06 16:57:25 +0100957API const struct lysp_tpdf *
958lysp_node_typedefs(const struct lysp_node *node)
959{
Radek Krejci0fb28562018-12-13 15:17:37 +0100960 switch (node->nodetype) {
961 case LYS_CONTAINER:
962 return ((struct lysp_node_container*)node)->typedefs;
963 case LYS_LIST:
964 return ((struct lysp_node_list*)node)->typedefs;
965 case LYS_GROUPING:
966 return ((struct lysp_grp*)node)->typedefs;
967 case LYS_ACTION:
968 return ((struct lysp_action*)node)->typedefs;
969 case LYS_INOUT:
970 return ((struct lysp_action_inout*)node)->typedefs;
971 case LYS_NOTIF:
972 return ((struct lysp_notif*)node)->typedefs;
973 default:
Radek Krejci056d0a82018-12-06 16:57:25 +0100974 return NULL;
975 }
976}
977
Radek Krejci53ea6152018-12-13 15:21:15 +0100978API const struct lysp_grp *
979lysp_node_groupings(const struct lysp_node *node)
980{
981 switch (node->nodetype) {
982 case LYS_CONTAINER:
983 return ((struct lysp_node_container*)node)->groupings;
984 case LYS_LIST:
985 return ((struct lysp_node_list*)node)->groupings;
986 case LYS_GROUPING:
987 return ((struct lysp_grp*)node)->groupings;
988 case LYS_ACTION:
989 return ((struct lysp_action*)node)->groupings;
990 case LYS_INOUT:
991 return ((struct lysp_action_inout*)node)->groupings;
992 case LYS_NOTIF:
993 return ((struct lysp_notif*)node)->groupings;
994 default:
995 return NULL;
996 }
997}
998
Radek Krejcibbe09a92018-11-08 09:36:54 +0100999struct lysp_action **
Radek Krejci056d0a82018-12-06 16:57:25 +01001000lysp_node_actions_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001001{
1002 assert(node);
1003 switch (node->nodetype) {
1004 case LYS_CONTAINER:
1005 return &((struct lysp_node_container*)node)->actions;
1006 case LYS_LIST:
1007 return &((struct lysp_node_list*)node)->actions;
1008 case LYS_GROUPING:
1009 return &((struct lysp_grp*)node)->actions;
1010 case LYS_AUGMENT:
1011 return &((struct lysp_augment*)node)->actions;
1012 default:
1013 return NULL;
1014 }
1015}
1016
Radek Krejci056d0a82018-12-06 16:57:25 +01001017API const struct lysp_action *
1018lysp_node_actions(const struct lysp_node *node)
1019{
1020 struct lysp_action **actions;
1021 actions = lysp_node_actions_p((struct lysp_node*)node);
1022 if (actions) {
1023 return *actions;
1024 } else {
1025 return NULL;
1026 }
1027}
1028
Radek Krejcibbe09a92018-11-08 09:36:54 +01001029struct lysp_notif **
Radek Krejci056d0a82018-12-06 16:57:25 +01001030lysp_node_notifs_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001031{
1032 assert(node);
1033 switch (node->nodetype) {
1034 case LYS_CONTAINER:
1035 return &((struct lysp_node_container*)node)->notifs;
1036 case LYS_LIST:
1037 return &((struct lysp_node_list*)node)->notifs;
1038 case LYS_GROUPING:
1039 return &((struct lysp_grp*)node)->notifs;
1040 case LYS_AUGMENT:
1041 return &((struct lysp_augment*)node)->notifs;
1042 default:
1043 return NULL;
1044 }
1045}
1046
Radek Krejci056d0a82018-12-06 16:57:25 +01001047API const struct lysp_notif *
1048lysp_node_notifs(const struct lysp_node *node)
1049{
1050 struct lysp_notif **notifs;
1051 notifs = lysp_node_notifs_p((struct lysp_node*)node);
1052 if (notifs) {
1053 return *notifs;
1054 } else {
1055 return NULL;
1056 }
1057}
1058
Radek Krejcibbe09a92018-11-08 09:36:54 +01001059struct lysp_node **
Radek Krejci056d0a82018-12-06 16:57:25 +01001060lysp_node_children_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001061{
1062 assert(node);
1063 switch (node->nodetype) {
1064 case LYS_CONTAINER:
1065 return &((struct lysp_node_container*)node)->child;
1066 case LYS_CHOICE:
1067 return &((struct lysp_node_choice*)node)->child;
1068 case LYS_LIST:
1069 return &((struct lysp_node_list*)node)->child;
1070 case LYS_CASE:
1071 return &((struct lysp_node_case*)node)->child;
1072 case LYS_GROUPING:
1073 return &((struct lysp_grp*)node)->data;
1074 case LYS_AUGMENT:
1075 return &((struct lysp_augment*)node)->child;
1076 case LYS_INOUT:
1077 return &((struct lysp_action_inout*)node)->data;
1078 case LYS_NOTIF:
1079 return &((struct lysp_notif*)node)->data;
1080 default:
1081 return NULL;
1082 }
1083}
1084
Radek Krejci056d0a82018-12-06 16:57:25 +01001085API const struct lysp_node *
1086lysp_node_children(const struct lysp_node *node)
1087{
1088 struct lysp_node **children;
1089 children = lysp_node_children_p((struct lysp_node*)node);
1090 if (children) {
1091 return *children;
1092 } else {
1093 return NULL;
1094 }
1095}
1096
1097struct lysc_action **
1098lysc_node_actions_p(struct lysc_node *node)
1099{
1100 assert(node);
1101 switch (node->nodetype) {
1102 case LYS_CONTAINER:
1103 return &((struct lysc_node_container*)node)->actions;
1104 case LYS_LIST:
1105 return &((struct lysc_node_list*)node)->actions;
1106 default:
1107 return NULL;
1108 }
1109}
1110
1111API const struct lysc_action *
1112lysc_node_actions(const struct lysc_node *node)
1113{
1114 struct lysc_action **actions;
1115 actions = lysc_node_actions_p((struct lysc_node*)node);
1116 if (actions) {
1117 return *actions;
1118 } else {
1119 return NULL;
1120 }
1121}
1122
1123struct lysc_notif **
1124lysc_node_notifs_p(struct lysc_node *node)
1125{
1126 assert(node);
1127 switch (node->nodetype) {
1128 case LYS_CONTAINER:
1129 return &((struct lysc_node_container*)node)->notifs;
1130 case LYS_LIST:
1131 return &((struct lysc_node_list*)node)->notifs;
1132 default:
1133 return NULL;
1134 }
1135}
1136
1137API const struct lysc_notif *
1138lysc_node_notifs(const struct lysc_node *node)
1139{
1140 struct lysc_notif **notifs;
1141 notifs = lysc_node_notifs_p((struct lysc_node*)node);
1142 if (notifs) {
1143 return *notifs;
1144 } else {
1145 return NULL;
1146 }
1147}
1148
Radek Krejcibbe09a92018-11-08 09:36:54 +01001149struct lysc_node **
Radek Krejci6eeb58f2019-02-22 16:29:37 +01001150lysc_node_children_p(const struct lysc_node *node, uint16_t flags)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001151{
1152 assert(node);
1153 switch (node->nodetype) {
1154 case LYS_CONTAINER:
1155 return &((struct lysc_node_container*)node)->child;
1156 case LYS_CHOICE:
Radek Krejcia3045382018-11-22 14:30:31 +01001157 if (((struct lysc_node_choice*)node)->cases) {
Radek Krejci95710c92019-02-11 15:49:55 +01001158 return &((struct lysc_node_choice*)node)->cases->child;
Radek Krejcia3045382018-11-22 14:30:31 +01001159 } else {
1160 return NULL;
1161 }
Radek Krejci01342af2019-01-03 15:18:08 +01001162 case LYS_CASE:
1163 return &((struct lysc_node_case*)node)->child;
Radek Krejcibbe09a92018-11-08 09:36:54 +01001164 case LYS_LIST:
1165 return &((struct lysc_node_list*)node)->child;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01001166 case LYS_ACTION:
1167 if (flags & LYS_CONFIG_R) {
1168 return &((struct lysc_action*)node)->output.data;
1169 } else {
1170 /* LYS_CONFIG_W, but also the default case */
1171 return &((struct lysc_action*)node)->input.data;
1172 }
1173 /* TODO Notification */
Radek Krejcibbe09a92018-11-08 09:36:54 +01001174 default:
1175 return NULL;
1176 }
1177}
1178
Radek Krejci056d0a82018-12-06 16:57:25 +01001179API const struct lysc_node *
Radek Krejci6eeb58f2019-02-22 16:29:37 +01001180lysc_node_children(const struct lysc_node *node, uint16_t flags)
Radek Krejcia3045382018-11-22 14:30:31 +01001181{
Radek Krejci056d0a82018-12-06 16:57:25 +01001182 struct lysc_node **children;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01001183 children = lysc_node_children_p((struct lysc_node*)node, flags);
Radek Krejci056d0a82018-12-06 16:57:25 +01001184 if (children) {
1185 return *children;
1186 } else {
Radek Krejcia3045382018-11-22 14:30:31 +01001187 return NULL;
1188 }
1189}
1190
Radek Krejci96a0bfd2018-11-22 15:25:06 +01001191struct lys_module *
1192lysp_find_module(struct ly_ctx *ctx, const struct lysp_module *mod)
1193{
1194 unsigned int u;
1195
1196 for (u = 0; u < ctx->list.count; ++u) {
1197 if (((struct lys_module*)ctx->list.objs[u])->parsed == mod) {
1198 return ((struct lys_module*)ctx->list.objs[u]);
1199 }
1200 }
1201 return NULL;
1202}
1203