schema parsers CHANGE detect typedef collisions between main module and submodules
diff --git a/src/tree_schema.c b/src/tree_schema.c
index e82ff02..7301326 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -1506,7 +1506,7 @@
}
struct lys_module *
-lys_parse_mem_(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, int implement,
+lys_parse_mem_(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, int implement, struct ly_parser_ctx *main_ctx,
LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, void *data), void *check_data)
{
struct lys_module *mod = NULL, *latest, *mod_dup;
@@ -1522,6 +1522,12 @@
context.ctx = ctx;
context.line = 1;
+ if (main_ctx) {
+ /* map the typedefs and groupings list from main context to the submodule's context */
+ memcpy(&context.tpdfs_nodes, &main_ctx->tpdfs_nodes, sizeof main_ctx->tpdfs_nodes);
+ memcpy(&context.grps_nodes, &main_ctx->grps_nodes, sizeof main_ctx->grps_nodes);
+ }
+
mod = calloc(1, sizeof *mod);
LY_CHECK_ERR_RET(!mod, LOGMEM(ctx), NULL);
@@ -1557,6 +1563,11 @@
}
if (mod->parsed->submodule) { /* submodule */
+ if (!main_ctx) {
+ LOGERR(ctx, LY_EDENIED, "Input data contains submodule \"%s\" which cannot be parsed directly without its main module.",
+ mod->parsed->name);
+ goto error;
+ }
/* decide the latest revision */
latest_p = ly_ctx_get_submodule(ctx, mod->parsed->belongsto, mod->parsed->name, NULL);
if (latest_p) {
@@ -1575,6 +1586,9 @@
} else {
mod->parsed->latest_revision = 1;
}
+ /* remap possibly changed and reallocated typedefs and groupings list back to the main context */
+ memcpy(&main_ctx->tpdfs_nodes, &context.tpdfs_nodes, sizeof main_ctx->tpdfs_nodes);
+ memcpy(&main_ctx->grps_nodes, &context.grps_nodes, sizeof main_ctx->grps_nodes);
} else { /* module */
/* check for duplicity in the context */
mod_dup = (struct lys_module*)ly_ctx_get_module(ctx, mod->parsed->name, mod->parsed->revs ? mod->parsed->revs[0].date : NULL);
@@ -1650,7 +1664,7 @@
}
LY_ARRAY_FOR(mod->parsed->includes, u) {
inc = &mod->parsed->includes[u];
- if (!inc->submodule && lysp_load_submodule(ctx, mod->parsed, inc)) {
+ if (!inc->submodule && lysp_load_submodule(&context, mod->parsed, inc)) {
goto error_ctx;
}
}
@@ -1673,16 +1687,7 @@
API struct lys_module *
lys_parse_mem(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format)
{
- struct lys_module *result;
-
- result = lys_parse_mem_(ctx, data, format, 1, NULL, NULL);
- if (result && result->parsed->submodule) {
- LOGERR(ctx, LY_EDENIED, "Input data contains submodule \"%s\" which cannot be parsed directly without its main module.",
- result->parsed->name);
- lys_module_free(result, NULL);
- return NULL;
- }
- return result;
+ return lys_parse_mem_(ctx, data, format, 1, NULL, NULL, NULL);
}
static void
@@ -1709,7 +1714,7 @@
}
struct lys_module *
-lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement,
+lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement, struct ly_parser_ctx *main_ctx,
LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, void *data), void *check_data)
{
struct lys_module *mod;
@@ -1728,7 +1733,7 @@
return NULL;
}
- mod = lys_parse_mem_(ctx, addr, format, implement, custom_check, check_data);
+ mod = lys_parse_mem_(ctx, addr, format, implement, main_ctx, custom_check, check_data);
ly_munmap(addr, length);
if (mod && !mod->parsed->filepath) {
@@ -1741,20 +1746,11 @@
API struct lys_module *
lys_parse_fd(struct ly_ctx *ctx, int fd, LYS_INFORMAT format)
{
- struct lys_module *result;
-
- result = lys_parse_fd_(ctx, fd, format, 1, NULL, NULL);
- if (result && result->parsed->submodule) {
- LOGERR(ctx, LY_EDENIED, "Input data contains submodule \"%s\" which cannot be parsed directly without its main module.",
- result->parsed->name);
- lys_module_free(result, NULL);
- return NULL;
- }
- return result;
+ return lys_parse_fd_(ctx, fd, format, 1, NULL, NULL, NULL);
}
struct lys_module *
-lys_parse_path_(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, int implement,
+lys_parse_path_(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, int implement, struct ly_parser_ctx *main_ctx,
LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, void *data), void *check_data)
{
int fd;
@@ -1767,7 +1763,7 @@
fd = open(path, O_RDONLY);
LY_CHECK_ERR_RET(fd == -1, LOGERR(ctx, LY_ESYS, "Opening file \"%s\" failed (%s).", path, strerror(errno)), NULL);
- mod = lys_parse_fd_(ctx, fd, format, implement, custom_check, check_data);
+ mod = lys_parse_fd_(ctx, fd, format, implement, main_ctx, custom_check, check_data);
close(fd);
LY_CHECK_RET(!mod, NULL);
@@ -1811,16 +1807,7 @@
API struct lys_module *
lys_parse_path(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format)
{
- struct lys_module *result;
-
- result = lys_parse_path_(ctx, path, format, 1, NULL, NULL);
- if (result && result->parsed->submodule) {
- LOGERR(ctx, LY_EDENIED, "Input file \"%s\" contains submodule \"%s\" which cannot be parsed directly without its main module.",
- path, result->parsed->name);
- lys_module_free(result, NULL);
- return NULL;
- }
- return result;
+ return lys_parse_path_(ctx, path, format, 1, NULL, NULL, NULL);
}
API LY_ERR
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index f7904d3..df72591 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -323,11 +323,9 @@
"Invalid name \"%s\" of typedef - name collision with another top-level type.", name);
return LY_EEXIST;
}
- if (!lyht_find(tpdfs_scoped, &name, hash, NULL)) {
- LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
- "Invalid name \"%s\" of typedef - top-level type collide with a scoped type.", name);
- return LY_EEXIST;
- }
+ /* it is not necessary to test collision with the scoped types - in lysp_check_typedefs, all the
+ * top-level typedefs are inserted into the tables before the scoped typedefs, so the collision
+ * is detected in the first branch few lines above */
}
return LY_SUCCESS;
@@ -356,6 +354,13 @@
goto cleanup;
}
}
+ LY_ARRAY_FOR(ctx->mod->includes, i) {
+ LY_ARRAY_FOR(ctx->mod->includes[i].submodule->typedefs, u) {
+ if (lysp_check_typedef(ctx, NULL, &ctx->mod->includes[i].submodule->typedefs[u], ids_global, ids_scoped)) {
+ goto cleanup;
+ }
+ }
+ }
for (u = 0; u < ctx->tpdfs_nodes.count; ++u) {
typedefs = lysp_node_typedefs((struct lysp_node *)ctx->tpdfs_nodes.objs[u]);
LY_ARRAY_FOR(*typedefs, i) {
@@ -463,7 +468,7 @@
}
LY_ERR
-lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement,
+lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct ly_parser_ctx *main_ctx,
struct lys_module **result)
{
int fd;
@@ -489,7 +494,7 @@
check_data.name = name;
check_data.revision = revision;
check_data.path = filepath;
- mod = lys_parse_fd_(ctx, fd, format, implement,
+ mod = lys_parse_fd_(ctx, fd, format, implement, main_ctx,
lysp_load_module_check, &check_data);
close(fd);
LY_CHECK_ERR_GOTO(!mod, ly_errcode(ctx), cleanup);
@@ -544,7 +549,7 @@
&format, &module_data, &module_data_free) == LY_SUCCESS) {
check_data.name = name;
check_data.revision = revision;
- *mod = lys_parse_mem_(ctx, module_data, format, implement,
+ *mod = lys_parse_mem_(ctx, module_data, format, implement, NULL,
lysp_load_module_check, &check_data);
if (module_data_free) {
module_data_free((void*)module_data, ctx->imp_clb_data);
@@ -558,7 +563,7 @@
search_file:
if (!(ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
/* module was not received from the callback or there is no callback set */
- lys_module_localfile(ctx, name, revision, implement, mod);
+ lys_module_localfile(ctx, name, revision, implement, NULL, mod);
}
if (!(*mod) && (ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
goto search_clb;
@@ -601,7 +606,7 @@
}
LY_ERR
-lysp_load_submodule(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc)
+lysp_load_submodule(struct ly_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc)
{
struct lys_module *submod;
const char *submodule_data = NULL;
@@ -610,31 +615,31 @@
struct lysp_load_module_check_data check_data = {0};
/* submodule not present in the context, get the input data and parse it */
- if (!(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
+ if (!(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
search_clb:
- if (ctx->imp_clb) {
- if (ctx->imp_clb(mod->name, NULL, inc->name, inc->rev[0] ? inc->rev : NULL, ctx->imp_clb_data,
+ if (ctx->ctx->imp_clb) {
+ if (ctx->ctx->imp_clb(mod->name, NULL, inc->name, inc->rev[0] ? inc->rev : NULL, ctx->ctx->imp_clb_data,
&format, &submodule_data, &submodule_data_free) == LY_SUCCESS) {
check_data.name = inc->name;
check_data.revision = inc->rev[0] ? inc->rev : NULL;
check_data.submoduleof = mod->name;
- submod = lys_parse_mem_(ctx, submodule_data, format, mod->implemented,
+ submod = lys_parse_mem_(ctx->ctx, submodule_data, format, mod->implemented, ctx,
lysp_load_module_check, &check_data);
if (submodule_data_free) {
- submodule_data_free((void*)submodule_data, ctx->imp_clb_data);
+ submodule_data_free((void*)submodule_data, ctx->ctx->imp_clb_data);
}
}
}
- if (!submod && !(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
+ if (!submod && !(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
goto search_file;
}
} else {
search_file:
- if (!(ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
+ if (!(ctx->ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
/* module was not received from the callback or there is no callback set */
- lys_module_localfile(ctx, inc->name, inc->rev[0] ? inc->rev : NULL, mod->implemented, &submod);
+ lys_module_localfile(ctx->ctx, inc->name, inc->rev[0] ? inc->rev : NULL, mod->implemented, ctx, &submod);
}
- if (!submod && (ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
+ if (!submod && (ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
goto search_clb;
}
}
@@ -649,7 +654,7 @@
free(submod);
}
if (!inc->submodule) {
- LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Including \"%s\" submodule into \"%s\" failed.", inc->name, mod->name);
+ LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Including \"%s\" submodule into \"%s\" failed.", inc->name, mod->name);
return LY_EVALID;
}
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 73a77b3..a73fb0a 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -115,13 +115,13 @@
/**
* @brief Parse included submodule into the simply parsed YANG module.
*
- * @param[in] ctx libyang context
+ * @param[in] ctx parser context
* @param[in] mod Module including a submodule.
* @param[in,out] inc Include structure holding all available information about the include statement, the parsed
* submodule is stored into this structure.
* @return LY_ERR value.
*/
-LY_ERR lysp_load_submodule(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc);
+LY_ERR lysp_load_submodule(struct ly_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc);
/**
* @brief Get address of a node's typedefs list if any.
@@ -210,11 +210,12 @@
* format.
* @param[in] format Format of the input data (YANG or YIN).
* @param[in] implement Flag if the schema is supposed to be marked as implemented.
+ * @param[in] main_ctx Parser context of the main module in case of parsing submodule.
* @param[in] custom_check Callback to check the parsed schema before it is accepted.
* @param[in] check_data Caller's data to pass to the custom_check callback.
* @return Pointer to the data model structure or NULL on error.
*/
-struct lys_module *lys_parse_mem_(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, int implement,
+struct lys_module *lys_parse_mem_(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, int implement, struct ly_parser_ctx *main_ctx,
LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, void *data), void *check_data);
/**
@@ -231,11 +232,12 @@
* in the specified format.
* @param[in] format Format of the input data (YANG or YIN).
* @param[in] implement Flag if the schema is supposed to be marked as implemented.
+ * @param[in] main_ctx Parser context of the main module in case of parsing submodule.
* @param[in] custom_check Callback to check the parsed schema before it is accepted.
* @param[in] check_data Caller's data to pass to the custom_check callback.
* @return Pointer to the data model structure or NULL on error.
*/
-struct lys_module *lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement,
+struct lys_module *lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement, struct ly_parser_ctx *main_ctx,
LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, void *data), void *check_data);
/**
@@ -253,11 +255,12 @@
* @param[in] path Path to the file with the model in the specified format.
* @param[in] format Format of the input data (YANG or YIN).
* @param[in] implement Flag if the schema is supposed to be marked as implemented.
+ * @param[in] main_ctx Parser context of the main module in case of parsing submodule.
* @param[in] custom_check Callback to check the parsed schema before it is accepted.
* @param[in] check_data Caller's data to pass to the custom_check callback.
* @return Pointer to the data model structure or NULL on error.
*/
-struct lys_module *lys_parse_path_(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, int implement,
+struct lys_module *lys_parse_path_(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, int implement, struct ly_parser_ctx *main_ctx,
LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, void *data), void *check_data);
/**
@@ -271,10 +274,12 @@
* @param[in] name Name of the (sub)module to load.
* @param[in] revision Optional revision of the (sub)module to load, if NULL the newest revision is being loaded.
* @param[in] implement Flag if the (sub)module is supposed to be marked as implemented.
+ * @param[in] main_ctx Parser context of the main module in case of loading submodule.
* @param[out] result Parsed YANG schema tree of the requested module. If it is a module, it is already in the context!
* @return LY_ERR value, in case of LY_SUCCESS, the \arg result is always provided.
*/
-LY_ERR lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct lys_module **result);
+LY_ERR lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct ly_parser_ctx *main_ctx,
+ struct lys_module **result);
/**
* @brief Make the module implemented.