yanglint FEATURE allow creating context from yanglib data
Refs #1780
diff --git a/tools/lint/main_ni.c b/tools/lint/main_ni.c
index bff705a..39e2694 100644
--- a/tools/lint/main_ni.c
+++ b/tools/lint/main_ni.c
@@ -34,6 +34,8 @@
*/
struct context {
/* libyang context for the run */
+ const char *yang_lib_file;
+ uint16_t ctx_options;
struct ly_ctx *ctx;
/* prepared output (--output option or stdout by default) */
@@ -215,8 +217,8 @@
printf(" -l, --list Print info about the loaded schemas.\n"
" (i - imported module, I - implemented module)\n"
- " In case the -f option with data encoding is specified,\n"
- " the list is printed as ietf-yang-library data.\n\n");
+ " In case the '-f' option with data encoding is specified,\n"
+ " the list is printed as \"ietf-yang-library\" data.\n\n");
printf(" -L LINE_LENGTH, --tree-line-length=LINE_LENGTH\n"
" The limit of the maximum line length on which the 'tree'\n"
@@ -239,6 +241,11 @@
" Note that this module includes definitions of mandatory state\n"
" data that can result in unexpected data validation errors.\n\n");
+ printf(" -Y FILE, --yang-library-file=FILE\n"
+ " Parse FILE with \"ietf-yang-library\" data and use them to\n"
+ " create an exact YANG schema context. If specified, the '-F'\n"
+ " parameter (enabled features) is ignored.\n\n");
+
#ifndef NDEBUG
printf(" -G GROUPS, --debug=GROUPS\n"
" Enable printing of specific debugging message group\n"
@@ -289,10 +296,41 @@
static int
fill_context_inputs(int argc, char *argv[], struct context *c)
{
- struct ly_in *in;
+ struct ly_in *in = NULL;
struct schema_features *sf;
struct lys_module *mod;
- const char *all_features[] = {"*", NULL};
+ const char *all_features[] = {"*", NULL}, *searchdir;
+ char *dir = NULL, *module = NULL;
+
+ /* get the first searchdir */
+ searchdir = c->searchpaths.count ? c->searchpaths.objs[0] : NULL;
+
+ if (c->yang_lib_file) {
+ /* ignore features */
+ ly_set_erase(&c->schema_features, free_features);
+
+ /* create context from the yang-library file */
+ if (ly_ctx_new_ylpath(searchdir, c->yang_lib_file, LYD_UNKNOWN, c->ctx_options, &c->ctx)) {
+ YLMSG_E("Unable to create libyang context from yang-library data.\n");
+ return -1;
+ }
+ } else {
+ /* set imp feature flag if all should be enabled */
+ if (!c->schema_features.count) {
+ c->ctx_options |= LY_CTX_ENABLE_IMP_FEATURES;
+ }
+
+ /* libyang context */
+ if (ly_ctx_new(searchdir, c->ctx_options, &c->ctx)) {
+ YLMSG_E("Unable to create libyang context.\n");
+ return -1;
+ }
+
+ /* set the rest of searchdirs */
+ for (uint32_t i = 1; i < c->searchpaths.count; ++i) {
+ ly_ctx_set_searchdir(c->ctx, c->searchpaths.objs[i]);
+ }
+ }
/* process the operational content if any */
if (c->data_operational.path) {
@@ -304,7 +342,6 @@
for (int i = 0; i < argc - optind; i++) {
LYS_INFORMAT format_schema = LYS_IN_UNKNOWN;
LYD_FORMAT format_data = LYD_UNKNOWN;
- in = NULL;
if (get_input(argv[optind + i], &format_schema, &format_data, &in)) {
goto error;
@@ -313,42 +350,51 @@
if (format_schema) {
LY_ERR ret;
uint8_t path_unset = 1; /* flag to unset the path from the searchpaths list (if not already present) */
- char *dir, *module;
const char **features;
struct lys_module *mod;
+ /* parse the input */
if (parse_schema_path(argv[optind + i], &dir, &module)) {
goto error;
}
- /* add temporarily also the path of the module itself */
- if (ly_ctx_set_searchdir(c->ctx, dir) == LY_EEXIST) {
- path_unset = 0;
- }
-
- /* get features list for this module */
- if (!c->schema_features.count) {
- features = all_features;
+ if (c->yang_lib_file) {
+ /* just get the module, it should already be parsed */
+ mod = ly_ctx_get_module_implemented(c->ctx, module);
+ if (!mod) {
+ YLMSG_E("Schema module \"%s\" not implemented in yang-library data.\n", module);
+ goto error;
+ }
} else {
- get_features(&c->schema_features, module, &features);
+ /* add temporarily also the path of the module itself */
+ if (ly_ctx_set_searchdir(c->ctx, dir) == LY_EEXIST) {
+ path_unset = 0;
+ }
+
+ /* get features list for this module */
+ if (!c->schema_features.count) {
+ features = all_features;
+ } else {
+ get_features(&c->schema_features, module, &features);
+ }
+
+ /* parse module */
+ ret = lys_parse(c->ctx, in, format_schema, features, &mod);
+ ly_ctx_unset_searchdir_last(c->ctx, path_unset);
+ if (ret) {
+ YLMSG_E("Parsing schema module \"%s\" failed.\n", argv[optind + i]);
+ goto error;
+ }
}
/* temporary cleanup */
free(dir);
+ dir = NULL;
free(module);
-
- /* parse module */
- ret = lys_parse(c->ctx, in, format_schema, features, &mod);
- ly_ctx_unset_searchdir_last(c->ctx, path_unset);
- ly_in_free(in, 1);
- in = NULL;
- if (ret) {
- YLMSG_E("Parsing schema module \"%s\" failed.\n", argv[optind + i]);
- goto error;
- }
+ module = NULL;
if (c->schema_out_format) {
- /* modules will be printed */
+ /* module will be printed */
if (ly_set_add(&c->schema_modules, (void *)mod, 1, NULL)) {
YLMSG_E("Storing parsed schema module (%s) for print failed.\n", argv[optind + i]);
goto error;
@@ -359,10 +405,10 @@
goto error;
}
in = NULL;
- } else {
- ly_in_free(in, 1);
- in = NULL;
}
+
+ ly_in_free(in, 1);
+ in = NULL;
}
/* check that all specified features were applied, apply now if possible */
@@ -389,6 +435,8 @@
error:
ly_in_free(in, 1);
+ free(dir);
+ free(module);
return -1;
}
@@ -406,45 +454,45 @@
int opt, opt_index;
struct option options[] = {
- {"help", no_argument, NULL, 'h'},
- {"version", no_argument, NULL, 'v'},
- {"verbose", no_argument, NULL, 'V'},
- {"quiet", no_argument, NULL, 'Q'},
- {"format", required_argument, NULL, 'f'},
- {"path", required_argument, NULL, 'p'},
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'v'},
+ {"verbose", no_argument, NULL, 'V'},
+ {"quiet", no_argument, NULL, 'Q'},
+ {"format", required_argument, NULL, 'f'},
+ {"path", required_argument, NULL, 'p'},
{"disable-searchdir", no_argument, NULL, 'D'},
- {"features", required_argument, NULL, 'F'},
- {"make-implemented", no_argument, NULL, 'i'},
- {"schema-node", required_argument, NULL, 'P'},
- {"single-node", no_argument, NULL, 'q'},
- {"submodule", required_argument, NULL, 's'},
- {"not-strict", no_argument, NULL, 'n'},
- {"present", no_argument, NULL, 'e'},
- {"type", required_argument, NULL, 't'},
- {"default", required_argument, NULL, 'd'},
- {"list", no_argument, NULL, 'l'},
- {"tree-line-length", required_argument, NULL, 'L'},
- {"output", required_argument, NULL, 'o'},
- {"operational", required_argument, NULL, 'O'},
- {"merge", no_argument, NULL, 'm'},
- {"yang-library", no_argument, NULL, 'y'},
+ {"features", required_argument, NULL, 'F'},
+ {"make-implemented", no_argument, NULL, 'i'},
+ {"schema-node", required_argument, NULL, 'P'},
+ {"single-node", no_argument, NULL, 'q'},
+ {"submodule", required_argument, NULL, 's'},
+ {"not-strict", no_argument, NULL, 'n'},
+ {"present", no_argument, NULL, 'e'},
+ {"type", required_argument, NULL, 't'},
+ {"default", required_argument, NULL, 'd'},
+ {"list", no_argument, NULL, 'l'},
+ {"tree-line-length", required_argument, NULL, 'L'},
+ {"output", required_argument, NULL, 'o'},
+ {"operational", required_argument, NULL, 'O'},
+ {"merge", no_argument, NULL, 'm'},
+ {"yang-library", no_argument, NULL, 'y'},
+ {"yang-library-file", required_argument, NULL, 'Y'},
#ifndef NDEBUG
{"debug", required_argument, NULL, 'G'},
#endif
{NULL, 0, NULL, 0}
};
-
- uint16_t options_ctx = YL_DEFAULT_CTX_OPTIONS;
uint8_t data_type_set = 0;
+ c->ctx_options = YL_DEFAULT_CTX_OPTIONS;
c->data_parse_options = YL_DEFAULT_DATA_PARSE_OPTIONS;
c->line_length = 0;
opterr = 0;
#ifndef NDEBUG
- while ((opt = getopt_long(argc, argv, "hvVQf:p:DF:iP:qs:net:d:lL:o:OmyG:", options, &opt_index)) != -1) {
+ while ((opt = getopt_long(argc, argv, "hvVQf:p:DF:iP:qs:net:d:lL:o:OmyY:G:", options, &opt_index)) != -1) {
#else
- while ((opt = getopt_long(argc, argv, "hvVQf:p:DF:iP:qs:net:d:lL:o:Omy", options, &opt_index)) != -1) {
+ while ((opt = getopt_long(argc, argv, "hvVQf:p:DF:iP:qs:net:d:lL:o:OmyY:", options, &opt_index)) != -1) {
#endif
switch (opt) {
case 'h': /* --help */
@@ -523,14 +571,14 @@
} /* case 'p' */
case 'D': /* --disable-search */
- if (options_ctx & LY_CTX_DISABLE_SEARCHDIRS) {
+ if (c->ctx_options & LY_CTX_DISABLE_SEARCHDIRS) {
YLMSG_W("The -D option specified too many times.\n");
}
- if (options_ctx & LY_CTX_DISABLE_SEARCHDIR_CWD) {
- options_ctx &= ~LY_CTX_DISABLE_SEARCHDIR_CWD;
- options_ctx |= LY_CTX_DISABLE_SEARCHDIRS;
+ if (c->ctx_options & LY_CTX_DISABLE_SEARCHDIR_CWD) {
+ c->ctx_options &= ~LY_CTX_DISABLE_SEARCHDIR_CWD;
+ c->ctx_options |= LY_CTX_DISABLE_SEARCHDIRS;
} else {
- options_ctx |= LY_CTX_DISABLE_SEARCHDIR_CWD;
+ c->ctx_options |= LY_CTX_DISABLE_SEARCHDIR_CWD;
}
break;
@@ -541,11 +589,11 @@
break;
case 'i': /* --make-implemented */
- if (options_ctx & LY_CTX_REF_IMPLEMENTED) {
- options_ctx &= ~LY_CTX_REF_IMPLEMENTED;
- options_ctx |= LY_CTX_ALL_IMPLEMENTED;
+ if (c->ctx_options & LY_CTX_REF_IMPLEMENTED) {
+ c->ctx_options &= ~LY_CTX_REF_IMPLEMENTED;
+ c->ctx_options |= LY_CTX_ALL_IMPLEMENTED;
} else {
- options_ctx |= LY_CTX_REF_IMPLEMENTED;
+ c->ctx_options |= LY_CTX_REF_IMPLEMENTED;
}
break;
@@ -650,7 +698,12 @@
break;
case 'y': /* --yang-library */
- options_ctx &= ~LY_CTX_NO_YANGLIBRARY;
+ c->ctx_options &= ~LY_CTX_NO_YANGLIBRARY;
+ break;
+
+ case 'Y': /* --yang-library-file */
+ c->ctx_options &= ~LY_CTX_NO_YANGLIBRARY;
+ c->yang_lib_file = optarg;
break;
#ifndef NDEBUG
@@ -688,20 +741,6 @@
} /* switch */
}
- /* set imp feature flag if all should be enabled */
- if (!c->schema_features.count) {
- options_ctx |= LY_CTX_ENABLE_IMP_FEATURES;
- }
-
- /* libyang context */
- if (ly_ctx_new(NULL, options_ctx, &c->ctx)) {
- YLMSG_E("Unable to create libyang context.\n");
- return -1;
- }
- for (uint32_t u = 0; u < c->searchpaths.count; ++u) {
- ly_ctx_set_searchdir(c->ctx, c->searchpaths.objs[u]);
- }
-
/* additional checks for the options combinations */
if (!c->list && (optind >= argc)) {
help(1);
@@ -738,7 +777,7 @@
if (c->schema_out_format == LYS_OUT_TREE) {
/* print tree from lysc_nodes */
- ly_ctx_set_options(c->ctx, LY_CTX_SET_PRIV_PARSED);
+ c->ctx_options |= LY_CTX_SET_PRIV_PARSED;
}
/* process input files provided as standalone command line arguments,