context FEATURE add ly_ctx_new_ylpath and path
diff --git a/src/context.c b/src/context.c
index 5c240de..7ef2cde 100644
--- a/src/context.c
+++ b/src/context.c
@@ -42,6 +42,7 @@
#include "set.h"
#include "tree.h"
#include "tree_data.h"
+#include "tree_data_internal.h"
#include "tree_schema.h"
#include "tree_schema_internal.h"
@@ -290,6 +291,178 @@
return rc;
}
+static LY_ERR
+ly_ctx_new_yl_legacy(struct ly_ctx *ctx, struct lyd_node *yltree)
+{
+ struct lyd_node *module, *node;
+ struct ly_set *set;
+ const char **feature_arr = NULL;
+ const char *name = NULL, *revision = NULL;
+ struct ly_set features = {0};
+ ly_bool imported = 0;
+ const struct lys_module *mod;
+ LY_ERR ret = LY_SUCCESS;
+
+ LY_CHECK_RET(ret = lyd_find_xpath(yltree, "/ietf-yang-library:yang-library/modules-state/module", &set));
+
+ /* process the data tree */
+ for (uint32_t i = 0; i < set->count; ++i) {
+ module = set->dnodes[i];
+
+ /* initiate */
+ revision = NULL;
+ name = NULL;
+ imported = 0;
+
+ LY_LIST_FOR(lyd_child(module), node) {
+ if (!strcmp(node->schema->name, "name")) {
+ name = LYD_CANON_VALUE(node);
+ } else if (!strcmp(node->schema->name, "revision")) {
+ revision = LYD_CANON_VALUE(node);
+ } else if (!strcmp(node->schema->name, "feature")) {
+ LY_CHECK_GOTO(ret = ly_set_add(&features, node, 0, NULL), cleanup);
+ } else if (!strcmp(node->schema->name, "conformance-type") &&
+ !strcmp(LYD_CANON_VALUE(node), "import")) {
+ /* imported module - skip it, it will be loaded as a side effect
+ * of loading another module */
+ imported = 1;
+ break;
+ }
+ }
+
+ if (imported) {
+ continue;
+ }
+
+ feature_arr = malloc((features.count + 1) * sizeof *feature_arr);
+ LY_CHECK_ERR_GOTO(!feature_arr, ret = LY_EMEM, cleanup);
+
+ /* Parse features into an array of strings */
+ for (uint32_t u = 0; u < features.count; u++) {
+ feature_arr[u] = LYD_CANON_VALUE(features.dnodes[u]);
+ }
+ feature_arr[features.count] = NULL;
+ ly_set_clean(&features, free);
+
+ /* use the gathered data to load the module */
+ mod = ly_ctx_load_module(ctx, name, revision, feature_arr);
+ free(feature_arr);
+ if (!mod) {
+ LOGERR(ctx, LY_EINVAL, "Unable to load module specified by yang library data.");
+ ly_set_free(set, free);
+ return LY_EINVAL;
+ }
+ }
+
+cleanup:
+ ly_set_clean(&features, free);
+ ly_set_free(set, free);
+ return ret;
+}
+
+static LY_ERR
+ly_ctx_new_yl_common(const char *search_dir, const char *input, LYD_FORMAT format, int options,
+ LY_ERR (*parser_func)(const struct ly_ctx *, const char *, LYD_FORMAT, uint32_t, uint32_t, struct lyd_node **),
+ struct ly_ctx **ctx)
+{
+ const char *name = NULL, *revision = NULL;
+ struct lyd_node *module, *node;
+ struct lyd_node *yltree = NULL;
+ struct ly_set *set = NULL;
+ const char **feature_arr = NULL;
+ struct ly_set features = {0};
+ LY_ERR ret = LY_SUCCESS;
+ const struct lys_module *mod;
+ struct ly_ctx *ctx_yl = NULL, *ctx_new = NULL;
+
+ /* create a seperate context in case it is LY_CTX_NO_YANGLIBRARY since it needs it for parsing */
+ if (options & LY_CTX_NO_YANGLIBRARY) {
+ LY_CHECK_GOTO(ret = ly_ctx_new(search_dir, 0, &ctx_yl), cleanup);
+ LY_CHECK_GOTO(ret = ly_ctx_new(search_dir, options, &ctx_new), cleanup);
+ } else {
+ LY_CHECK_GOTO(ret = ly_ctx_new(search_dir, options, &ctx_yl), cleanup);
+ ctx_new = ctx_yl;
+ }
+
+ /* parse yang library data tree */
+ LY_CHECK_GOTO(ret = parser_func(ctx_yl, input, format, 0, LYD_VALIDATE_PRESENT, &yltree), cleanup);
+
+ LY_CHECK_GOTO(ret = lyd_find_xpath(yltree, "/ietf-yang-library:yang-library/module-set[1]/module", &set), cleanup);
+
+ if (set->count == 0) {
+ /* perhaps a legacy data tree? */
+ LY_CHECK_GOTO(ret = ly_ctx_new_yl_legacy(ctx_new, yltree), cleanup);
+ } else {
+ /* process the data tree */
+ for (uint32_t i = 0; i < set->count; ++i) {
+ module = set->dnodes[i];
+
+ /* initiate */
+ name = NULL;
+ revision = NULL;
+
+ /* Iterate over data */
+ LY_LIST_FOR(lyd_child(module), node) {
+ if (!strcmp(node->schema->name, "name")) {
+ name = LYD_CANON_VALUE(node);
+ } else if (!strcmp(node->schema->name, "revision")) {
+ revision = LYD_CANON_VALUE(node);
+ } else if (!strcmp(node->schema->name, "feature")) {
+ LY_CHECK_GOTO(ret = ly_set_add(&features, node, 0, NULL), cleanup);
+ }
+ }
+
+ feature_arr = malloc((features.count + 1) * sizeof *feature_arr);
+ LY_CHECK_ERR_GOTO(!feature_arr, ret = LY_EMEM, cleanup);
+
+ /* Parse features into an array of strings */
+ for (uint32_t u = 0; u < features.count; u++) {
+ feature_arr[u] = LYD_CANON_VALUE(features.dnodes[u]);
+ }
+ feature_arr[features.count] = NULL;
+ ly_set_clean(&features, NULL);
+
+ /* use the gathered data to load the module */
+ mod = ly_ctx_load_module(ctx_new, name, revision, feature_arr);
+ free(feature_arr);
+ if (!mod) {
+ LOGERR(NULL, LY_EINVAL, "Unable to load module specified by yang library data.");
+ ret = LY_EINVAL;
+ goto cleanup;
+ }
+ }
+ }
+
+cleanup:
+ lyd_free_all(yltree);
+ ly_set_free(set, NULL);
+ ly_set_erase(&features, NULL);
+ if (ctx_yl != ctx_new) {
+ ly_ctx_destroy(ctx_yl, NULL);
+ }
+ *ctx = ctx_new;
+ if (ret) {
+ ly_ctx_destroy(*ctx, NULL);
+ *ctx = NULL;
+ }
+
+ return ret;
+}
+
+API LY_ERR
+ly_ctx_new_ylpath(const char *search_dir, const char *path, LYD_FORMAT format, int options, struct ly_ctx **ctx)
+{
+ LY_CHECK_ARG_RET2(NULL, path, ctx, LY_EINVAL);
+ return ly_ctx_new_yl_common(search_dir, path, format, options, lyd_parse_data_path, ctx);
+}
+
+API LY_ERR
+ly_ctx_new_ylmem(const char *search_dir, const char *data, LYD_FORMAT format, int options, struct ly_ctx **ctx)
+{
+ LY_CHECK_ARG_RET(NULL, data, ctx, LY_EINVAL);
+ return ly_ctx_new_yl_common(search_dir, data, format, options, lyd_parse_data_mem, ctx);
+}
+
API uint16_t
ly_ctx_get_options(const struct ly_ctx *ctx)
{