tree schema CHANGE compile import module information
diff --git a/src/common.h b/src/common.h
index fe00f7b..c075979 100644
--- a/src/common.h
+++ b/src/common.h
@@ -353,6 +353,24 @@
LY_CHECK_ERR_RET(!(ARRAY), LOGMEM(CTX), RETVAL); \
ARRAY = (void*)((uint32_t*)(ARRAY) + 1)
+/**
+ * @brief Allocate a ([sized array](@ref sizedarrays)) for the specified number of items.
+ *
+ * Does not set the size information, it is supposed to be incremented via ::LY_ARRAY_INCREMENT
+ * when the items are filled.
+ *
+ * @param[in] CTX libyang context for logging.
+ * @param[in,out] ARRAY Pointer to the array to create.
+ * @param[in] SIZE Number of items the array is supposed to hold. The size of the allocated
+ * space is then counted from the type of the ARRAY, so do not provide placeholder void pointers.
+ * @param[out] RET Variable to store error code.
+ * @param[in] GOTO Label to go in case of error (memory allocation failure).
+ */
+#define LY_ARRAY_CREATE_GOTO(CTX, ARRAY, SIZE, RET, GOTO) \
+ ARRAY = calloc(1, sizeof(uint32_t) + SIZE * sizeof *(ARRAY)); \
+ LY_CHECK_ERR_GOTO(!(ARRAY), LOGMEM(CTX); RET = LY_EMEM, GOTO); \
+ ARRAY = (void*)((uint32_t*)(ARRAY) + 1)
+
#define LY_ARRAY_INCREMENT(ARRAY) \
++(*((uint32_t*)(ARRAY) - 1))
/**
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 257a259..8c117f1 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -34,6 +34,16 @@
#define FREE_STRING(CTX, STRING, DICT) if (DICT && STRING) {lydict_remove(CTX, STRING);}
#define FREE_STRINGS(CTX, ARRAY, DICT) {uint64_t c__; LY_ARRAY_FOR(ARRAY, c__){FREE_STRING(CTX, ARRAY[c__], DICT);}LY_ARRAY_FREE(ARRAY);}
+#define COMPILE_ARRAY_GOTO(CTX, ARRAY_P, ARRAY_C, OPTIONS, ITER, FUNC, RET, GOTO) \
+ if (ARRAY_P) { \
+ LY_ARRAY_CREATE_GOTO((CTX).mod->ctx, ARRAY_C, LY_ARRAY_SIZE(ARRAY_P), RET, GOTO); \
+ for (ITER = 0; ITER < LY_ARRAY_SIZE(ARRAY_P); ++ITER) { \
+ RET = FUNC(&(CTX), &(ARRAY_P)[ITER], OPTIONS, &(ARRAY_C)[ITER]); \
+ LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
+ LY_ARRAY_INCREMENT(ARRAY_C); \
+ } \
+ }
+
static void lysp_grp_free(struct ly_ctx *ctx, struct lysp_grp *grp, int dict);
static void lysp_node_free(struct ly_ctx *ctx, struct lysp_node *node, int dict);
@@ -993,6 +1003,49 @@
}
static LY_ERR
+lys_compile_import(struct lysc_ctx *ctx, struct lysp_import *imp_p, int options, struct lysc_import *imp)
+{
+ struct lys_module *mod;
+ struct lysc_module *comp;
+
+ if (options & LYSC_OPT_FREE_SP) {
+ /* just switch the pointers */
+ imp->prefix = imp_p->prefix;
+ } else {
+ /* keep refcounts correct for lysp_module_free() */
+ imp->prefix = lydict_insert(ctx->mod->ctx, imp_p->prefix, 0);
+ }
+ imp->module = imp_p->module;
+
+ /* make sure that we have both versions (lysp_ and lysc_) of the imported module. To import groupings or
+ * typedefs, the lysp_ is needed. To augment or deviate imported module, we need the lysc_ structure */
+ if (!imp->module->parsed) {
+ comp = imp->module->compiled;
+ /* try to get filepath from the compiled version */
+ if (comp->filepath) {
+ mod = (struct lys_module*)lys_parse_path(ctx->mod->ctx, comp->filepath,
+ !strcmp(&comp->filepath[strlen(comp->filepath - 4)], ".yin") ? LYS_IN_YIN : LYS_IN_YANG);
+ if (mod != imp->module) {
+ LOGERR(ctx->mod->ctx, LY_EINT, "Filepath \"%s\" of the module \"%s\" does not match.",
+ comp->filepath, comp->name);
+ mod = NULL;
+ }
+ }
+ if (!mod) {
+ if (lysp_load_module(ctx->mod->ctx, comp->name, comp->revs ? comp->revs[0].date : NULL, 0, 1, &mod)) {
+ LOGERR(ctx->mod->ctx, LY_ENOTFOUND, "Unable to reload \"%s\" module to import it into \"%s\", source data not found.",
+ comp->name, ctx->mod->name);
+ return LY_ENOTFOUND;
+ }
+ }
+ } else if (!imp->module->compiled) {
+ return lys_compile(imp->module->parsed, options, &imp->module->compiled);
+ }
+
+ return LY_SUCCESS;
+}
+
+static LY_ERR
lys_compile_feature(struct lysc_ctx *ctx, struct lysp_feature *feature_p, int options, struct lysc_feature *feature)
{
unsigned int u;
@@ -1053,16 +1106,8 @@
mod_c->prefix = lydict_insert(sp->ctx, sp->prefix, 0);
}
- if (sp->features) {
- /* allocate everything now */
- LY_ARRAY_CREATE_RET(ctx.mod->ctx, mod_c->features, LY_ARRAY_SIZE(sp->features), LY_EMEM);
-
- for (u = 0; u < LY_ARRAY_SIZE(sp->features); ++u) {
- ret = lys_compile_feature(&ctx, &sp->features[u], options, &mod_c->features[u]);
- LY_CHECK_GOTO(ret != LY_SUCCESS, error);
- LY_ARRAY_INCREMENT(mod_c->features);
- }
- }
+ COMPILE_ARRAY_GOTO(ctx, sp->imports, mod_c->imports, options, u, lys_compile_import, ret, error);
+ COMPILE_ARRAY_GOTO(ctx, sp->features, mod_c->features, options, u, lys_compile_feature, ret, error);
if (options & LYSC_OPT_FREE_SP) {
lysp_module_free_(sp, 0);
@@ -1072,12 +1117,8 @@
return LY_SUCCESS;
error:
+ lysc_module_free_(mod_c, (options & LYSC_OPT_FREE_SP) ? 0 : 1);
- if (options & LYSC_OPT_FREE_SP) {
- lysc_module_free_(mod_c, 0);
- } else {
- lysc_module_free_(mod_c, 1);
- }
return ret;
}
@@ -1097,7 +1138,7 @@
struct lys_module *
lys_parse_mem_(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, const char *revision, int implement)
{
- struct lys_module *mod = NULL, *latest;
+ struct lys_module *mod = NULL, *latest, *mod_dup;
struct lysp_module *latest_p;
struct lysp_import *imp;
struct lysp_include *inc;
@@ -1168,16 +1209,26 @@
}
} else { /* module */
/* check for duplicity in the context */
- if (ly_ctx_get_module(ctx, mod->parsed->name, mod->parsed->revs ? mod->parsed->revs[0].date : NULL)) {
- if (mod->parsed->revs) {
- LOGERR(ctx, LY_EEXIST, "Module \"%s\" of revision \"%s\" is already present in the context.",
- mod->parsed->name, mod->parsed->revs[0].date);
+ mod_dup = (struct lys_module*)ly_ctx_get_module(ctx, mod->parsed->name, mod->parsed->revs ? mod->parsed->revs[0].date : NULL);
+ if (mod_dup) {
+ if (mod_dup->parsed) {
+ /* error */
+ if (mod->parsed->revs) {
+ LOGERR(ctx, LY_EEXIST, "Module \"%s\" of revision \"%s\" is already present in the context.",
+ mod->parsed->name, mod->parsed->revs[0].date);
+ } else {
+ LOGERR(ctx, LY_EEXIST, "Module \"%s\" with no revision is already present in the context.",
+ mod->parsed->name);
+ }
+ lys_module_free(mod, NULL);
+ return NULL;
} else {
- LOGERR(ctx, LY_EEXIST, "Module \"%s\" with no revision is already present in the context.",
- mod->parsed->name);
+ /* add the parsed data to the currently compiled-only module in the context */
+ mod_dup->parsed = mod->parsed;
+ free(mod);
+ mod = mod_dup;
+ goto finish_parsing;
}
- lys_module_free(mod, NULL);
- return NULL;
}
#if 0
@@ -1214,11 +1265,12 @@
/* add into context */
ly_set_add(&ctx->list, mod, LY_SET_OPT_USEASLIST);
+finish_parsing:
/* resolve imports and includes */
mod->parsed->parsing = 1;
LY_ARRAY_FOR(mod->parsed->imports, u) {
imp = &mod->parsed->imports[u];
- if (!imp->module && lysp_load_module(ctx, imp->name, imp->rev[0] ? imp->rev : NULL, 0, &imp->module)) {
+ if (!imp->module && lysp_load_module(ctx, imp->name, imp->rev[0] ? imp->rev : NULL, 0, 0, &imp->module)) {
ly_set_rm(&ctx->list, mod, NULL);
lys_module_free(mod, NULL);
return NULL;
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 048e87e..ff1d929 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -743,6 +743,7 @@
struct lysp_module {
struct ly_ctx *ctx; /**< libyang context of the module (mandatory) */
const char *name; /**< name of the module (mandatory) */
+ const char *filepath; /**< path, if the schema was read from a file, NULL in case of reading from memory */
union {
/* module */
const char *ns; /**< namespace of the module (module - mandatory) */
@@ -754,7 +755,6 @@
in the list is always the last (newest) revision of the module */
struct lysp_import *imports; /**< list of imported modules ([sized array](@ref sizedarrays)) */
struct lysp_include *includes; /**< list of included submodules ([sized array](@ref sizedarrays)) */
- const char *filepath; /**< path, if the schema was read from a file, NULL in case of reading from memory */
const char *org; /**< party/company responsible for the module */
const char *contact; /**< contact information for the module */
const char *dsc; /**< description of the module */
@@ -793,7 +793,7 @@
* @brief YANG import-stmt
*/
struct lysc_import {
- struct lysc_module *module; /**< link to the imported module */
+ struct lys_module *module; /**< link to the imported module */
const char *prefix; /**< prefix for the data from the imported schema (mandatory) */
struct lysp_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
};
@@ -871,6 +871,7 @@
struct lysc_module {
struct ly_ctx *ctx; /**< libyang context of the module (mandatory) */
const char *name; /**< name of the module (mandatory) */
+ const char *filepath; /**< path, if the schema was read from a file, NULL in case of reading from memory */
const char *ns; /**< namespace of the module (mandatory) */
const char *prefix; /**< module prefix (mandatory) */
struct lysc_revision *revs; /**< list of the module revisions ([sized array](@ref sizedarrays)), the first revision
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index a9bd79f..e4d26b9 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -120,7 +120,7 @@
}
LY_ERR
-lysp_load_module(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct lys_module **mod)
+lysp_load_module(struct ly_ctx *ctx, const char *name, const char *revision, int implement, int require_parsed, struct lys_module **mod)
{
const char *submodule_data = NULL;
LYS_INFORMAT format = LYS_IN_UNKNOWN;
@@ -133,7 +133,9 @@
*mod = (struct lys_module*)ly_ctx_get_module_latest(ctx, name);
}
- if (!(*mod)) {
+ if (!(*mod) || (require_parsed && !(*mod)->parsed)) {
+ (*mod) = NULL;
+
/* check collision with other implemented revision */
if (implement && ly_ctx_get_module_implemented(ctx, name)) {
LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
@@ -293,7 +295,13 @@
/* search in imports */
LY_ARRAY_FOR(mod->imports, struct lysc_import, imp) {
if (!strncmp(imp->prefix, prefix, len) && mod->prefix[len] == '\0') {
- return imp->module;
+ if (!imp->module->compiled) {
+ /* shouldn't be needed, the function is internally used when
+ * the imported modules should be also compiled. But for sure
+ * and possible future optimizations, check it here */
+ lys_compile(imp->module->parsed, 0, &imp->module->compiled);
+ }
+ return imp->module->compiled;
}
}
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 58be352..f99d6f6 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -80,10 +80,13 @@
* @param[in] ctx libyang context.
* @param[in] name Name of the module to load.
* @param[in] revison Optional revision of the module to load. If NULL, the newest revision is loaded.
+ * @param[in] implement Flag if the loaded module is supposed to be marked as implemented.
+ * @param[in] require_parsed Flag to require parsed module structure in case the module is already in the context,
+ * but only the compiled structure is available.
* @param[out] mod Parsed module structure.
* @return LY_ERR value.
*/
-LY_ERR lysp_load_module(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct lys_module **mod);
+LY_ERR lysp_load_module(struct ly_ctx *ctx, const char *name, const char *revision, int implement, int require_parsed, struct lys_module **mod);
/**
* @brief Parse included submodule into the simply parsed YANG module.