yanglint FEATURE initial version of yanglint(1)

Source codes are mostly taken from libyang 1.0 and slightly modified for
libyang 2.0. A lot of functionality is still missing since it is not yet
provided by libyang 2.0
diff --git a/tools/config.h.in b/tools/config.h.in
new file mode 100644
index 0000000..f65d92d
--- /dev/null
+++ b/tools/config.h.in
@@ -0,0 +1,23 @@
+/**
+ * @file config.h
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief various variables detected by cmake
+ *
+ * Copyright (c) 2019 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#ifndef YANGLINT_CONFIG_H_
+#define YANGLINT_CONFIG_H_
+
+#define _DEFAULT_SOURCE
+#define _GNU_SOURCE
+
+#define PROJECT_VERSION "@LIBYANG_VERSION@" /**< libyang project version string */
+
+#endif /* YANGLINT_CONFIG_H_ */
diff --git a/tools/lint/commands.c b/tools/lint/commands.c
new file mode 100644
index 0000000..0e7913a
--- /dev/null
+++ b/tools/lint/commands.c
@@ -0,0 +1,1551 @@
+/**
+ * @file commands.c
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief libyang's yanglint tool commands
+ *
+ * Copyright (c) 2015 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <libgen.h>
+
+#include "commands.h"
+#include "libyang.h"
+
+COMMAND commands[];
+extern int done;
+extern struct ly_ctx *ctx;
+
+void
+cmd_add_help(void)
+{
+    printf("add [-i] <path-to-model> [<paths-to-other-models> ...]\n");
+    printf("\t-i         - make all the imported modules implemented\n");
+}
+
+void
+cmd_load_help(void)
+{
+    printf("load [-i] <model-name> [<other-model-names> ...]\n");
+    printf("\t-i         - make all the imported modules implemented\n");
+}
+
+void
+cmd_clear_help(void)
+{
+    printf("clear [<yang-library> | -e]\n");
+    printf("\t Replace the current context with an empty one, searchpaths are not kept.\n");
+    printf("\t If <yang-library> path specified, load the modules according to the yang library data.\n");
+    printf("\t Option '-e' causes ietf-yang-library will not be loaded.\n");
+}
+
+void
+cmd_print_help(void)
+{
+    printf("print [-f (yang | yin | tree [<tree-options>] | info [-P <info-path>] | jsons)] [-o <output-file>]"
+           " <model-name>[@<revision>]\n");
+    printf("\n");
+    printf("\ttree-options:\t--tree-print-groupings\t(print top-level groupings in a separate section)\n");
+    printf("\t             \t--tree-print-uses\t(print uses nodes instead the resolved grouping nodes)\n");
+    printf("\t             \t--tree-no-leafref-target\t(do not print the target nodes of leafrefs)\n");
+    printf("\t             \t--tree-path <schema-path>\t(print only the specified subtree)\n");
+    printf("\t             \t--tree-line-length <line-length>\t(wrap lines if longer than line-length,\n");
+    printf("\t             \t\tnot a strict limit, longer lines can often appear)\n");
+    printf("\n");
+    printf("\tinfo-path:\t<schema-path> | typedef[<schema-path>]/<typedef-name> |\n");
+    printf("\t          \t| identity/<identity-name> | feature/<feature-name> |\n");
+    printf("\t          \t| grouping[<schema-path>]/<grouping-name> |\n");
+    printf("\t          \t| type/<schema-path-leaf-or-leaflist>\n");
+    printf("\n");
+    printf("\tschema-path:\t( /<module-name>:<node-identifier> )+\n");
+}
+
+void
+cmd_data_help(void)
+{
+    printf("data [-(-s)trict] [-t TYPE] [-d DEFAULTS] [-o <output-file>] [-f (xml | json | lyb)] [-r <running-file-name>]\n");
+    printf("     <data-file-name> [<RPC/action-data-file-name> | <yang-data name>]\n\n");
+    printf("Accepted TYPEs:\n");
+    printf("\tauto       - resolve data type (one of the following) automatically (as pyang does),\n");
+    printf("\t             this option is applicable only in case of XML input data.\n");
+    printf("\tdata       - LYD_OPT_DATA (default value) - complete datastore including status data.\n");
+    printf("\tconfig     - LYD_OPT_CONFIG - complete configuration datastore.\n");
+    printf("\tget        - LYD_OPT_GET - <get> operation result.\n");
+    printf("\tgetconfig  - LYD_OPT_GETCONFIG - <get-config> operation result.\n");
+    printf("\tedit       - LYD_OPT_EDIT - <edit-config>'s data (content of its <config> element).\n");
+    printf("\trpc        - LYD_OPT_RPC - NETCONF RPC message.\n");
+    printf("\trpcreply   - LYD_OPT_RPCREPLY (last parameter mandatory in this case)\n");
+    printf("\tnotif      - LYD_OPT_NOTIF - NETCONF Notification message.\n");
+    printf("\tyangdata   - LYD_OPT_DATA_TEMPLATE - yang-data extension (last parameter mandatory in this case)\n\n");
+    printf("Accepted DEFAULTS:\n");
+    printf("\tall        - add missing default nodes\n");
+    printf("\tall-tagged - add missing default nodes and mark all the default nodes with the attribute.\n");
+    printf("\ttrim       - remove all nodes with a default value\n");
+    printf("\timplicit-tagged    - add missing nodes and mark them with the attribute\n\n");
+    printf("Option -r:\n");
+    printf("\tOptional parameter for 'rpc', 'rpcreply' and 'notif' TYPEs, the file contains running\n");
+    printf("\tconfiguration datastore data referenced from the RPC/Notification. Note that the file is\n");
+    printf("\tvalidated as 'data' TYPE. Special value '!' can be used as argument to ignore the\n");
+    printf("\texternal references.\n\n");
+    printf("\tIf an XPath expression (when/must) needs access to configuration data, you can provide\n");
+    printf("\tthem in a file, which will be parsed as 'data' TYPE.\n\n");
+}
+
+void
+cmd_xpath_help(void)
+{
+    printf("xpath [-t TYPE] [-x <additional-tree-file-name>] -e <XPath-expression>\n"
+           "      <XML-data-file-name> [<JSON-rpc/action-schema-nodeid>]\n");
+    printf("Accepted TYPEs:\n");
+    printf("\tauto       - resolve data type (one of the following) automatically (as pyang does),\n");
+    printf("\t             this option is applicable only in case of XML input data.\n");
+    printf("\tconfig     - LYD_OPT_CONFIG\n");
+    printf("\tget        - LYD_OPT_GET\n");
+    printf("\tgetconfig  - LYD_OPT_GETCONFIG\n");
+    printf("\tedit       - LYD_OPT_EDIT\n");
+    printf("\trpc        - LYD_OPT_RPC\n");
+    printf("\trpcreply   - LYD_OPT_RPCREPLY (last parameter mandatory in this case)\n");
+    printf("\tnotif      - LYD_OPT_NOTIF\n\n");
+    printf("Option -x:\n");
+    printf("\tIf RPC/action/notification/RPC reply (for TYPEs 'rpc', 'rpcreply', and 'notif') includes\n");
+    printf("\tan XPath expression (when/must) that needs access to the configuration data, you can provide\n");
+    printf("\tthem in a file, which will be parsed as 'config'.\n");
+}
+
+void
+cmd_list_help(void)
+{
+    printf("list [-f (xml | json)]\n\n");
+    printf("\tBasic list output (no -f): i - imported module, I - implemented module\n");
+}
+
+void
+cmd_feature_help(void)
+{
+    printf("feature [ -(-e)nable | -(-d)isable (* | <feature-name>[,<feature-name> ...]) ] <model-name>[@<revision>]\n");
+}
+
+void
+cmd_searchpath_help(void)
+{
+    printf("searchpath [<model-dir-path> | --clear]\n\n");
+    printf("\tThey are used to search for imports and includes of a model.\n");
+    printf("\tThe \"load\" command uses these directories to find models directly.\n");
+}
+
+void
+cmd_verb_help(void)
+{
+    printf("verb (error/0 | warning/1 | verbose/2 | debug/3)\n");
+}
+
+#ifndef NDEBUG
+
+void
+cmd_debug_help(void)
+{
+    printf("debug (dict | yang | yin | xpath | diff)+\n");
+}
+
+#endif
+
+LYS_INFORMAT
+get_schema_format(const char *path)
+{
+    char *ptr;
+
+    if ((ptr = strrchr(path, '.')) != NULL) {
+        ++ptr;
+        if (!strcmp(ptr, "yang")) {
+            return LYS_IN_YANG;
+        /* TODO YIN parser not yet implemented
+        } else if (!strcmp(ptr, "yin")) {
+             return LYS_IN_YIN;
+        */
+        } else {
+            fprintf(stderr, "Input file in an unknown format \"%s\".\n", ptr);
+            return LYS_IN_UNKNOWN;
+        }
+    } else {
+        fprintf(stdout, "Input file \"%s\" without extension - unknown format.\n", path);
+        return LYS_IN_UNKNOWN;
+    }
+}
+
+int
+cmd_add(const char *arg)
+{
+    int path_len, ret = 1, index = 0;
+    char *path, *dir, *s, *arg_ptr;
+    const char * const *searchpaths;
+    const struct lys_module *model;
+    LYS_INFORMAT format = LYS_IN_UNKNOWN;
+
+    if (strlen(arg) < 5) {
+        cmd_add_help();
+        return 1;
+    }
+
+    arg_ptr = strdup(arg + 3 /* ignore "add" */);
+
+    for (s = strstr(arg_ptr, "-i"); s ; s = strstr(s + 2, "-i")) {
+        if (s[2] == '\0' || s[2] == ' ') {
+            ly_ctx_set_option(ctx, LY_CTX_ALLIMPLEMENTED);
+            s[0] = s[1] = ' ';
+        }
+    }
+    s = arg_ptr;
+
+    while (arg_ptr[0] == ' ') {
+        ++arg_ptr;
+    }
+    if (strchr(arg_ptr, ' ')) {
+        path_len = strchr(arg_ptr, ' ') - arg_ptr;
+    } else {
+        path_len = strlen(arg_ptr);
+    }
+    path = strndup(arg_ptr, path_len);
+
+    searchpaths = ly_ctx_get_searchdirs(ctx);
+    if (searchpaths) {
+        for (index = 0; searchpaths[index]; index++);
+    }
+
+    while (path) {
+        format = get_schema_format(path);
+        if (format == LYS_IN_UNKNOWN) {
+            free(path);
+            goto cleanup;
+        }
+
+        dir = strdup(path);
+        ly_ctx_set_searchdir(ctx, dirname(dir));
+        model = lys_parse_path(ctx, path, format);
+        ly_ctx_unset_searchdir(ctx, index);
+        free(path);
+        free(dir);
+
+        if (!model) {
+            /* libyang printed the error messages */
+            goto cleanup;
+        }
+
+        /* next model */
+        arg_ptr += path_len;
+        while (arg_ptr[0] == ' ') {
+            ++arg_ptr;
+        }
+        if (strchr(arg_ptr, ' ')) {
+            path_len = strchr(arg_ptr, ' ') - arg_ptr;
+        } else {
+            path_len = strlen(arg_ptr);
+        }
+
+        if (path_len) {
+            path = strndup(arg_ptr, path_len);
+        } else {
+            path = NULL;
+        }
+    }
+    if (format == LYS_IN_UNKNOWN) {
+        /* no schema on input */
+        cmd_add_help();
+        goto cleanup;
+    }
+    ret = 0;
+
+cleanup:
+    free(s);
+    ly_ctx_unset_option(ctx, LY_CTX_ALLIMPLEMENTED);
+
+    return ret;
+}
+
+int
+cmd_load(const char *arg)
+{
+    int name_len, ret = 1;
+    char *name, *s, *arg_ptr;
+    const struct lys_module *model;
+
+    if (strlen(arg) < 6) {
+        cmd_load_help();
+        return 1;
+    }
+
+    arg_ptr = strdup(arg + 4 /* ignore "load" */);
+
+    for (s = strstr(arg_ptr, "-i"); s ; s = strstr(s + 2, "-i")) {
+        if (s[2] == '\0' || s[2] == ' ') {
+            ly_ctx_set_option(ctx, LY_CTX_ALLIMPLEMENTED);
+            s[0] = s[1] = ' ';
+        }
+    }
+    s = arg_ptr;
+
+    while (arg_ptr[0] == ' ') {
+        ++arg_ptr;
+    }
+    if (strchr(arg_ptr, ' ')) {
+        name_len = strchr(arg_ptr, ' ') - arg_ptr;
+    } else {
+        name_len = strlen(arg_ptr);
+    }
+    name = strndup(arg_ptr, name_len);
+
+    while (name) {
+        model = ly_ctx_load_module(ctx, name, NULL);
+        free(name);
+        if (!model) {
+            /* libyang printed the error messages */
+            goto cleanup;
+        }
+
+        /* next model */
+        arg_ptr += name_len;
+        while (arg_ptr[0] == ' ') {
+            ++arg_ptr;
+        }
+        if (strchr(arg_ptr, ' ')) {
+            name_len = strchr(arg_ptr, ' ') - arg_ptr;
+        } else {
+            name_len = strlen(arg_ptr);
+        }
+
+        if (name_len) {
+            name = strndup(arg_ptr, name_len);
+        } else {
+            name = NULL;
+        }
+    }
+    ret = 0;
+
+cleanup:
+    free(s);
+    ly_ctx_unset_option(ctx, LY_CTX_ALLIMPLEMENTED);
+
+    return ret;
+}
+
+int
+cmd_print(const char *arg)
+{
+    int c, argc, option_index, ret = 1, tree_ll = 0, tree_opts = 0;
+    char **argv = NULL, *ptr, *model_name, *revision;
+    const char *out_path = NULL;
+    const struct lys_module *module;
+    LYS_OUTFORMAT format = LYS_OUT_TREE;
+    FILE *output = stdout;
+    static struct option long_options[] = {
+        {"help", no_argument, 0, 'h'},
+        {"format", required_argument, 0, 'f'},
+        {"output", required_argument, 0, 'o'},
+#if 0
+        {"tree-print-groupings", no_argument, 0, 'g'},
+        {"tree-print-uses", no_argument, 0, 'u'},
+        {"tree-no-leafref-target", no_argument, 0, 'n'},
+        {"tree-path", required_argument, 0, 'P'},
+        {"info-path", required_argument, 0, 'P'},
+        {"tree-line-length", required_argument, 0, 'L'},
+#endif
+        {NULL, 0, 0, 0}
+    };
+    void *rlcd;
+
+    argc = 1;
+    argv = malloc(2*sizeof *argv);
+    *argv = strdup(arg);
+    ptr = strtok(*argv, " ");
+    while ((ptr = strtok(NULL, " "))) {
+        rlcd = realloc(argv, (argc+2)*sizeof *argv);
+        if (!rlcd) {
+            fprintf(stderr, "Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+            goto cleanup;
+        }
+        argv = rlcd;
+        argv[argc++] = ptr;
+    }
+    argv[argc] = NULL;
+
+    optind = 0;
+    while (1) {
+        option_index = 0;
+        c = getopt_long(argc, argv, "hf:go:guP:L:", long_options, &option_index);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+        case 'h':
+            cmd_print_help();
+            ret = 0;
+            goto cleanup;
+        case 'f':
+            if (!strcmp(optarg, "yang")) {
+                format = LYS_OUT_YANG;
+#if 0
+            } else if (!strcmp(optarg, "yin")) {
+                format = LYS_OUT_YIN;
+            } else if (!strcmp(optarg, "tree")) {
+                format = LYS_OUT_TREE;
+            } else if (!strcmp(optarg, "tree-rfc")) {
+                format = LYS_OUT_TREE;
+                tree_opts |= LYS_OUTOPT_TREE_RFC;
+            } else if (!strcmp(optarg, "info")) {
+                format = LYS_OUT_INFO;
+            } else if (!strcmp(optarg, "jsons")) {
+                format = LYS_OUT_JSON;
+#endif
+            } else {
+                fprintf(stderr, "Unknown output format \"%s\".\n", optarg);
+                goto cleanup;
+            }
+            break;
+        case 'o':
+            if (out_path) {
+                fprintf(stderr, "Output specified twice.\n");
+                goto cleanup;
+            }
+            out_path = optarg;
+            break;
+#if 0
+        case 'g':
+            tree_opts |= LYS_OUTOPT_TREE_GROUPING;
+            break;
+        case 'u':
+            tree_opts |= LYS_OUTOPT_TREE_USES;
+            break;
+        case 'n':
+            tree_opts |= LYS_OUTOPT_TREE_NO_LEAFREF;
+            break;
+        case 'P':
+            target_path = optarg;
+            break;
+        case 'L':
+            tree_ll = atoi(optarg);
+            break;
+#endif
+        case '?':
+            fprintf(stderr, "Unknown option \"%d\".\n", (char)c);
+            goto cleanup;
+        }
+    }
+
+    /* file name */
+    if (optind == argc) {
+        fprintf(stderr, "Missing the module name.\n");
+        goto cleanup;
+    }
+
+    /* tree fromat with or without gropings */
+    if ((tree_opts || tree_ll) && format != LYS_OUT_TREE) {
+        fprintf(stderr, "--tree options take effect only in case of the tree output format.\n");
+    }
+
+    /* module, revision */
+    model_name = argv[optind];
+    revision = NULL;
+    if (strchr(model_name, '@')) {
+        revision = strchr(model_name, '@');
+        revision[0] = '\0';
+        ++revision;
+    }
+
+    if (revision) {
+        module = ly_ctx_get_module(ctx, model_name, revision);
+    } else {
+        module = ly_ctx_get_module_latest(ctx, model_name);
+    }
+#if 0
+    if (!module) {
+        /* not a module, try to find it as a submodule */
+        module = (const struct lys_module *)ly_ctx_get_submodule(ctx, NULL, NULL, model_name, revision);
+    }
+#endif
+
+    if (!module) {
+        if (revision) {
+            fprintf(stderr, "No (sub)module \"%s\" in revision %s found.\n", model_name, revision);
+        } else {
+            fprintf(stderr, "No (sub)module \"%s\" found.\n", model_name);
+        }
+        goto cleanup;
+    }
+
+    if (out_path) {
+        output = fopen(out_path, "w");
+        if (!output) {
+            fprintf(stderr, "Could not open the output file (%s).\n", strerror(errno));
+            goto cleanup;
+        }
+    }
+
+    ret = lys_print_file(output, module, format, tree_ll, tree_opts);
+    if (format == LYS_OUT_JSON) {
+        fputs("\n", output);
+    }
+
+cleanup:
+    free(*argv);
+    free(argv);
+
+    if (output && (output != stdout)) {
+        fclose(output);
+    }
+
+    return ret;
+}
+#if 0
+static LYD_FORMAT
+detect_data_format(char *filepath)
+{
+    size_t len;
+
+    /* detect input format according to file suffix */
+    len = strlen(filepath);
+    for (; isspace(filepath[len - 1]); len--, filepath[len] = '\0'); /* remove trailing whitespaces */
+    if (len >= 5 && !strcmp(&filepath[len - 4], ".xml")) {
+        return LYD_XML;
+    } else if (len >= 6 && !strcmp(&filepath[len - 5], ".json")) {
+        return LYD_JSON;
+    } else if (len >= 5 && !strcmp(&filepath[len - 4], ".lyb")) {
+        return LYD_LYB;
+    } else {
+        return LYD_UNKNOWN;
+    }
+}
+
+static int
+parse_data(char *filepath, int *options, struct lyd_node *val_tree, const char *rpc_act_file,
+           struct lyd_node **result)
+{
+    LYD_FORMAT informat = LYD_UNKNOWN;
+    struct lyxml_elem *xml = NULL;
+    struct lyd_node *data = NULL, *rpc_act = NULL;
+    int opts = *options;
+
+    /* detect input format according to file suffix */
+    informat = detect_data_format(filepath);
+    if (informat == LYD_UNKNOWN) {
+        fprintf(stderr, "Unable to resolve format of the input file, please add \".xml\", \".json\", or \".lyb\" suffix.\n");
+        return EXIT_FAILURE;
+    }
+
+    ly_errno = LY_SUCCESS;
+
+    if ((opts & LYD_OPT_TYPEMASK) == LYD_OPT_TYPEMASK) {
+        /* automatically detect data type from the data top level */
+        if (informat != LYD_XML) {
+            fprintf(stderr, "Only XML data can be automatically explored.\n");
+            return EXIT_FAILURE;
+        }
+
+        xml = lyxml_parse_path(ctx, filepath, 0);
+        if (!xml) {
+            fprintf(stderr, "Failed to parse XML data for automatic type detection.\n");
+            return EXIT_FAILURE;
+        }
+
+        /* NOTE: namespace is ignored to simplify usage of this feature */
+
+        if (!strcmp(xml->name, "data")) {
+            fprintf(stdout, "Parsing %s as complete datastore.\n", filepath);
+            opts = (opts & ~LYD_OPT_TYPEMASK) | LYD_OPT_DATA_ADD_YANGLIB;
+        } else if (!strcmp(xml->name, "config")) {
+            fprintf(stdout, "Parsing %s as config data.\n", filepath);
+            opts = (opts & ~LYD_OPT_TYPEMASK) | LYD_OPT_CONFIG;
+        } else if (!strcmp(xml->name, "get-reply")) {
+            fprintf(stdout, "Parsing %s as <get> reply data.\n", filepath);
+            opts = (opts & ~LYD_OPT_TYPEMASK) | LYD_OPT_GET;
+        } else if (!strcmp(xml->name, "get-config-reply")) {
+            fprintf(stdout, "Parsing %s as <get-config> reply data.\n", filepath);
+            opts = (opts & ~LYD_OPT_TYPEMASK) | LYD_OPT_GETCONFIG;
+        } else if (!strcmp(xml->name, "edit-config")) {
+            fprintf(stdout, "Parsing %s as <edit-config> data.\n", filepath);
+            opts = (opts & ~LYD_OPT_TYPEMASK) | LYD_OPT_EDIT;
+        } else if (!strcmp(xml->name, "rpc")) {
+            fprintf(stdout, "Parsing %s as <rpc> data.\n", filepath);
+            opts = (opts & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPC;
+        } else if (!strcmp(xml->name, "rpc-reply")) {
+            if (!rpc_act_file) {
+                fprintf(stderr, "RPC/action reply data require additional argument (file with the RPC/action).\n");
+                lyxml_free(ctx, xml);
+                return EXIT_FAILURE;
+            }
+            fprintf(stdout, "Parsing %s as <rpc-reply> data.\n", filepath);
+            opts = (opts & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPCREPLY;
+            rpc_act = lyd_parse_path(ctx, rpc_act_file, informat, LYD_OPT_RPC, val_tree);
+            if (!rpc_act) {
+                fprintf(stderr, "Failed to parse RPC/action.\n");
+                lyxml_free(ctx, xml);
+                return EXIT_FAILURE;
+            }
+        } else if (!strcmp(xml->name, "notification")) {
+            fprintf(stdout, "Parsing %s as <notification> data.\n", filepath);
+            opts = (opts & ~LYD_OPT_TYPEMASK) | LYD_OPT_NOTIF;
+        } else if (!strcmp(xml->name, "yang-data")) {
+            fprintf(stdout, "Parsing %s as <yang-data> data.\n", filepath);
+            opts = (opts & ~LYD_OPT_TYPEMASK) | LYD_OPT_DATA_TEMPLATE;
+            if (!rpc_act_file) {
+                fprintf(stderr, "YANG-DATA require additional argument (name instance of yang-data extension).\n");
+                lyxml_free(ctx, xml);
+                return EXIT_FAILURE;
+            }
+        } else {
+            fprintf(stderr, "Invalid top-level element for automatic data type recognition.\n");
+            lyxml_free(ctx, xml);
+            return EXIT_FAILURE;
+        }
+
+        if (opts & LYD_OPT_RPCREPLY) {
+            data = lyd_parse_xml(ctx, &xml->child, opts, rpc_act, val_tree);
+        } else if (opts & (LYD_OPT_RPC | LYD_OPT_NOTIF)) {
+            data = lyd_parse_xml(ctx, &xml->child, opts, val_tree);
+        } else if (opts & LYD_OPT_DATA_TEMPLATE) {
+            data = lyd_parse_xml(ctx, &xml->child, opts, rpc_act_file);
+        } else {
+            data = lyd_parse_xml(ctx, &xml->child, opts);
+        }
+        lyxml_free(ctx, xml);
+    } else {
+        if (opts & LYD_OPT_RPCREPLY) {
+            if (!rpc_act_file) {
+                fprintf(stderr, "RPC/action reply data require additional argument (file with the RPC/action).\n");
+                return EXIT_FAILURE;
+            }
+            rpc_act = lyd_parse_path(ctx, rpc_act_file, informat, LYD_OPT_RPC, val_tree);
+            if (!rpc_act) {
+                fprintf(stderr, "Failed to parse RPC/action.\n");
+                return EXIT_FAILURE;
+            }
+            data = lyd_parse_path(ctx, filepath, informat, opts, rpc_act, val_tree);
+        } else if (opts & (LYD_OPT_RPC | LYD_OPT_NOTIF)) {
+            data = lyd_parse_path(ctx, filepath, informat, opts, val_tree);
+        } else if (opts & LYD_OPT_DATA_TEMPLATE) {
+            if (!rpc_act_file) {
+                fprintf(stderr, "YANG-DATA require additional argument (name instance of yang-data extension).\n");
+                return EXIT_FAILURE;
+            }
+            data = lyd_parse_path(ctx, filepath, informat, opts, rpc_act_file);
+        } else {
+            if (!(opts & LYD_OPT_TYPEMASK)) {
+                /* automatically add yang-library data */
+                opts |= LYD_OPT_DATA_ADD_YANGLIB;
+            }
+            data = lyd_parse_path(ctx, filepath, informat, opts);
+        }
+    }
+    lyd_free_withsiblings(rpc_act);
+
+    if (ly_errno) {
+        fprintf(stderr, "Failed to parse data.\n");
+        lyd_free_withsiblings(data);
+        return EXIT_FAILURE;
+    }
+
+    *result = data;
+    *options = opts;
+    return EXIT_SUCCESS;
+}
+
+int
+cmd_data(const char *arg)
+{
+    int c, argc, option_index, ret = 1;
+    int options = 0, printopt = 0;
+    char **argv = NULL, *ptr;
+    const char *out_path = NULL;
+    struct lyd_node *data = NULL, *val_tree = NULL;
+    LYD_FORMAT outformat = LYD_UNKNOWN;
+    FILE *output = stdout;
+    static struct option long_options[] = {
+        {"defaults", required_argument, 0, 'd'},
+        {"help", no_argument, 0, 'h'},
+        {"format", required_argument, 0, 'f'},
+        {"option", required_argument, 0, 't'},
+        {"output", required_argument, 0, 'o'},
+        {"running", required_argument, 0, 'r'},
+        {"strict", no_argument, 0, 's'},
+        {NULL, 0, 0, 0}
+    };
+    void *rlcd;
+
+    argc = 1;
+    argv = malloc(2*sizeof *argv);
+    *argv = strdup(arg);
+    ptr = strtok(*argv, " ");
+    while ((ptr = strtok(NULL, " "))) {
+        rlcd = realloc(argv, (argc + 2) * sizeof *argv);
+        if (!rlcd) {
+            fprintf(stderr, "Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+            goto cleanup;
+        }
+        argv = rlcd;
+        argv[argc++] = ptr;
+    }
+    argv[argc] = NULL;
+
+    optind = 0;
+    while (1) {
+        option_index = 0;
+        c = getopt_long(argc, argv, "d:hf:o:st:r:", long_options, &option_index);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+        case 'd':
+            if (!strcmp(optarg, "all")) {
+                printopt = (printopt & ~LYP_WD_MASK) | LYP_WD_ALL;
+            } else if (!strcmp(optarg, "all-tagged")) {
+                printopt = (printopt & ~LYP_WD_MASK) | LYP_WD_ALL_TAG;
+            } else if (!strcmp(optarg, "trim")) {
+                printopt = (printopt & ~LYP_WD_MASK) | LYP_WD_TRIM;
+            } else if (!strcmp(optarg, "implicit-tagged")) {
+                printopt = (printopt & ~LYP_WD_MASK) | LYP_WD_IMPL_TAG;
+            }
+            break;
+        case 'h':
+            cmd_data_help();
+            ret = 0;
+            goto cleanup;
+        case 'f':
+            if (!strcmp(optarg, "xml")) {
+                outformat = LYD_XML;
+            } else if (!strcmp(optarg, "json")) {
+                outformat = LYD_JSON;
+            } else if (!strcmp(optarg, "lyb")) {
+                outformat = LYD_LYB;
+            } else {
+                fprintf(stderr, "Unknown output format \"%s\".\n", optarg);
+                goto cleanup;
+            }
+            break;
+        case 'o':
+            if (out_path) {
+                fprintf(stderr, "Output specified twice.\n");
+                goto cleanup;
+            }
+            out_path = optarg;
+            break;
+        case 'r':
+            if (val_tree || (options & LYD_OPT_NOEXTDEPS)) {
+                fprintf(stderr, "The running datastore (-r) cannot be set multiple times.\n");
+                goto cleanup;
+            }
+            if (optarg[0] == '!') {
+                /* ignore extenral dependencies to the running datastore */
+                options |= LYD_OPT_NOEXTDEPS;
+            } else {
+                /* external file with the running datastore */
+                val_tree = lyd_parse_path(ctx, optarg, LYD_XML, LYD_OPT_DATA_NO_YANGLIB);
+                if (!val_tree) {
+                    fprintf(stderr, "Failed to parse the additional data tree for validation.\n");
+                    goto cleanup;
+                }
+            }
+            break;
+        case 's':
+            options |= LYD_OPT_STRICT;
+            options |= LYD_OPT_OBSOLETE;
+            break;
+        case 't':
+            if (!strcmp(optarg, "auto")) {
+                options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_TYPEMASK;
+            } else if (!strcmp(optarg, "data")) {
+                options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_DATA;
+            } else if (!strcmp(optarg, "config")) {
+                options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_CONFIG;
+            } else if (!strcmp(optarg, "get")) {
+                options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_GET;
+            } else if (!strcmp(optarg, "getconfig")) {
+                options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_GETCONFIG;
+            } else if (!strcmp(optarg, "edit")) {
+                options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_EDIT;
+            } else if (!strcmp(optarg, "rpc")) {
+                options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPC;
+            } else if (!strcmp(optarg, "rpcreply")) {
+                options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPCREPLY;
+            } else if (!strcmp(optarg, "notif")) {
+                options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_NOTIF;
+            } else if (!strcmp(optarg, "yangdata")) {
+                options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_DATA_TEMPLATE;
+            } else {
+                fprintf(stderr, "Invalid parser option \"%s\".\n", optarg);
+                cmd_data_help();
+                goto cleanup;
+            }
+            break;
+        case '?':
+            fprintf(stderr, "Unknown option \"%d\".\n", (char)c);
+            goto cleanup;
+        }
+    }
+
+    /* file name */
+    if (optind == argc) {
+        fprintf(stderr, "Missing the data file name.\n");
+        goto cleanup;
+    }
+
+    if (parse_data(argv[optind], &options, val_tree, argv[optind + 1], &data)) {
+        goto cleanup;
+    }
+
+    if (out_path) {
+        output = fopen(out_path, "w");
+        if (!output) {
+            fprintf(stderr, "Could not open the output file (%s).\n", strerror(errno));
+            goto cleanup;
+        }
+    }
+
+    if (outformat != LYD_UNKNOWN) {
+        if (options & LYD_OPT_RPCREPLY) {
+            lyd_print_file(output, data->child, outformat, LYP_WITHSIBLINGS | LYP_FORMAT | printopt);
+        } else {
+            lyd_print_file(output, data, outformat, LYP_WITHSIBLINGS | LYP_FORMAT | printopt);
+        }
+    }
+
+    ret = 0;
+
+cleanup:
+    free(*argv);
+    free(argv);
+
+    if (output && (output != stdout)) {
+        fclose(output);
+    }
+
+    lyd_free_withsiblings(val_tree);
+    lyd_free_withsiblings(data);
+
+    return ret;
+}
+
+int
+cmd_xpath(const char *arg)
+{
+    int c, argc, option_index, ret = 1, long_str;
+    char **argv = NULL, *ptr, *expr = NULL;
+    unsigned int i, j;
+    int options = 0;
+    struct lyd_node *data = NULL, *node, *val_tree = NULL;
+    struct lyd_node_leaf_list *key;
+    struct ly_set *set;
+    static struct option long_options[] = {
+        {"help", no_argument, 0, 'h'},
+        {"expr", required_argument, 0, 'e'},
+        {NULL, 0, 0, 0}
+    };
+    void *rlcd;
+
+    long_str = 0;
+    argc = 1;
+    argv = malloc(2 * sizeof *argv);
+    *argv = strdup(arg);
+    ptr = strtok(*argv, " ");
+    while ((ptr = strtok(NULL, " "))) {
+        if (long_str) {
+            ptr[-1] = ' ';
+            if (ptr[strlen(ptr) - 1] == long_str) {
+                long_str = 0;
+                ptr[strlen(ptr) - 1] = '\0';
+            }
+        } else {
+            rlcd = realloc(argv, (argc + 2) * sizeof *argv);
+            if (!rlcd) {
+                fprintf(stderr, "Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+                goto cleanup;
+            }
+            argv = rlcd;
+            argv[argc] = ptr;
+            if (ptr[0] == '"') {
+                long_str = '"';
+                ++argv[argc];
+            }
+            if (ptr[0] == '\'') {
+                long_str = '\'';
+                ++argv[argc];
+            }
+            if (ptr[strlen(ptr) - 1] == long_str) {
+                long_str = 0;
+                ptr[strlen(ptr) - 1] = '\0';
+            }
+            ++argc;
+        }
+    }
+    argv[argc] = NULL;
+
+    optind = 0;
+    while (1) {
+        option_index = 0;
+        c = getopt_long(argc, argv, "he:t:x:", long_options, &option_index);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+        case 'h':
+            cmd_xpath_help();
+            ret = 0;
+            goto cleanup;
+        case 'e':
+            expr = optarg;
+            break;
+        case 't':
+            if (!strcmp(optarg, "auto")) {
+                options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_TYPEMASK;
+            } else if (!strcmp(optarg, "config")) {
+                options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_CONFIG;
+            } else if (!strcmp(optarg, "get")) {
+                options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_GET;
+            } else if (!strcmp(optarg, "getconfig")) {
+                options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_GETCONFIG;
+            } else if (!strcmp(optarg, "edit")) {
+                options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_EDIT;
+            } else if (!strcmp(optarg, "rpc")) {
+                options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPC;
+            } else if (!strcmp(optarg, "rpcreply")) {
+                options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPCREPLY;
+            } else if (!strcmp(optarg, "notif")) {
+                options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_NOTIF;
+            } else if (!strcmp(optarg, "yangdata")) {
+                options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_DATA_TEMPLATE;
+            } else {
+                fprintf(stderr, "Invalid parser option \"%s\".\n", optarg);
+                cmd_data_help();
+                goto cleanup;
+            }
+            break;
+        case 'x':
+            val_tree = lyd_parse_path(ctx, optarg, LYD_XML, LYD_OPT_CONFIG);
+            if (!val_tree) {
+                fprintf(stderr, "Failed to parse the additional data tree for validation.\n");
+                goto cleanup;
+            }
+            break;
+        case '?':
+            fprintf(stderr, "Unknown option \"%d\".\n", (char)c);
+            goto cleanup;
+        }
+    }
+
+    if (optind == argc) {
+        fprintf(stderr, "Missing the file with data.\n");
+        goto cleanup;
+    }
+
+    if (!expr) {
+        fprintf(stderr, "Missing the XPath expression.\n");
+        goto cleanup;
+    }
+
+    if (parse_data(argv[optind], &options, val_tree, argv[optind + 1], &data)) {
+        goto cleanup;
+    }
+
+    if (!(set = lyd_find_path(data, expr))) {
+        goto cleanup;
+    }
+
+    /* print result */
+    printf("Result:\n");
+    if (!set->number) {
+        printf("\tEmpty\n");
+    } else {
+        for (i = 0; i < set->number; ++i) {
+            node = set->set.d[i];
+            switch (node->schema->nodetype) {
+            case LYS_CONTAINER:
+                printf("\tContainer ");
+                break;
+            case LYS_LEAF:
+                printf("\tLeaf ");
+                break;
+            case LYS_LEAFLIST:
+                printf("\tLeaflist ");
+                break;
+            case LYS_LIST:
+                printf("\tList ");
+                break;
+            case LYS_ANYXML:
+                printf("\tAnyxml ");
+                break;
+            case LYS_ANYDATA:
+                printf("\tAnydata ");
+                break;
+            default:
+                printf("\tUnknown ");
+                break;
+            }
+            printf("\"%s\"", node->schema->name);
+            if (node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
+                printf(" (val: %s)", ((struct lyd_node_leaf_list *)node)->value_str);
+            } else if (node->schema->nodetype == LYS_LIST) {
+                key = (struct lyd_node_leaf_list *)node->child;
+                printf(" (");
+                for (j = 0; j < ((struct lys_node_list *)node->schema)->keys_size; ++j) {
+                    if (j) {
+                        printf(" ");
+                    }
+                    printf("\"%s\": %s", key->schema->name, key->value_str);
+                    key = (struct lyd_node_leaf_list *)key->next;
+                }
+                printf(")");
+            }
+            printf("\n");
+        }
+    }
+    printf("\n");
+
+    ly_set_free(set);
+    ret = 0;
+
+cleanup:
+    free(*argv);
+    free(argv);
+
+    lyd_free_withsiblings(data);
+
+    return ret;
+}
+
+int
+print_list(FILE *out, struct ly_ctx *ctx, LYD_FORMAT outformat)
+{
+    struct lyd_node *ylib;
+    uint32_t idx = 0, has_modules = 0;
+    uint8_t u;
+    const struct lys_module *mod;
+
+    if (outformat != LYD_UNKNOWN) {
+        ylib = ly_ctx_info(ctx);
+        if (!ylib) {
+            fprintf(stderr, "Getting context info (ietf-yang-library data) failed.\n");
+            return 1;
+        }
+
+        lyd_print_file(out, ylib, outformat, LYP_WITHSIBLINGS | LYP_FORMAT);
+        lyd_free_withsiblings(ylib);
+        return 0;
+    }
+
+    /* iterate schemas in context and provide just the basic info */
+    fprintf(out, "List of the loaded models:\n");
+    while ((mod = ly_ctx_get_module_iter(ctx, &idx))) {
+        has_modules++;
+
+        /* conformance print */
+        if (mod->implemented) {
+            fprintf(out, "\tI");
+        } else {
+            fprintf(out, "\ti");
+        }
+
+        /* module print */
+        fprintf(out, " %s", mod->name);
+        if (mod->rev_size) {
+            fprintf(out, "@%s", mod->rev[0].date);
+        }
+
+        /* submodules print */
+        if (mod->inc_size) {
+            fprintf(out, " (");
+            for (u = 0; u < mod->inc_size; u++) {
+                fprintf(out, "%s%s", !u ? "" : ",", mod->inc[u].submodule->name);
+                if (mod->inc[u].submodule->rev_size) {
+                    fprintf(out, "@%s", mod->inc[u].submodule->rev[0].date);
+                }
+            }
+            fprintf(out, ")");
+        }
+
+        /* finish the line */
+        fprintf(out, "\n");
+    }
+
+    if (!has_modules) {
+        fprintf(out, "\t(none)\n");
+    }
+
+    return 0;
+}
+
+int
+cmd_list(const char *arg)
+{
+    char **argv = NULL, *ptr;
+    int c, argc, option_index;
+    LYD_FORMAT outformat = LYD_UNKNOWN;
+    static struct option long_options[] = {
+        {"help", no_argument, 0, 'h'},
+        {"format", required_argument, 0, 'f'},
+        {NULL, 0, 0, 0}
+    };
+    void *rlcd;
+
+    argc = 1;
+    argv = malloc(2*sizeof *argv);
+    *argv = strdup(arg);
+    ptr = strtok(*argv, " ");
+    while ((ptr = strtok(NULL, " "))) {
+        rlcd = realloc(argv, (argc+2)*sizeof *argv);
+        if (!rlcd) {
+            fprintf(stderr, "Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+            goto error;
+        }
+        argv = rlcd;
+        argv[argc++] = ptr;
+    }
+    argv[argc] = NULL;
+
+    optind = 0;
+    while (1) {
+        option_index = 0;
+        c = getopt_long(argc, argv, "hf:", long_options, &option_index);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+        case 'h':
+            cmd_data_help();
+            free(*argv);
+            free(argv);
+            return 0;
+        case 'f':
+            if (!strcmp(optarg, "xml")) {
+                outformat = LYD_XML;
+            } else if (!strcmp(optarg, "json")) {
+                outformat = LYD_JSON;
+            } else {
+                fprintf(stderr, "Unknown output format \"%s\".\n", optarg);
+                goto error;
+            }
+            break;
+        case '?':
+            /* getopt_long() prints message */
+            goto error;
+        }
+    }
+    if (optind != argc) {
+        fprintf(stderr, "Unknown parameter \"%s\"\n", argv[optind]);
+error:
+        free(*argv);
+        free(argv);
+        return 1;
+    }
+    free(*argv);
+    free(argv);
+
+    return print_list(stdout, ctx, outformat);
+}
+#endif
+int
+cmd_feature(const char *arg)
+{
+    int c, argc, option_index, ret = 1, task = 0;
+    char **argv = NULL, *ptr, *model_name, *revision, *feat_names = NULL;
+    const struct lys_module *module;
+    static struct option long_options[] = {
+        {"help", no_argument, 0, 'h'},
+        {"enable", required_argument, 0, 'e'},
+        {"disable", required_argument, 0, 'd'},
+        {NULL, 0, 0, 0}
+    };
+    void *rlcd;
+
+    argc = 1;
+    argv = malloc(2*sizeof *argv);
+    *argv = strdup(arg);
+    ptr = strtok(*argv, " ");
+    while ((ptr = strtok(NULL, " "))) {
+        rlcd = realloc(argv, (argc + 2) * sizeof *argv);
+        if (!rlcd) {
+            fprintf(stderr, "Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+            goto cleanup;
+        }
+        argv = rlcd;
+        argv[argc++] = ptr;
+    }
+    argv[argc] = NULL;
+
+    optind = 0;
+    while (1) {
+        option_index = 0;
+        c = getopt_long(argc, argv, "he:d:", long_options, &option_index);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+        case 'h':
+            cmd_feature_help();
+            ret = 0;
+            goto cleanup;
+        case 'e':
+            if (task) {
+                fprintf(stderr, "Only one of enable or disable can be specified.\n");
+                goto cleanup;
+            }
+            task = 1;
+            feat_names = optarg;
+            break;
+        case 'd':
+            if (task) {
+                fprintf(stderr, "Only one of enable, or disable can be specified.\n");
+                goto cleanup;
+            }
+            task = 2;
+            feat_names = optarg;
+            break;
+        case '?':
+            fprintf(stderr, "Unknown option \"%d\".\n", (char)c);
+            goto cleanup;
+        }
+    }
+
+    /* module name */
+    if (optind == argc) {
+        fprintf(stderr, "Missing the module name.\n");
+        goto cleanup;
+    }
+
+    revision = NULL;
+    model_name = argv[optind];
+    if (strchr(model_name, '@')) {
+        revision = strchr(model_name, '@');
+        revision[0] = '\0';
+        ++revision;
+    }
+
+    module = ly_ctx_get_module(ctx, model_name, revision);
+#if 0
+    if (!module) {
+        /* not a module, try to find it as a submodule */
+        module = (const struct lys_module *)ly_ctx_get_submodule(ctx, NULL, NULL, model_name, revision);
+    }
+#endif
+
+    if (module == NULL) {
+        if (revision) {
+            fprintf(stderr, "No (sub)module \"%s\" in revision %s found.\n", model_name, revision);
+        } else {
+            fprintf(stderr, "No (sub)module \"%s\" found.\n", model_name);
+        }
+        goto cleanup;
+    }
+
+    if (!task) {
+        unsigned int len, max_len = 0;
+        unsigned int u;
+        struct lysc_feature *features;
+
+        printf("%s features:\n", module->name);
+
+        if (module->compiled) {
+            features = module->compiled->features;
+        } else {
+            features = module->off_features;
+        }
+
+        /* get the max len */
+        LY_ARRAY_FOR(features, u) {
+            len = strlen(features[u].name);
+            if (len > max_len) {
+                max_len = len;
+            }
+        }
+
+        LY_ARRAY_FOR(features, u) {
+            printf("\t%-*s (%s)\n", max_len, features[u].name, (features[u].flags & LYS_FENABLED) ? "on" : "off");
+        }
+        if (!u) {
+            printf("\t(none)\n");
+        }
+    } else {
+        feat_names = strtok(feat_names, ",");
+        while (feat_names) {
+            if (((task == 1) && lys_feature_enable(module, feat_names))
+                    || ((task == 2) && lys_feature_disable(module, feat_names))) {
+                fprintf(stderr, "Feature \"%s\" not found.\n", feat_names);
+                ret = 1;
+            }
+            feat_names = strtok(NULL, ",");
+        }
+    }
+
+cleanup:
+    free(*argv);
+    free(argv);
+
+    return ret;
+}
+
+int
+cmd_searchpath(const char *arg)
+{
+    const char *path;
+    const char * const *searchpaths;
+    int index;
+    struct stat st;
+
+    for (path = strchr(arg, ' '); path && (path[0] == ' '); ++path);
+    if (!path || (path[0] == '\0')) {
+        searchpaths = ly_ctx_get_searchdirs(ctx);
+        if (searchpaths) {
+            for (index = 0; searchpaths[index]; index++) {
+                fprintf(stdout, "%s\n", searchpaths[index]);
+            }
+        }
+        return 0;
+    }
+
+    if ((!strncmp(path, "-h", 2) && (path[2] == '\0' || path[2] == ' ')) ||
+        (!strncmp(path, "--help", 6) && (path[6] == '\0' || path[6] == ' '))) {
+        cmd_searchpath_help();
+        return 0;
+    } else if (!strncmp(path, "--clear", 7) && (path[7] == '\0' || path[7] == ' ')) {
+        ly_ctx_unset_searchdirs(ctx, NULL);
+        return 0;
+    }
+
+    if (stat(path, &st) == -1) {
+        fprintf(stderr, "Failed to stat the search path (%s).\n", strerror(errno));
+        return 1;
+    }
+    if (!S_ISDIR(st.st_mode)) {
+        fprintf(stderr, "\"%s\" is not a directory.\n", path);
+        return 1;
+    }
+
+    ly_ctx_set_searchdir(ctx, path);
+
+    return 0;
+}
+
+int
+cmd_clear(const char *arg)
+{
+    struct ly_ctx *ctx_new;
+    int options = 0;
+#if 0
+    int i;
+    char *ylpath;
+    const char * const *searchpaths;
+    LYD_FORMAT format;
+
+    /* get optional yang library file name */
+    for (i = 5; arg[i] && isspace(arg[i]); i++);
+    if (arg[i]) {
+        if (arg[i] == '-' && arg[i + 1] == 'e') {
+            options = LY_CTX_NOYANGLIBRARY;
+            goto create_empty;
+        } else {
+            ylpath = strdup(&arg[i]);
+            format = detect_data_format(ylpath);
+            if (format == LYD_UNKNOWN) {
+                free(ylpath);
+                fprintf(stderr, "Unable to resolve format of the yang library file, please add \".xml\" or \".json\" suffix.\n");
+                goto create_empty;
+            }
+            searchpaths = ly_ctx_get_searchdirs(ctx);
+            ctx_new = ly_ctx_new_ylpath(searchpaths ? searchpaths[0] : NULL, ylpath, format, 0);
+            free(ylpath);
+        }
+    } else {
+create_empty:
+#else
+    (void) arg; /* TODO unused */
+    {
+#endif
+        ly_ctx_new(NULL, options, &ctx_new);
+    }
+
+    if (!ctx_new) {
+        fprintf(stderr, "Failed to create context.\n");
+        return 1;
+    }
+
+    /* final switch */
+    ly_ctx_destroy(ctx, NULL);
+    ctx = ctx_new;
+
+    return 0;
+}
+
+int
+cmd_verb(const char *arg)
+{
+    const char *verb;
+    if (strlen(arg) < 5) {
+        cmd_verb_help();
+        return 1;
+    }
+
+    verb = arg + 5;
+    if (!strcmp(verb, "error") || !strcmp(verb, "0")) {
+        ly_verb(LY_LLERR);
+#ifndef NDEBUG
+        ly_verb_dbg(0);
+#endif
+    } else if (!strcmp(verb, "warning") || !strcmp(verb, "1")) {
+        ly_verb(LY_LLWRN);
+#ifndef NDEBUG
+        ly_verb_dbg(0);
+#endif
+    } else if (!strcmp(verb, "verbose")  || !strcmp(verb, "2")) {
+        ly_verb(LY_LLVRB);
+#ifndef NDEBUG
+        ly_verb_dbg(0);
+#endif
+    } else if (!strcmp(verb, "debug")  || !strcmp(verb, "3")) {
+        ly_verb(LY_LLDBG);
+#ifndef NDEBUG
+        ly_verb_dbg(LY_LDGDICT | LY_LDGYANG | LY_LDGYIN | LY_LDGXPATH | LY_LDGDIFF);
+#endif
+    } else {
+        fprintf(stderr, "Unknown verbosity \"%s\"\n", verb);
+        return 1;
+    }
+
+    return 0;
+}
+
+#ifndef NDEBUG
+
+int
+cmd_debug(const char *arg)
+{
+    const char *beg, *end;
+    int grps = 0;
+    if (strlen(arg) < 6) {
+        cmd_debug_help();
+        return 1;
+    }
+
+    end = arg + 6;
+    while (end[0]) {
+        for (beg = end; isspace(beg[0]); ++beg);
+        if (!beg[0]) {
+            break;
+        }
+
+        for (end = beg; (end[0] && !isspace(end[0])); ++end);
+
+        if (!strncmp(beg, "dict", end - beg)) {
+            grps |= LY_LDGDICT;
+        } else if (!strncmp(beg, "yang", end - beg)) {
+            grps |= LY_LDGYANG;
+        } else if (!strncmp(beg, "yin", end - beg)) {
+            grps |= LY_LDGYIN;
+        } else if (!strncmp(beg, "xpath", end - beg)) {
+            grps |= LY_LDGXPATH;
+        } else if (!strncmp(beg, "diff", end - beg)) {
+            grps |= LY_LDGDIFF;
+        } else {
+            fprintf(stderr, "Unknown debug group \"%.*s\"\n", (int)(end - beg), beg);
+            return 1;
+        }
+    }
+    ly_verb_dbg(grps);
+
+    return 0;
+}
+
+#endif
+
+int
+cmd_quit(const char *UNUSED(arg))
+{
+    done = 1;
+    return 0;
+}
+
+int
+cmd_help(const char *arg)
+{
+    int i;
+    char *args = strdup(arg);
+    char *cmd = NULL;
+
+    strtok(args, " ");
+    if ((cmd = strtok(NULL, " ")) == NULL) {
+
+generic_help:
+        fprintf(stdout, "Available commands:\n");
+
+        for (i = 0; commands[i].name; i++) {
+            if (commands[i].helpstring != NULL) {
+                fprintf(stdout, "  %-15s %s\n", commands[i].name, commands[i].helpstring);
+            }
+        }
+    } else {
+        /* print specific help for the selected command */
+
+        /* get the command of the specified name */
+        for (i = 0; commands[i].name; i++) {
+            if (strcmp(cmd, commands[i].name) == 0) {
+                break;
+            }
+        }
+
+        /* execute the command's help if any valid command specified */
+        if (commands[i].name) {
+            if (commands[i].help_func != NULL) {
+                commands[i].help_func();
+            } else {
+                printf("%s\n", commands[i].helpstring);
+            }
+        } else {
+            /* if unknown command specified, print the list of commands */
+            printf("Unknown command \'%s\'\n", cmd);
+            goto generic_help;
+        }
+    }
+
+    free(args);
+    return 0;
+}
+
+COMMAND commands[] = {
+        {"help", cmd_help, NULL, "Display commands description"},
+        {"add", cmd_add, cmd_add_help, "Add a new model from a specific file"},
+        {"load", cmd_load, cmd_load_help, "Load a new model from the searchdirs"},
+        {"print", cmd_print, cmd_print_help, "Print a model"},
+#if 0
+        {"data", cmd_data, cmd_data_help, "Load, validate and optionally print instance data"},
+        {"xpath", cmd_xpath, cmd_xpath_help, "Get data nodes satisfying an XPath expression"},
+        {"list", cmd_list, cmd_list_help, "List all the loaded models"},
+#endif
+        {"feature", cmd_feature, cmd_feature_help, "Print/enable/disable all/specific features of models"},
+        {"searchpath", cmd_searchpath, cmd_searchpath_help, "Print/set the search path(s) for models"},
+        {"clear", cmd_clear, cmd_clear_help, "Clear the context - remove all the loaded models"},
+        {"verb", cmd_verb, cmd_verb_help, "Change verbosity"},
+#ifndef NDEBUG
+        {"debug", cmd_debug, cmd_debug_help, "Display specific debug message groups"},
+#endif
+        {"quit", cmd_quit, NULL, "Quit the program"},
+        /* synonyms for previous commands */
+        {"?", cmd_help, NULL, "Display commands description"},
+        {"exit", cmd_quit, NULL, "Quit the program"},
+        {NULL, NULL, NULL, NULL}
+};
diff --git a/tools/lint/commands.h b/tools/lint/commands.h
new file mode 100644
index 0000000..18d7fdc
--- /dev/null
+++ b/tools/lint/commands.h
@@ -0,0 +1,46 @@
+/**
+ * @file main.c
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief libyang's yanglint tool commands header
+ *
+ * Copyright (c) 2015 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#ifndef COMMANDS_H_
+#define COMMANDS_H_
+
+#ifdef __GNUC__
+#  define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
+#else
+#  define UNUSED(x) UNUSED_ ## x
+#endif
+
+#include <stdlib.h>
+
+#include "libyang.h"
+
+#define PROMPT "> "
+
+struct model_hint {
+	char* hint;
+	struct model_hint* next;
+};
+
+typedef struct {
+	char *name; /* User printable name of the function. */
+	int (*func)(const char*); /* Function to call to do the command. */
+	void (*help_func)(void); /* Display command help. */
+	char *helpstring; /* Documentation for this function. */
+} COMMAND;
+
+LYS_INFORMAT get_schema_format(const char *path);
+
+extern COMMAND commands[];
+
+#endif /* COMMANDS_H_ */
diff --git a/tools/lint/completion.c b/tools/lint/completion.c
new file mode 100644
index 0000000..f2e8461
--- /dev/null
+++ b/tools/lint/completion.c
@@ -0,0 +1,140 @@
+/**
+ * @file completion.c
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief libyang's yanglint tool auto completion
+ *
+ * Copyright (c) 2015 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+
+#include "commands.h"
+#include "./linenoise/linenoise.h"
+#include "libyang.h"
+
+extern struct ly_ctx *ctx;
+
+static void
+get_cmd_completion(const char *hint, char ***matches, unsigned int *match_count)
+{
+    int i;
+    void *p;
+
+    *match_count = 0;
+    *matches = NULL;
+
+    for (i = 0; commands[i].name; i++) {
+        if (!strncmp(hint, commands[i].name, strlen(hint))) {
+            ++(*match_count);
+            p = realloc(*matches, *match_count * sizeof **matches);
+            if (!p) {
+                fprintf(stderr, "Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+                return;
+            }
+            *matches = p;
+            (*matches)[*match_count-1] = strdup(commands[i].name);
+        }
+    }
+}
+
+static int
+last_is_opt(const char *hint)
+{
+    const char *ptr;
+
+    /* last is option */
+    if (hint[0] == '-') {
+        return 1;
+    }
+
+    do {
+        --hint;
+    } while (hint[0] == ' ');
+
+    /* last is option argument */
+    ptr = strrchr(hint, ' ');
+    if (ptr) {
+        ++ptr;
+        if (ptr[0] == '-') {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static void
+get_model_completion(const char *hint, char ***matches, unsigned int *match_count)
+{
+    unsigned int u;
+    uint32_t idx = 0;
+    const struct lys_module *module;
+    void *p;
+
+    *match_count = 0;
+    *matches = NULL;
+
+    while ((module = ly_ctx_get_module_iter(ctx, &idx))) {
+        if (!strncmp(hint, module->name, strlen(hint))) {
+            ++(*match_count);
+            p = realloc(*matches, *match_count * sizeof **matches);
+            if (!p) {
+                fprintf(stderr, "Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+                return;
+            }
+            *matches = p;
+            (*matches)[*match_count-1] = strdup(module->name);
+        }
+
+        LY_ARRAY_FOR(module->parsed->includes, u) {
+            if (!strncmp(hint, module->parsed->includes[u].submodule->name, strlen(hint))) {
+                ++(*match_count);
+                p = realloc(*matches, *match_count * sizeof **matches);
+                if (!p) {
+                    fprintf(stderr, "Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+                    return;
+                }
+                *matches = p;
+                (*matches)[*match_count-1] = strdup(module->parsed->includes[u].submodule->name);
+            }
+        }
+    }
+}
+
+void
+complete_cmd(const char *buf, const char *hint, linenoiseCompletions *lc)
+{
+    char **matches = NULL;
+    unsigned int match_count = 0, i;
+
+    if (!strncmp(buf, "add ", 4)) {
+        linenoisePathCompletion(buf, hint, lc);
+    } else if ((!strncmp(buf, "searchpath ", 11) || !strncmp(buf, "data ", 5)
+            || !strncmp(buf, "config ", 7) || !strncmp(buf, "filter ", 7)
+            || !strncmp(buf, "xpath ", 6) || !strncmp(buf, "clear ", 6)) && !last_is_opt(hint)) {
+        linenoisePathCompletion(buf, hint, lc);
+    } else if ((!strncmp(buf, "print ", 6) || !strncmp(buf, "feature ", 8)) && !last_is_opt(hint)) {
+        get_model_completion(hint, &matches, &match_count);
+    } else if (!strchr(buf, ' ') && hint[0]) {
+        get_cmd_completion(hint, &matches, &match_count);
+    }
+
+    for (i = 0; i < match_count; ++i) {
+        linenoiseAddCompletion(lc, matches[i]);
+        free(matches[i]);
+    }
+    free(matches);
+}
diff --git a/tools/lint/completion.h b/tools/lint/completion.h
new file mode 100644
index 0000000..953add2
--- /dev/null
+++ b/tools/lint/completion.h
@@ -0,0 +1,22 @@
+/**
+ * @file main.c
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief libyang's yanglint tool auto completion header
+ *
+ * Copyright (c) 2015 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#ifndef COMPLETION_H_
+#define COMPLETION_H_
+
+#include "./linenoise/linenoise.h"
+
+void complete_cmd(const char *buf, const char *hint, linenoiseCompletions *lc);
+
+#endif /* COMPLETION_H_ */
diff --git a/tools/lint/configuration.c b/tools/lint/configuration.c
new file mode 100644
index 0000000..095d2d0
--- /dev/null
+++ b/tools/lint/configuration.c
@@ -0,0 +1,121 @@
+/**
+ * @file configuration.c
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief yanglint configuration
+ *
+ * Copyright (c) 2017 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <pwd.h>
+
+#include "configuration.h"
+#include "./linenoise/linenoise.h"
+
+/* Yanglint home (appended to ~/) */
+#define YL_DIR ".yanglint"
+
+char *
+get_yanglint_dir(void)
+{
+    int ret;
+    struct passwd *pw;
+    char *user_home, *yl_dir;
+
+    if (!(pw = getpwuid(getuid()))) {
+        fprintf(stderr, "Determining home directory failed (%s).\n", strerror(errno));
+        return NULL;
+    }
+    user_home = pw->pw_dir;
+
+    yl_dir = malloc(strlen(user_home) + 1 + strlen(YL_DIR) + 1);
+    if (!yl_dir) {
+        fprintf(stderr, "Memory allocation failed (%s).\n", strerror(errno));
+        return NULL;
+    }
+    sprintf(yl_dir, "%s/%s", user_home, YL_DIR);
+
+    ret = access(yl_dir, R_OK | X_OK);
+    if (ret == -1) {
+        if (errno == ENOENT) {
+            /* directory does not exist */
+            fprintf(stdout, "Configuration directory \"%s\" does not exist, creating it.\n", yl_dir);
+            if (mkdir(yl_dir, 00700)) {
+                fprintf(stderr, "Configuration directory \"%s\" cannot be created (%s).\n", yl_dir, strerror(errno));
+                free(yl_dir);
+                return NULL;
+            }
+        } else {
+            fprintf(stderr, "Configuration directory \"%s\" exists but cannot be accessed (%s).\n", yl_dir, strerror(errno));
+            free(yl_dir);
+            return NULL;
+        }
+    }
+
+    return yl_dir;
+}
+
+void
+load_config(void)
+{
+    char *yl_dir, *history_file;
+    if ((yl_dir = get_yanglint_dir()) == NULL) {
+        return;
+    }
+
+    history_file = malloc(strlen(yl_dir) + 9);
+    if (!history_file) {
+        fprintf(stderr, "Memory allocation failed (%s).\n", strerror(errno));
+        free(yl_dir);
+        return;
+    }
+
+    sprintf(history_file, "%s/history", yl_dir);
+    if (access(history_file, F_OK) && (errno == ENOENT)) {
+        fprintf(stdout, "No saved history.\n");
+    } else if (linenoiseHistoryLoad(history_file)) {
+        fprintf(stderr, "Failed to load history.\n");
+    }
+
+    free(history_file);
+    free(yl_dir);
+}
+
+void
+store_config(void)
+{
+    char *yl_dir, *history_file;
+
+    if ((yl_dir = get_yanglint_dir()) == NULL) {
+        return;
+    }
+
+    history_file = malloc(strlen(yl_dir) + 9);
+    if (!history_file) {
+        fprintf(stderr, "Memory allocation failed (%s).\n", strerror(errno));
+        free(yl_dir);
+        return;
+    }
+
+    sprintf(history_file, "%s/history", yl_dir);
+    if (linenoiseHistorySave(history_file)) {
+        fprintf(stderr, "Failed to save history.\n");
+    }
+
+    free(history_file);
+    free(yl_dir);
+}
diff --git a/tools/lint/configuration.h b/tools/lint/configuration.h
new file mode 100644
index 0000000..a299407
--- /dev/null
+++ b/tools/lint/configuration.h
@@ -0,0 +1,37 @@
+/**
+ * @file configuration.h
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief yanglint configuration header
+ *
+ * Copyright (c) 2017 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#ifndef CONFIGURATION_H_
+#define CONFIGURATION_H_
+
+
+/**
+ * @brief Finds the current user's yanglint dir
+ * @return NULL on failure, dynamically allocated yanglint dir path
+ * otherwise
+ */
+char *get_yanglint_dir(void);
+
+/**
+ * @brief Checks all the relevant files and directories creating any
+ * that are missing, sets the saved configuration (currently only history)
+ */
+void load_config(void);
+
+/**
+ * @brief Saves the current configuration (currently only history)
+ */
+void store_config(void);
+
+#endif /* CONFIGURATION_H_ */
diff --git a/tools/lint/examples/README.md b/tools/lint/examples/README.md
new file mode 100644
index 0000000..4b1d972
--- /dev/null
+++ b/tools/lint/examples/README.md
@@ -0,0 +1,572 @@
+YANGLINT IS NOT YET PREPARED FOR USE, EXAMPLES MAY NOT WORK YET!!!
+
+# YANGLINT - Interactive Mode Examples
+
+This text provides several use-case of the `yanglint(1)` interactive
+mode. For basic information about the `yanglint(1)` usage, please see
+the man page.
+
+The examples are supposed to be went through one by one. Some of the examples
+suppose the specific schemas loaded in some of the previous example is still
+loaded. If an addition work is need, the *preparation* part in the example
+provides information what to do.
+
+To show all available command of the `yanglint(1)`, use the `help` command:
+```
+> help
+Available commands:
+  help            Display commands description
+  add             Add a new model
+  print           Print model
+  data            Load, validate and optionally print instance data
+  xpath           Get data nodes satisfying an XPath expression
+  list            List all the loaded models
+  feature         Print/enable/disable all/specific features of models
+  searchpath      Set the search path for models
+  clear           Clear the context - remove all the loaded models
+  verb            Change verbosity
+  quit            Quit the program
+  ?               Display commands description
+  exit            Quit the program
+```
+To show the information about the specific command, use the `help` command in
+combination with the command name you are interested in:
+```
+> help searchpath
+searchpath <model-dir-path>
+```
+
+The input files referred in this document are available together with this
+document.
+
+## Duplicit Data Model
+
+Let's have two data models [module1.yang](./module1.yang)
+and [module1b.yang](./module1b.yang).
+They differ in the module name but their namespaces are the same.
+
+Preparation:
+
+```
+> clear
+> add module1.yang
+> list
+```
+
+Output:
+
+```
+List of the loaded models (mod-set-id 5):
+        ietf-inet-types@2013-07-15
+        ietf-yang-types@2013-07-15
+        ietf-yang-library@2015-07-03
+        module1
+```
+
+Command and its output:
+
+```
+> add module1b.yang
+libyang[0]: Two different modules ("module1" and "module1b") have the same namespace "urn:yanglint:module".
+libyang[0]: Module "module1b" parsing failed.
+```
+
+## Yang Data Model Validation
+
+**YANG/YIN syntax**
+
+`module2.yin` contains a syntax error.
+There is a bad syntax of the `type` statement in YIN file.
+
+```
+<type value="string"/>
+```
+
+instead of
+
+```
+<type name="string"/>
+```
+
+Preparation:
+
+```
+> clear
+```
+
+Command and its output:
+
+```
+> add module2.yin
+libyang[0]: Missing argument "name" to keyword "type".
+libyang[0]: Module "module1" parsing failed.
+```
+
+Similarly, there is a typo in `module2.yang`.
+
+**XPath errors**
+
+`libyang` and `yanglint(1)` is able to detect also errors in XPath expressions.
+In `module3.yang` the `must` expression refers to the node which does not exists.
+
+Preparation:
+
+```
+> clear
+```
+
+Command and its output:
+
+```
+> add module3.yang
+libyang[0]: Schema node "a" not found (../c/a).
+libyang[0]: Path is related to the previous error message. (path: /module3:m)
+libyang[0]: Module "module3" parsing failed.
+```
+
+Note that libyang does not provide line numbers of the error. Instead it tries to
+print the path to the related node. in some cases (as this one) it is not able
+to print the path immediately so the path (to the node `m` which refers node which
+does not exist) is printed in the second message.
+
+## Data Validation
+
+Preparation:
+
+```
+> clear
+> add ietf-netconf-acm.yang
+```
+
+**Unknown data**
+
+By default, yanglint ignores unknown data and no error is printed (you can
+compare real content of the `datastore.xml` file and what yanglint prints
+in the following command if you add `-f xml` option).
+
+Command and its output:
+
+```
+> data -t config datastore.xml
+```
+
+We use option `-t` to specify type of the data in `datastore.xml`. By the
+`config` value we declare that the input file contains all the configuration
+data (with at least all the mandatory nodes as required by the loaded schemas),
+but without the status data. More examples of different data types will follow.
+
+To handle unknown data as error, use strict mode (`-s` option).
+
+Command and its output:
+
+```
+> data -t config -s datastore.xml
+libyang[0]: Unknown element "interfaces". (path: /)
+Failed to parse data.
+```
+
+Note that in case of working with complete datastore including the status data
+(no `-t` option is specified), `yanglint(1)` has to add status data from its
+internal `ietf-yang-library` module. Using the `-s` option in this case forces
+validation in time of parsing the input file so it is expected to include also
+the mandatory status data from the `ietf-yang-library` module.
+
+**RPC and RPC-reply**
+
+It is possible to validate RPCs and their replies as well.
+
+Peparation:
+
+```
+> clear
+> add module4.yang
+```
+
+Command and its output:
+
+```
+> data -t rpc rpc.xml
+```
+
+Reply to this RPC can be validated too, but it must be specified, to which
+RPC it is a reply to, because it is not included in the reply itself.
+
+Command and its output:
+
+```
+> data -t rpcreply rpc-reply.xml rpc.xml
+```
+
+**action and action-reply**
+
+Actions are validated the same way as RPCs except you need to be careful
+about the input file structure.
+
+Preparation
+
+```
+> clear
+> add module4.yang
+```
+
+Command and its output:
+
+```
+> data -t rpc action.xml
+```
+
+Command and its output:
+
+```
+> data -t rpc action-reply.xml action.xml
+```
+
+**notification**
+
+Both top-level and nested notification can be validated.
+
+Preparation
+
+```
+> clear
+> add module4.yang
+```
+
+Command and its output:
+
+```
+> data -t notif notification.xml
+```
+
+Command and its output:
+
+```
+> data -t notif nested-notification.xml
+```
+
+
+**Multiple top-level elements in a single document**
+
+As a feature and in conflict with the XML definition, `yanglint(1)` (and libyang)
+is able to read XML files with multiple top-level elements. Such documents
+are not well-formed according to the XML spec, but it fits to how the YANG
+interconnects data trees (defined as top-level elements of a single schema
+or by multiple schemas).
+
+Preparation:
+
+```
+> clear
+> add ietf-netconf-acm.yang
+> add ietf-interfaces.yang
+> add ietf-ip.yang
+> add iana-if-type.yang
+```
+
+Command and its output:
+
+```
+> data -t config -s datastore.xml
+```
+
+**Different data content types**
+
+Since NETCONF requires the data described by YANG to be used in different
+situations (e.g. as <edit-config data>, result of the <get> with status data
+included or as a result of the <get-config> without the status data and
+possibly filtered, so without specified subtrees), it must be possible to
+specify which kind of data is going to be parsed. In `yanglint(1)`, this is done
+via `-t` option. The list of supported modes can be displayed by the `-h`
+option given to the `data` command. In general, the `auto` value lets the
+`yanglint(1)` to recognize the data type automatically by the additional top-level
+elements added to the parsed data. This is the same way as `pyang(1)` uses. Note,
+that the automatic data type recognition is available only for the XML input.
+
+**Malformed XML data**
+
+Command and its output:
+
+```
+> data -t edit config-missing-key.xml
+libyang[0]: Invalid (mixed names) opening (nam) and closing (name) element tags. (path: /nacm/groups/group/nam)
+Failed to parse data.
+```
+
+**State information in edit-config XML**
+
+Command and its output:
+
+```
+> data -t edit config-unknown-element.xml
+libyang[0]: Unknown element "denied-operations". (path: /ietf-netconf-acm:nacm/denied-operations)
+Failed to parse data.
+```
+
+**Missing required element in NETCONF data**
+
+Command and its output:
+
+```
+> data data-missing-key.xml
+libyang[0]: Missing required element "name" in "rule". (path: /ietf-netconf-acm:nacm/rule-list[name='almighty']/rule)
+Failed to parse data.
+```
+
+**Malformed XML**
+
+Command and its output:
+
+```
+> data data-malformed-xml.xml
+libyang[0]: Invalid (mixed names) opening (nam) and closing (rule) element tags. (path: /nacm/rule-list/rule/nam)
+Failed to parse data.
+```
+
+Command and its output:
+
+```
+> data data-malformed-xml2.xml
+libyang[0]: Invalid (mixed names) opening (module-name) and closing (name) element tags. (path: /nacm/rule-list/rule/name/module-name)
+Failed to parse data.
+```
+
+**Bad value**
+
+Command and its output:
+
+```
+> data data-out-of-range-value.xml
+libyang[0]: Invalid value "-1" in "denied-operations" element. (path: /ietf-netconf-acm:nacm/denied-operations)
+Failed to parse data.
+```
+
+## Validation of "when" Statement in Data
+
+Preparation:
+
+```
+> clear
+> add ietf-netconf-acm-when.yang
+```
+
+**`When` condition is not satisfied since `denied-operation = 0`**
+
+Command and its output:
+
+```
+> data data-acm.xml
+```
+
+The command succeeds. It is because `yanglint(1)` (via `libyang`) performs
+autodeletion - the not satisfied `when` condition in `denied-data-writes`
+causes its automatic (silent) deletion.
+
+## Printing a Data Model
+
+Preparation:
+
+```
+> clear
+> add ietf-netconf-acm.yang
+```
+
+**Print a `pyang`-style tree**
+
+Command and its output:
+
+```
+> print ietf-netconf-acm
+module: ietf-netconf-acm
+   +--rw nacm
+      +--rw enable-nacm?              boolean <true>
+      +--rw read-default?             action-type <permit>
+      +--rw write-default?            action-type <deny>
+      +--rw exec-default?             action-type <permit>
+      +--rw enable-external-groups?   boolean <true>
+      +--ro denied-operations         ietf-yang-types:zero-based-counter32
+      +--ro denied-data-writes        ietf-yang-types:zero-based-counter32
+      +--ro denied-notifications      ietf-yang-types:zero-based-counter32
+      +--rw groups
+      |  +--rw group* [name]
+      |     +--rw name         group-name-type
+      |     +--rw user-name*   user-name-type
+      +--rw rule-list* [name]
+         +--rw name     string
+         +--rw group*   union
+         +--rw rule* [name]
+            +--rw name                 string
+            +--rw module-name?         union <*>
+            +--rw (rule-type)?
+            |  +--:(protocol-operation)
+            |  |  +--rw rpc-name?             union
+            |  +--:(notification)
+            |  |  +--rw notification-name?    union
+            |  +--:(data-node)
+            |     +--rw path                  node-instance-identifier
+            +--rw access-operations?   union <*>
+            +--rw action               action-type
+            +--rw comment?             string
+>
+```
+
+**Obtain information about model**
+
+Command and its output:
+
+```
+> print -f info ietf-netconf-acm
+Module:    ietf-netconf-acm
+Namespace: urn:ietf:params:xml:ns:yang:ietf-netconf-acm
+Prefix:    nacm
+Desc:      NETCONF Access Control Model.
+
+           Copyright (c) 2012 IETF Trust and the persons identified as
+           authors of the code.  All rights reserved.
+
+           Redistribution and use in source and binary forms, with or
+           without modification, is permitted pursuant to, and subject
+           to the license terms contained in, the Simplified BSD
+           License set forth in Section 4.c of the IETF Trust's
+           Legal Provisions Relating to IETF Documents
+           (http://trustee.ietf.org/license-info).
+
+           This version of this YANG module is part of RFC 6536; see
+           the RFC itself for full legal notices.
+Reference:
+Org:       IETF NETCONF (Network Configuration) Working Group
+Contact:   WG Web:   <http://tools.ietf.org/wg/netconf/>
+           WG List:  <mailto:netconf@ietf.org>
+
+           WG Chair: Mehmet Ersue
+                     <mailto:mehmet.ersue@nsn.com>
+
+           WG Chair: Bert Wijnen
+                     <mailto:bertietf@bwijnen.net>
+
+           Editor:   Andy Bierman
+                     <mailto:andy@yumaworks.com>
+
+           Editor:   Martin Bjorklund
+                     <mailto:mbj@tail-f.com>
+YANG ver:  1.0
+Deviated:  no
+Implement: yes
+URI:
+Revisions: 2012-02-22
+Includes:
+Imports:   yang:ietf-yang-types
+Typedefs:  user-name-type
+           matchall-string-type
+           access-operations-type
+           group-name-type
+           action-type
+           node-instance-identifier
+Idents:
+Features:
+Augments:
+Deviation:
+Data:      container "nacm"
+```
+
+**Print information about specific model part**
+
+Command and its output:
+
+```
+> print -f info -t /ietf-netconf-acm:nacm/ietf-netconf-acm:enable-nacm ietf-netconf-ac
+Leaf:      enable-nacm
+Module:    ietf-netconf-acm
+Desc:      Enables or disables all NETCONF access control
+           enforcement.  If 'true', then enforcement
+           is enabled.  If 'false', then enforcement
+           is disabled.
+Reference:
+Config:    read-write
+Status:    current
+Mandatory: no
+Type:      boolean
+Units:
+Default:   true
+If-feats:
+When:
+Must:
+NACM:      default-deny-all
+```
+
+## Query using NETCONF data
+
+Preparation:
+
+```
+> clear
+> add ietf-netconf-acm.yang
+```
+
+**Print all `user-name` elements that occure in data**
+
+Command and its output:
+
+```
+> xpath -e //ietf-netconf-acm:user-name data-acm.xml
+Result:
+        Leaflist "user-name" (val: smith)
+        Leaflist "user-name" (val: smith)
+        Leaflist "user-name" (val: doe)
+
+```
+
+**Print all data that satisfies condition**
+
+Command and its output:
+
+```
+> xpath -e //ietf-netconf-acm:user-name[text()="smith"] data-acm.xml
+Result:
+        Leaflist "user-name" (val: smith)
+        Leaflist "user-name" (val: smith)
+
+```
+
+## Usage of `feature` in Yang
+
+Preparation:
+
+```
+> clear
+> add ietf-interfaces.yang
+> add ietf-ip.yang
+> add iana-if-type.yang
+```
+
+Note: This example also shows `JSON` output of the command.
+
+Command and its output:
+```
+> feature -e * ietf-ip
+> data -f json -t config data-ip.xml
+{
+  "ietf-interfaces:interfaces": {
+    "interface": [
+      {
+        "name": "eth0",
+        "description": "Wire Connection",
+        "type": "iana-if-type:ethernetCsmacd",
+        "enabled": true,
+        "ietf-ip:ipv4": {
+          "address": [
+            {
+              "ip": "192.168.1.15",
+              "netmask": "255.255.255.0"
+            },
+            {
+              "ip": "192.168.1.10",
+              "netmask": "255.255.255.0"
+            }
+          ]
+        }
+      }
+    ]
+  }
+}
+```
+
diff --git a/tools/lint/examples/action-reply.xml b/tools/lint/examples/action-reply.xml
new file mode 100644
index 0000000..5a4788e
--- /dev/null
+++ b/tools/lint/examples/action-reply.xml
@@ -0,0 +1 @@
+<leaf3 xmlns="urn:module4">some_output</leaf3>
diff --git a/tools/lint/examples/action.xml b/tools/lint/examples/action.xml
new file mode 100644
index 0000000..b0bd411
--- /dev/null
+++ b/tools/lint/examples/action.xml
@@ -0,0 +1,10 @@
+<action xmlns="urn:ietf:params:xml:ns:yang:1">
+  <cont1 xmlns="urn:module4">
+    <list>
+      <leaf1>key_val</leaf1>
+      <act>
+        <leaf2>some_input</leaf2>
+      </act>
+    </list>
+  </cont1>
+</action>
diff --git a/tools/lint/examples/config-acm.xml b/tools/lint/examples/config-acm.xml
new file mode 100644
index 0000000..8c99419
--- /dev/null
+++ b/tools/lint/examples/config-acm.xml
@@ -0,0 +1,24 @@
+<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <rule-list>
+    <name>almighty</name>
+    <group>almighty</group>
+    <group nc:operation="create">test</group>
+    <rule>
+      <name>almighty</name>
+      <module-name>*</module-name>
+      <access-operations>*</access-operations>
+      <action>permit</action>
+    </rule>
+  </rule-list>
+  <groups>
+    <group>
+      <name>test</name>
+      <user-name>smith</user-name>
+    </group>
+    <group>
+      <name>almighty</name>
+      <user-name>smith</user-name>
+      <user-name>doe</user-name>
+    </group>
+  </groups>
+</nacm>
diff --git a/tools/lint/examples/config-missing-key.xml b/tools/lint/examples/config-missing-key.xml
new file mode 100644
index 0000000..16854d5
--- /dev/null
+++ b/tools/lint/examples/config-missing-key.xml
@@ -0,0 +1,24 @@
+<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <rule-list>
+    <name>almighty</name>
+    <group>almighty</group>
+    <group nc:operation="create">test</group>
+    <rule>
+      <name>almighty</name>
+      <module-name>*</module-name>
+      <access-operations>*</access-operations>
+      <action>permit</action>
+    </rule>
+  </rule-list>
+  <groups>
+    <group>
+      <name>test</name>
+      <user-name>smith</user-name>
+    </group>
+    <group>
+      <nam>almighty</name>
+      <user-name>smith</user-name>
+      <user-name>doe</user-name>
+    </group>
+  </groups>
+</nacm>
diff --git a/tools/lint/examples/config-unknown-element.xml b/tools/lint/examples/config-unknown-element.xml
new file mode 100644
index 0000000..87c79ee
--- /dev/null
+++ b/tools/lint/examples/config-unknown-element.xml
@@ -0,0 +1,27 @@
+<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <rule-list>
+    <name>almighty</name>
+    <group>almighty</group>
+    <group nc:operation="create">test</group>
+    <rule>
+      <name>almighty</name>
+      <module-name>*</module-name>
+      <access-operations>*</access-operations>
+      <action>permit</action>
+    </rule>
+  </rule-list>
+  <groups>
+    <group>
+      <name>test</name>
+      <user-name>smith</user-name>
+    </group>
+    <group>
+      <name>almighty</name>
+      <user-name>smith</user-name>
+      <user-name>doe</user-name>
+    </group>
+  </groups>
+  <denied-operations>0</denied-operations>
+  <denied-data-writes>0</denied-data-writes>
+  <denied-notifications>0</denied-notifications>
+</nacm>
diff --git a/tools/lint/examples/data-acm.xml b/tools/lint/examples/data-acm.xml
new file mode 100644
index 0000000..87c79ee
--- /dev/null
+++ b/tools/lint/examples/data-acm.xml
@@ -0,0 +1,27 @@
+<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <rule-list>
+    <name>almighty</name>
+    <group>almighty</group>
+    <group nc:operation="create">test</group>
+    <rule>
+      <name>almighty</name>
+      <module-name>*</module-name>
+      <access-operations>*</access-operations>
+      <action>permit</action>
+    </rule>
+  </rule-list>
+  <groups>
+    <group>
+      <name>test</name>
+      <user-name>smith</user-name>
+    </group>
+    <group>
+      <name>almighty</name>
+      <user-name>smith</user-name>
+      <user-name>doe</user-name>
+    </group>
+  </groups>
+  <denied-operations>0</denied-operations>
+  <denied-data-writes>0</denied-data-writes>
+  <denied-notifications>0</denied-notifications>
+</nacm>
diff --git a/tools/lint/examples/data-ip.xml b/tools/lint/examples/data-ip.xml
new file mode 100644
index 0000000..1894f6d
--- /dev/null
+++ b/tools/lint/examples/data-ip.xml
@@ -0,0 +1,12 @@
+<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
+  <interface>
+    <name>eth0</name>
+    <description>Wire Connection</description>
+    <type xmlns:ift="urn:ietf:params:xml:ns:yang:iana-if-type">ift:ethernetCsmacd</type>
+    <enabled>true</enabled>
+    <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
+      <address><ip>192.168.1.15</ip><netmask>255.255.255.0</netmask></address>
+      <address><ip>192.168.1.10</ip><netmask>255.255.255.0</netmask></address>
+    </ipv4>
+  </interface>
+</interfaces>
diff --git a/tools/lint/examples/data-malformed-xml.xml b/tools/lint/examples/data-malformed-xml.xml
new file mode 100644
index 0000000..fd800ad
--- /dev/null
+++ b/tools/lint/examples/data-malformed-xml.xml
@@ -0,0 +1,27 @@
+<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <rule-list>
+    <name>almighty</name>
+    <group>almighty</group>
+    <group nc:operation="create">test</group>
+    <rule>
+      <nam>almighty
+      <module-name>*</module-name>
+      <access-operations>*</access-operations>
+      <action>permit</action>
+    </rule>
+  </rule-list>
+  <groups>
+    <group>
+      <name>test</name>
+      <user-name>smith</user-name>
+    </group>
+    <group>
+      <name>almighty</name>
+      <user-name>smith</user-name>
+      <user-name>doe</user-name>
+    </group>
+  </groups>
+  <denied-operations>0</denied-operations>
+  <denied-data-writes>0</denied-data-writes>
+  <denied-notifications>0</denied-notifications>
+</nacm>
diff --git a/tools/lint/examples/data-malformed-xml2.xml b/tools/lint/examples/data-malformed-xml2.xml
new file mode 100644
index 0000000..1837264
--- /dev/null
+++ b/tools/lint/examples/data-malformed-xml2.xml
@@ -0,0 +1,26 @@
+<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <rule-list>
+    <name>almighty</name>
+    <group>almighty</group>
+    <group nc:operation="create">test</group>
+    <rule>
+      <name>almighty<module-name></name> *</module-name>
+      <access-operations>*</access-operations>
+      <action>permit</action>
+    </rule>
+  </rule-list>
+  <groups>
+    <group>
+      <name>test</name>
+      <user-name>smith</user-name>
+    </group>
+    <group>
+      <name>almighty</name>
+      <user-name>smith</user-name>
+      <user-name>doe</user-name>
+    </group>
+  </groups>
+  <denied-operations>0</denied-operations>
+  <denied-data-writes>0</denied-data-writes>
+  <denied-notifications>0</denied-notifications>
+</nacm>
diff --git a/tools/lint/examples/data-missing-key.xml b/tools/lint/examples/data-missing-key.xml
new file mode 100644
index 0000000..d3ccd53
--- /dev/null
+++ b/tools/lint/examples/data-missing-key.xml
@@ -0,0 +1,26 @@
+<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <rule-list>
+    <name>almighty</name>
+    <group>almighty</group>
+    <group nc:operation="create">test</group>
+    <rule>
+      <module-name>*</module-name>
+      <access-operations>*</access-operations>
+      <action>permit</action>
+    </rule>
+  </rule-list>
+  <groups>
+    <group>
+      <name>test</name>
+      <user-name>smith</user-name>
+    </group>
+    <group>
+      <name>almighty</name>
+      <user-name>smith</user-name>
+      <user-name>doe</user-name>
+    </group>
+  </groups>
+  <denied-operations>0</denied-operations>
+  <denied-data-writes>0</denied-data-writes>
+  <denied-notifications>0</denied-notifications>
+</nacm>
diff --git a/tools/lint/examples/data-out-of-range-value.xml b/tools/lint/examples/data-out-of-range-value.xml
new file mode 100644
index 0000000..83a0d65
--- /dev/null
+++ b/tools/lint/examples/data-out-of-range-value.xml
@@ -0,0 +1,27 @@
+<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <rule-list>
+    <name>almighty</name>
+    <group>almighty</group>
+    <group nc:operation="create">test</group>
+    <rule>
+      <name>almighty</name>
+      <module-name>*</module-name>
+      <access-operations>*</access-operations>
+      <action>permit</action>
+    </rule>
+  </rule-list>
+  <groups>
+    <group>
+      <name>test</name>
+      <user-name>smith</user-name>
+    </group>
+    <group>
+      <name>almighty</name>
+      <user-name>smith</user-name>
+      <user-name>doe</user-name>
+    </group>
+  </groups>
+  <denied-operations>-1</denied-operations>
+  <denied-data-writes>0</denied-data-writes>
+  <denied-notifications>0</denied-notifications>
+</nacm>
diff --git a/tools/lint/examples/datastore.xml b/tools/lint/examples/datastore.xml
new file mode 100644
index 0000000..c6a6fc9
--- /dev/null
+++ b/tools/lint/examples/datastore.xml
@@ -0,0 +1,29 @@
+<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm">
+  <rule-list>
+    <name>almighty</name>
+    <group>almighty</group>
+    <rule>
+      <name>almighty</name>
+      <module-name>*</module-name>
+      <access-operations>*</access-operations>
+      <action>permit</action>
+    </rule>
+  </rule-list>
+  <groups>
+    <group>
+      <name>almighty</name>
+      <user-name>smith</user-name>
+    </group>
+  </groups>
+</nacm>
+<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
+  <interface>
+    <name>eth0</name>
+    <description>Wire Connection</description>
+    <type xmlns:ift="urn:ietf:params:xml:ns:yang:iana-if-type">ift:ethernetCsmacd</type>
+    <enabled>true</enabled>
+    <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
+      <address><ip>192.168.1.15</ip><prefix-length>24</prefix-length></address>
+    </ipv4>
+  </interface>
+</interfaces>
diff --git a/tools/lint/examples/iana-if-type.yang b/tools/lint/examples/iana-if-type.yang
new file mode 100644
index 0000000..5dd8219
--- /dev/null
+++ b/tools/lint/examples/iana-if-type.yang
@@ -0,0 +1,1547 @@
+module iana-if-type {
+  namespace "urn:ietf:params:xml:ns:yang:iana-if-type";
+  prefix ianaift;
+
+  import ietf-interfaces {
+    prefix if;
+  }
+
+  organization "IANA";
+  contact
+    "        Internet Assigned Numbers Authority
+
+     Postal: ICANN
+             4676 Admiralty Way, Suite 330
+             Marina del Rey, CA 90292
+
+     Tel:    +1 310 823 9358
+     <mailto:iana@iana.org>";
+  description
+    "This YANG module defines YANG identities for IANA-registered
+     interface types.
+
+     This YANG module is maintained by IANA and reflects the
+     'ifType definitions' registry.
+
+     The latest revision of this YANG module can be obtained from
+     the IANA web site.
+
+     Requests for new values should be made to IANA via
+     email (iana@iana.org).
+
+     Copyright (c) 2014 IETF Trust and the persons identified as
+     authors of the code.  All rights reserved.
+
+     Redistribution and use in source and binary forms, with or
+     without modification, is permitted pursuant to, and subject
+     to the license terms contained in, the Simplified BSD License
+     set forth in Section 4.c of the IETF Trust's Legal Provisions
+     Relating to IETF Documents
+     (http://trustee.ietf.org/license-info).
+
+     The initial version of this YANG module is part of RFC 7224;
+     see the RFC itself for full legal notices.";
+    reference
+      "IANA 'ifType definitions' registry.
+       <http://www.iana.org/assignments/smi-numbers>";
+
+  revision 2014-05-08 {
+    description
+      "Initial revision.";
+    reference
+      "RFC 7224: IANA Interface Type YANG Module";
+  }
+
+  identity iana-interface-type {
+    base if:interface-type;
+    description
+      "This identity is used as a base for all interface types
+       defined in the 'ifType definitions' registry.";
+  }
+
+
+
+
+
+
+  identity other {
+    base iana-interface-type;
+  }
+  identity regular1822 {
+    base iana-interface-type;
+  }
+  identity hdh1822 {
+    base iana-interface-type;
+  }
+  identity ddnX25 {
+    base iana-interface-type;
+  }
+  identity rfc877x25 {
+    base iana-interface-type;
+    reference
+      "RFC 1382 - SNMP MIB Extension for the X.25 Packet Layer";
+  }
+  identity ethernetCsmacd {
+    base iana-interface-type;
+    description
+      "For all Ethernet-like interfaces, regardless of speed,
+       as per RFC 3635.";
+    reference
+      "RFC 3635 - Definitions of Managed Objects for the
+                  Ethernet-like Interface Types";
+  }
+  identity iso88023Csmacd {
+    base iana-interface-type;
+    status deprecated;
+    description
+      "Deprecated via RFC 3635.
+       Use ethernetCsmacd(6) instead.";
+    reference
+      "RFC 3635 - Definitions of Managed Objects for the
+                  Ethernet-like Interface Types";
+  }
+  identity iso88024TokenBus {
+    base iana-interface-type;
+  }
+  identity iso88025TokenRing {
+    base iana-interface-type;
+  }
+  identity iso88026Man {
+    base iana-interface-type;
+  }
+  identity starLan {
+    base iana-interface-type;
+    status deprecated;
+    description
+      "Deprecated via RFC 3635.
+       Use ethernetCsmacd(6) instead.";
+    reference
+      "RFC 3635 - Definitions of Managed Objects for the
+                  Ethernet-like Interface Types";
+  }
+  identity proteon10Mbit {
+    base iana-interface-type;
+  }
+  identity proteon80Mbit {
+    base iana-interface-type;
+  }
+  identity hyperchannel {
+    base iana-interface-type;
+  }
+  identity fddi {
+    base iana-interface-type;
+    reference
+      "RFC 1512 - FDDI Management Information Base";
+  }
+  identity lapb {
+    base iana-interface-type;
+    reference
+      "RFC 1381 - SNMP MIB Extension for X.25 LAPB";
+  }
+  identity sdlc {
+    base iana-interface-type;
+  }
+  identity ds1 {
+    base iana-interface-type;
+    description
+      "DS1-MIB.";
+    reference
+      "RFC 4805 - Definitions of Managed Objects for the
+                  DS1, J1, E1, DS2, and E2 Interface Types";
+  }
+  identity e1 {
+    base iana-interface-type;
+    status obsolete;
+    description
+      "Obsolete; see DS1-MIB.";
+    reference
+      "RFC 4805 - Definitions of Managed Objects for the
+                  DS1, J1, E1, DS2, and E2 Interface Types";
+  }
+
+
+  identity basicISDN {
+    base iana-interface-type;
+    description
+      "No longer used.  See also RFC 2127.";
+  }
+  identity primaryISDN {
+    base iana-interface-type;
+    description
+      "No longer used.  See also RFC 2127.";
+  }
+  identity propPointToPointSerial {
+    base iana-interface-type;
+    description
+      "Proprietary serial.";
+  }
+  identity ppp {
+    base iana-interface-type;
+  }
+  identity softwareLoopback {
+    base iana-interface-type;
+  }
+  identity eon {
+    base iana-interface-type;
+    description
+      "CLNP over IP.";
+  }
+  identity ethernet3Mbit {
+    base iana-interface-type;
+  }
+  identity nsip {
+    base iana-interface-type;
+    description
+      "XNS over IP.";
+  }
+  identity slip {
+    base iana-interface-type;
+    description
+      "Generic SLIP.";
+  }
+  identity ultra {
+    base iana-interface-type;
+    description
+      "Ultra Technologies.";
+  }
+  identity ds3 {
+    base iana-interface-type;
+    description
+      "DS3-MIB.";
+    reference
+      "RFC 3896 - Definitions of Managed Objects for the
+                  DS3/E3 Interface Type";
+  }
+  identity sip {
+    base iana-interface-type;
+    description
+      "SMDS, coffee.";
+    reference
+      "RFC 1694 - Definitions of Managed Objects for SMDS
+                  Interfaces using SMIv2";
+  }
+  identity frameRelay {
+    base iana-interface-type;
+    description
+      "DTE only.";
+    reference
+      "RFC 2115 - Management Information Base for Frame Relay
+                  DTEs Using SMIv2";
+  }
+  identity rs232 {
+    base iana-interface-type;
+    reference
+      "RFC 1659 - Definitions of Managed Objects for RS-232-like
+                  Hardware Devices using SMIv2";
+  }
+  identity para {
+    base iana-interface-type;
+    description
+      "Parallel-port.";
+    reference
+      "RFC 1660 - Definitions of Managed Objects for
+                  Parallel-printer-like Hardware Devices using
+                  SMIv2";
+  }
+  identity arcnet {
+    base iana-interface-type;
+    description
+      "ARCnet.";
+  }
+  identity arcnetPlus {
+    base iana-interface-type;
+    description
+      "ARCnet Plus.";
+  }
+
+
+
+  identity atm {
+    base iana-interface-type;
+    description
+      "ATM cells.";
+  }
+  identity miox25 {
+    base iana-interface-type;
+    reference
+      "RFC 1461 - SNMP MIB extension for Multiprotocol
+                  Interconnect over X.25";
+  }
+  identity sonet {
+    base iana-interface-type;
+    description
+      "SONET or SDH.";
+  }
+  identity x25ple {
+    base iana-interface-type;
+    reference
+      "RFC 2127 - ISDN Management Information Base using SMIv2";
+  }
+  identity iso88022llc {
+    base iana-interface-type;
+  }
+  identity localTalk {
+    base iana-interface-type;
+  }
+  identity smdsDxi {
+    base iana-interface-type;
+  }
+  identity frameRelayService {
+    base iana-interface-type;
+    description
+      "FRNETSERV-MIB.";
+    reference
+      "RFC 2954 - Definitions of Managed Objects for Frame
+                  Relay Service";
+  }
+  identity v35 {
+    base iana-interface-type;
+  }
+  identity hssi {
+    base iana-interface-type;
+  }
+  identity hippi {
+    base iana-interface-type;
+  }
+
+  identity modem {
+    base iana-interface-type;
+    description
+      "Generic modem.";
+  }
+  identity aal5 {
+    base iana-interface-type;
+    description
+      "AAL5 over ATM.";
+  }
+  identity sonetPath {
+    base iana-interface-type;
+  }
+  identity sonetVT {
+    base iana-interface-type;
+  }
+  identity smdsIcip {
+    base iana-interface-type;
+    description
+      "SMDS InterCarrier Interface.";
+  }
+  identity propVirtual {
+    base iana-interface-type;
+    description
+      "Proprietary virtual/internal.";
+    reference
+      "RFC 2863 - The Interfaces Group MIB";
+  }
+  identity propMultiplexor {
+    base iana-interface-type;
+    description
+      "Proprietary multiplexing.";
+    reference
+      "RFC 2863 - The Interfaces Group MIB";
+  }
+  identity ieee80212 {
+    base iana-interface-type;
+    description
+      "100BaseVG.";
+  }
+  identity fibreChannel {
+    base iana-interface-type;
+    description
+      "Fibre Channel.";
+  }
+
+
+
+  identity hippiInterface {
+    base iana-interface-type;
+    description
+      "HIPPI interfaces.";
+  }
+  identity frameRelayInterconnect {
+    base iana-interface-type;
+    status obsolete;
+    description
+      "Obsolete; use either
+       frameRelay(32) or frameRelayService(44).";
+  }
+  identity aflane8023 {
+    base iana-interface-type;
+    description
+      "ATM Emulated LAN for 802.3.";
+  }
+  identity aflane8025 {
+    base iana-interface-type;
+    description
+      "ATM Emulated LAN for 802.5.";
+  }
+  identity cctEmul {
+    base iana-interface-type;
+    description
+      "ATM Emulated circuit.";
+  }
+  identity fastEther {
+    base iana-interface-type;
+    status deprecated;
+    description
+      "Obsoleted via RFC 3635.
+       ethernetCsmacd(6) should be used instead.";
+    reference
+      "RFC 3635 - Definitions of Managed Objects for the
+                  Ethernet-like Interface Types";
+  }
+  identity isdn {
+    base iana-interface-type;
+    description
+      "ISDN and X.25.";
+    reference
+      "RFC 1356 - Multiprotocol Interconnect on X.25 and ISDN
+                  in the Packet Mode";
+  }
+
+
+
+  identity v11 {
+    base iana-interface-type;
+    description
+      "CCITT V.11/X.21.";
+  }
+  identity v36 {
+    base iana-interface-type;
+    description
+      "CCITT V.36.";
+  }
+  identity g703at64k {
+    base iana-interface-type;
+    description
+      "CCITT G703 at 64Kbps.";
+  }
+  identity g703at2mb {
+    base iana-interface-type;
+    status obsolete;
+    description
+      "Obsolete; see DS1-MIB.";
+  }
+  identity qllc {
+    base iana-interface-type;
+    description
+      "SNA QLLC.";
+  }
+  identity fastEtherFX {
+    base iana-interface-type;
+    status deprecated;
+    description
+      "Obsoleted via RFC 3635.
+       ethernetCsmacd(6) should be used instead.";
+    reference
+      "RFC 3635 - Definitions of Managed Objects for the
+                  Ethernet-like Interface Types";
+  }
+  identity channel {
+    base iana-interface-type;
+    description
+      "Channel.";
+  }
+  identity ieee80211 {
+    base iana-interface-type;
+    description
+      "Radio spread spectrum.";
+  }
+  identity ibm370parChan {
+    base iana-interface-type;
+    description
+      "IBM System 360/370 OEMI Channel.";
+  }
+  identity escon {
+    base iana-interface-type;
+    description
+      "IBM Enterprise Systems Connection.";
+  }
+  identity dlsw {
+    base iana-interface-type;
+    description
+      "Data Link Switching.";
+  }
+  identity isdns {
+    base iana-interface-type;
+    description
+      "ISDN S/T interface.";
+  }
+  identity isdnu {
+    base iana-interface-type;
+    description
+      "ISDN U interface.";
+  }
+  identity lapd {
+    base iana-interface-type;
+    description
+      "Link Access Protocol D.";
+  }
+  identity ipSwitch {
+    base iana-interface-type;
+    description
+      "IP Switching Objects.";
+  }
+  identity rsrb {
+    base iana-interface-type;
+    description
+      "Remote Source Route Bridging.";
+  }
+  identity atmLogical {
+    base iana-interface-type;
+    description
+      "ATM Logical Port.";
+    reference
+      "RFC 3606 - Definitions of Supplemental Managed Objects
+                  for ATM Interface";
+  }
+  identity ds0 {
+    base iana-interface-type;
+    description
+      "Digital Signal Level 0.";
+    reference
+      "RFC 2494 - Definitions of Managed Objects for the DS0
+                  and DS0 Bundle Interface Type";
+  }
+  identity ds0Bundle {
+    base iana-interface-type;
+    description
+      "Group of ds0s on the same ds1.";
+    reference
+      "RFC 2494 - Definitions of Managed Objects for the DS0
+                  and DS0 Bundle Interface Type";
+  }
+  identity bsc {
+    base iana-interface-type;
+    description
+      "Bisynchronous Protocol.";
+  }
+  identity async {
+    base iana-interface-type;
+    description
+      "Asynchronous Protocol.";
+  }
+  identity cnr {
+    base iana-interface-type;
+    description
+      "Combat Net Radio.";
+  }
+  identity iso88025Dtr {
+    base iana-interface-type;
+    description
+      "ISO 802.5r DTR.";
+  }
+  identity eplrs {
+    base iana-interface-type;
+    description
+      "Ext Pos Loc Report Sys.";
+  }
+  identity arap {
+    base iana-interface-type;
+    description
+      "Appletalk Remote Access Protocol.";
+  }
+  identity propCnls {
+    base iana-interface-type;
+    description
+      "Proprietary Connectionless Protocol.";
+  }
+  identity hostPad {
+    base iana-interface-type;
+    description
+      "CCITT-ITU X.29 PAD Protocol.";
+  }
+  identity termPad {
+    base iana-interface-type;
+    description
+      "CCITT-ITU X.3 PAD Facility.";
+  }
+  identity frameRelayMPI {
+    base iana-interface-type;
+    description
+      "Multiproto Interconnect over FR.";
+  }
+  identity x213 {
+    base iana-interface-type;
+    description
+      "CCITT-ITU X213.";
+  }
+  identity adsl {
+    base iana-interface-type;
+    description
+      "Asymmetric Digital Subscriber Loop.";
+  }
+  identity radsl {
+    base iana-interface-type;
+    description
+      "Rate-Adapt. Digital Subscriber Loop.";
+  }
+  identity sdsl {
+    base iana-interface-type;
+    description
+      "Symmetric Digital Subscriber Loop.";
+  }
+  identity vdsl {
+    base iana-interface-type;
+    description
+      "Very H-Speed Digital Subscrib. Loop.";
+  }
+  identity iso88025CRFPInt {
+    base iana-interface-type;
+    description
+      "ISO 802.5 CRFP.";
+  }
+  identity myrinet {
+    base iana-interface-type;
+    description
+      "Myricom Myrinet.";
+  }
+  identity voiceEM {
+    base iana-interface-type;
+    description
+      "Voice recEive and transMit.";
+  }
+  identity voiceFXO {
+    base iana-interface-type;
+    description
+      "Voice Foreign Exchange Office.";
+  }
+  identity voiceFXS {
+    base iana-interface-type;
+    description
+      "Voice Foreign Exchange Station.";
+  }
+  identity voiceEncap {
+    base iana-interface-type;
+    description
+      "Voice encapsulation.";
+  }
+  identity voiceOverIp {
+    base iana-interface-type;
+    description
+      "Voice over IP encapsulation.";
+  }
+  identity atmDxi {
+    base iana-interface-type;
+    description
+      "ATM DXI.";
+  }
+  identity atmFuni {
+    base iana-interface-type;
+    description
+      "ATM FUNI.";
+  }
+  identity atmIma {
+    base iana-interface-type;
+    description
+      "ATM IMA.";
+  }
+  identity pppMultilinkBundle {
+    base iana-interface-type;
+    description
+      "PPP Multilink Bundle.";
+  }
+  identity ipOverCdlc {
+    base iana-interface-type;
+    description
+      "IBM ipOverCdlc.";
+  }
+  identity ipOverClaw {
+    base iana-interface-type;
+    description
+      "IBM Common Link Access to Workstn.";
+  }
+  identity stackToStack {
+    base iana-interface-type;
+    description
+      "IBM stackToStack.";
+  }
+  identity virtualIpAddress {
+    base iana-interface-type;
+    description
+      "IBM VIPA.";
+  }
+  identity mpc {
+    base iana-interface-type;
+    description
+      "IBM multi-protocol channel support.";
+  }
+  identity ipOverAtm {
+    base iana-interface-type;
+    description
+      "IBM ipOverAtm.";
+    reference
+      "RFC 2320 - Definitions of Managed Objects for Classical IP
+                  and ARP Over ATM Using SMIv2 (IPOA-MIB)";
+  }
+  identity iso88025Fiber {
+    base iana-interface-type;
+    description
+      "ISO 802.5j Fiber Token Ring.";
+  }
+  identity tdlc {
+    base iana-interface-type;
+    description
+      "IBM twinaxial data link control.";
+  }
+  identity gigabitEthernet {
+    base iana-interface-type;
+    status deprecated;
+
+
+    description
+      "Obsoleted via RFC 3635.
+       ethernetCsmacd(6) should be used instead.";
+    reference
+      "RFC 3635 - Definitions of Managed Objects for the
+                  Ethernet-like Interface Types";
+  }
+  identity hdlc {
+    base iana-interface-type;
+    description
+      "HDLC.";
+  }
+  identity lapf {
+    base iana-interface-type;
+    description
+      "LAP F.";
+  }
+  identity v37 {
+    base iana-interface-type;
+    description
+      "V.37.";
+  }
+  identity x25mlp {
+    base iana-interface-type;
+    description
+      "Multi-Link Protocol.";
+  }
+  identity x25huntGroup {
+    base iana-interface-type;
+    description
+      "X25 Hunt Group.";
+  }
+  identity transpHdlc {
+    base iana-interface-type;
+    description
+      "Transp HDLC.";
+  }
+  identity interleave {
+    base iana-interface-type;
+    description
+      "Interleave channel.";
+  }
+  identity fast {
+    base iana-interface-type;
+    description
+      "Fast channel.";
+  }
+
+  identity ip {
+    base iana-interface-type;
+    description
+      "IP (for APPN HPR in IP networks).";
+  }
+  identity docsCableMaclayer {
+    base iana-interface-type;
+    description
+      "CATV Mac Layer.";
+  }
+  identity docsCableDownstream {
+    base iana-interface-type;
+    description
+      "CATV Downstream interface.";
+  }
+  identity docsCableUpstream {
+    base iana-interface-type;
+    description
+      "CATV Upstream interface.";
+  }
+  identity a12MppSwitch {
+    base iana-interface-type;
+    description
+      "Avalon Parallel Processor.";
+  }
+  identity tunnel {
+    base iana-interface-type;
+    description
+      "Encapsulation interface.";
+  }
+  identity coffee {
+    base iana-interface-type;
+    description
+      "Coffee pot.";
+    reference
+      "RFC 2325 - Coffee MIB";
+  }
+  identity ces {
+    base iana-interface-type;
+    description
+      "Circuit Emulation Service.";
+  }
+  identity atmSubInterface {
+    base iana-interface-type;
+    description
+      "ATM Sub Interface.";
+  }
+
+  identity l2vlan {
+    base iana-interface-type;
+    description
+      "Layer 2 Virtual LAN using 802.1Q.";
+  }
+  identity l3ipvlan {
+    base iana-interface-type;
+    description
+      "Layer 3 Virtual LAN using IP.";
+  }
+  identity l3ipxvlan {
+    base iana-interface-type;
+    description
+      "Layer 3 Virtual LAN using IPX.";
+  }
+  identity digitalPowerline {
+    base iana-interface-type;
+    description
+      "IP over Power Lines.";
+  }
+  identity mediaMailOverIp {
+    base iana-interface-type;
+    description
+      "Multimedia Mail over IP.";
+  }
+  identity dtm {
+    base iana-interface-type;
+    description
+      "Dynamic synchronous Transfer Mode.";
+  }
+  identity dcn {
+    base iana-interface-type;
+    description
+      "Data Communications Network.";
+  }
+  identity ipForward {
+    base iana-interface-type;
+    description
+      "IP Forwarding Interface.";
+  }
+  identity msdsl {
+    base iana-interface-type;
+    description
+      "Multi-rate Symmetric DSL.";
+  }
+  identity ieee1394 {
+    base iana-interface-type;
+
+    description
+      "IEEE1394 High Performance Serial Bus.";
+  }
+  identity if-gsn {
+    base iana-interface-type;
+    description
+      "HIPPI-6400.";
+  }
+  identity dvbRccMacLayer {
+    base iana-interface-type;
+    description
+      "DVB-RCC MAC Layer.";
+  }
+  identity dvbRccDownstream {
+    base iana-interface-type;
+    description
+      "DVB-RCC Downstream Channel.";
+  }
+  identity dvbRccUpstream {
+    base iana-interface-type;
+    description
+      "DVB-RCC Upstream Channel.";
+  }
+  identity atmVirtual {
+    base iana-interface-type;
+    description
+      "ATM Virtual Interface.";
+  }
+  identity mplsTunnel {
+    base iana-interface-type;
+    description
+      "MPLS Tunnel Virtual Interface.";
+  }
+  identity srp {
+    base iana-interface-type;
+    description
+      "Spatial Reuse Protocol.";
+  }
+  identity voiceOverAtm {
+    base iana-interface-type;
+    description
+      "Voice over ATM.";
+  }
+  identity voiceOverFrameRelay {
+    base iana-interface-type;
+    description
+      "Voice Over Frame Relay.";
+  }
+  identity idsl {
+    base iana-interface-type;
+    description
+      "Digital Subscriber Loop over ISDN.";
+  }
+  identity compositeLink {
+    base iana-interface-type;
+    description
+      "Avici Composite Link Interface.";
+  }
+  identity ss7SigLink {
+    base iana-interface-type;
+    description
+      "SS7 Signaling Link.";
+  }
+  identity propWirelessP2P {
+    base iana-interface-type;
+    description
+      "Prop. P2P wireless interface.";
+  }
+  identity frForward {
+    base iana-interface-type;
+    description
+      "Frame Forward Interface.";
+  }
+  identity rfc1483 {
+    base iana-interface-type;
+    description
+      "Multiprotocol over ATM AAL5.";
+    reference
+      "RFC 1483 - Multiprotocol Encapsulation over ATM
+                  Adaptation Layer 5";
+  }
+  identity usb {
+    base iana-interface-type;
+    description
+      "USB Interface.";
+  }
+  identity ieee8023adLag {
+    base iana-interface-type;
+    description
+      "IEEE 802.3ad Link Aggregate.";
+  }
+  identity bgppolicyaccounting {
+    base iana-interface-type;
+    description
+      "BGP Policy Accounting.";
+  }
+  identity frf16MfrBundle {
+    base iana-interface-type;
+    description
+      "FRF.16 Multilink Frame Relay.";
+  }
+  identity h323Gatekeeper {
+    base iana-interface-type;
+    description
+      "H323 Gatekeeper.";
+  }
+  identity h323Proxy {
+    base iana-interface-type;
+    description
+      "H323 Voice and Video Proxy.";
+  }
+  identity mpls {
+    base iana-interface-type;
+    description
+      "MPLS.";
+  }
+  identity mfSigLink {
+    base iana-interface-type;
+    description
+      "Multi-frequency signaling link.";
+  }
+  identity hdsl2 {
+    base iana-interface-type;
+    description
+      "High Bit-Rate DSL - 2nd generation.";
+  }
+  identity shdsl {
+    base iana-interface-type;
+    description
+      "Multirate HDSL2.";
+  }
+  identity ds1FDL {
+    base iana-interface-type;
+    description
+      "Facility Data Link (4Kbps) on a DS1.";
+  }
+  identity pos {
+    base iana-interface-type;
+    description
+      "Packet over SONET/SDH Interface.";
+  }
+
+
+
+  identity dvbAsiIn {
+    base iana-interface-type;
+    description
+      "DVB-ASI Input.";
+  }
+  identity dvbAsiOut {
+    base iana-interface-type;
+    description
+      "DVB-ASI Output.";
+  }
+  identity plc {
+    base iana-interface-type;
+    description
+      "Power Line Communications.";
+  }
+  identity nfas {
+    base iana-interface-type;
+    description
+      "Non-Facility Associated Signaling.";
+  }
+  identity tr008 {
+    base iana-interface-type;
+    description
+      "TR008.";
+  }
+  identity gr303RDT {
+    base iana-interface-type;
+    description
+      "Remote Digital Terminal.";
+  }
+  identity gr303IDT {
+    base iana-interface-type;
+    description
+      "Integrated Digital Terminal.";
+  }
+  identity isup {
+    base iana-interface-type;
+    description
+      "ISUP.";
+  }
+  identity propDocsWirelessMaclayer {
+    base iana-interface-type;
+    description
+      "Cisco proprietary Maclayer.";
+  }
+
+
+
+  identity propDocsWirelessDownstream {
+    base iana-interface-type;
+    description
+      "Cisco proprietary Downstream.";
+  }
+  identity propDocsWirelessUpstream {
+    base iana-interface-type;
+    description
+      "Cisco proprietary Upstream.";
+  }
+  identity hiperlan2 {
+    base iana-interface-type;
+    description
+      "HIPERLAN Type 2 Radio Interface.";
+  }
+  identity propBWAp2Mp {
+    base iana-interface-type;
+    description
+      "PropBroadbandWirelessAccesspt2Multipt (use of this value
+       for IEEE 802.16 WMAN interfaces as per IEEE Std 802.16f
+       is deprecated, and ieee80216WMAN(237) should be used
+       instead).";
+  }
+  identity sonetOverheadChannel {
+    base iana-interface-type;
+    description
+      "SONET Overhead Channel.";
+  }
+  identity digitalWrapperOverheadChannel {
+    base iana-interface-type;
+    description
+      "Digital Wrapper.";
+  }
+  identity aal2 {
+    base iana-interface-type;
+    description
+      "ATM adaptation layer 2.";
+  }
+  identity radioMAC {
+    base iana-interface-type;
+    description
+      "MAC layer over radio links.";
+  }
+  identity atmRadio {
+    base iana-interface-type;
+    description
+      "ATM over radio links.";
+  }
+  identity imt {
+    base iana-interface-type;
+    description
+      "Inter-Machine Trunks.";
+  }
+  identity mvl {
+    base iana-interface-type;
+    description
+      "Multiple Virtual Lines DSL.";
+  }
+  identity reachDSL {
+    base iana-interface-type;
+    description
+      "Long Reach DSL.";
+  }
+  identity frDlciEndPt {
+    base iana-interface-type;
+    description
+      "Frame Relay DLCI End Point.";
+  }
+  identity atmVciEndPt {
+    base iana-interface-type;
+    description
+      "ATM VCI End Point.";
+  }
+  identity opticalChannel {
+    base iana-interface-type;
+    description
+      "Optical Channel.";
+  }
+  identity opticalTransport {
+    base iana-interface-type;
+    description
+      "Optical Transport.";
+  }
+  identity propAtm {
+    base iana-interface-type;
+    description
+      "Proprietary ATM.";
+  }
+  identity voiceOverCable {
+    base iana-interface-type;
+    description
+      "Voice Over Cable Interface.";
+  }
+
+
+
+  identity infiniband {
+    base iana-interface-type;
+    description
+      "Infiniband.";
+  }
+  identity teLink {
+    base iana-interface-type;
+    description
+      "TE Link.";
+  }
+  identity q2931 {
+    base iana-interface-type;
+    description
+      "Q.2931.";
+  }
+  identity virtualTg {
+    base iana-interface-type;
+    description
+      "Virtual Trunk Group.";
+  }
+  identity sipTg {
+    base iana-interface-type;
+    description
+      "SIP Trunk Group.";
+  }
+  identity sipSig {
+    base iana-interface-type;
+    description
+      "SIP Signaling.";
+  }
+  identity docsCableUpstreamChannel {
+    base iana-interface-type;
+    description
+      "CATV Upstream Channel.";
+  }
+  identity econet {
+    base iana-interface-type;
+    description
+      "Acorn Econet.";
+  }
+  identity pon155 {
+    base iana-interface-type;
+    description
+      "FSAN 155Mb Symetrical PON interface.";
+  }
+
+
+
+  identity pon622 {
+    base iana-interface-type;
+    description
+      "FSAN 622Mb Symetrical PON interface.";
+  }
+  identity bridge {
+    base iana-interface-type;
+    description
+      "Transparent bridge interface.";
+  }
+  identity linegroup {
+    base iana-interface-type;
+    description
+      "Interface common to multiple lines.";
+  }
+  identity voiceEMFGD {
+    base iana-interface-type;
+    description
+      "Voice E&M Feature Group D.";
+  }
+  identity voiceFGDEANA {
+    base iana-interface-type;
+    description
+      "Voice FGD Exchange Access North American.";
+  }
+  identity voiceDID {
+    base iana-interface-type;
+    description
+      "Voice Direct Inward Dialing.";
+  }
+  identity mpegTransport {
+    base iana-interface-type;
+    description
+      "MPEG transport interface.";
+  }
+  identity sixToFour {
+    base iana-interface-type;
+    status deprecated;
+    description
+      "6to4 interface (DEPRECATED).";
+    reference
+      "RFC 4087 - IP Tunnel MIB";
+  }
+  identity gtp {
+    base iana-interface-type;
+    description
+      "GTP (GPRS Tunneling Protocol).";
+  }
+  identity pdnEtherLoop1 {
+    base iana-interface-type;
+    description
+      "Paradyne EtherLoop 1.";
+  }
+  identity pdnEtherLoop2 {
+    base iana-interface-type;
+    description
+      "Paradyne EtherLoop 2.";
+  }
+  identity opticalChannelGroup {
+    base iana-interface-type;
+    description
+      "Optical Channel Group.";
+  }
+  identity homepna {
+    base iana-interface-type;
+    description
+      "HomePNA ITU-T G.989.";
+  }
+  identity gfp {
+    base iana-interface-type;
+    description
+      "Generic Framing Procedure (GFP).";
+  }
+  identity ciscoISLvlan {
+    base iana-interface-type;
+    description
+      "Layer 2 Virtual LAN using Cisco ISL.";
+  }
+  identity actelisMetaLOOP {
+    base iana-interface-type;
+    description
+      "Acteleis proprietary MetaLOOP High Speed Link.";
+  }
+  identity fcipLink {
+    base iana-interface-type;
+    description
+      "FCIP Link.";
+  }
+  identity rpr {
+    base iana-interface-type;
+    description
+      "Resilient Packet Ring Interface Type.";
+  }
+
+
+
+  identity qam {
+    base iana-interface-type;
+    description
+      "RF Qam Interface.";
+  }
+  identity lmp {
+    base iana-interface-type;
+    description
+      "Link Management Protocol.";
+    reference
+      "RFC 4327 - Link Management Protocol (LMP) Management
+                  Information Base (MIB)";
+  }
+  identity cblVectaStar {
+    base iana-interface-type;
+    description
+      "Cambridge Broadband Networks Limited VectaStar.";
+  }
+  identity docsCableMCmtsDownstream {
+    base iana-interface-type;
+    description
+      "CATV Modular CMTS Downstream Interface.";
+  }
+  identity adsl2 {
+    base iana-interface-type;
+    status deprecated;
+    description
+      "Asymmetric Digital Subscriber Loop Version 2
+       (DEPRECATED/OBSOLETED - please use adsl2plus(238)
+       instead).";
+    reference
+      "RFC 4706 - Definitions of Managed Objects for Asymmetric
+                  Digital Subscriber Line 2 (ADSL2)";
+  }
+  identity macSecControlledIF {
+    base iana-interface-type;
+    description
+      "MACSecControlled.";
+  }
+  identity macSecUncontrolledIF {
+    base iana-interface-type;
+    description
+      "MACSecUncontrolled.";
+  }
+  identity aviciOpticalEther {
+    base iana-interface-type;
+    description
+      "Avici Optical Ethernet Aggregate.";
+  }
+  identity atmbond {
+    base iana-interface-type;
+    description
+      "atmbond.";
+  }
+  identity voiceFGDOS {
+    base iana-interface-type;
+    description
+      "Voice FGD Operator Services.";
+  }
+  identity mocaVersion1 {
+    base iana-interface-type;
+    description
+      "MultiMedia over Coax Alliance (MoCA) Interface
+       as documented in information provided privately to IANA.";
+  }
+  identity ieee80216WMAN {
+    base iana-interface-type;
+    description
+      "IEEE 802.16 WMAN interface.";
+  }
+  identity adsl2plus {
+    base iana-interface-type;
+    description
+      "Asymmetric Digital Subscriber Loop Version 2 -
+       Version 2 Plus and all variants.";
+  }
+  identity dvbRcsMacLayer {
+    base iana-interface-type;
+    description
+      "DVB-RCS MAC Layer.";
+    reference
+      "RFC 5728 - The SatLabs Group DVB-RCS MIB";
+  }
+  identity dvbTdm {
+    base iana-interface-type;
+    description
+      "DVB Satellite TDM.";
+    reference
+      "RFC 5728 - The SatLabs Group DVB-RCS MIB";
+  }
+  identity dvbRcsTdma {
+    base iana-interface-type;
+    description
+      "DVB-RCS TDMA.";
+    reference
+      "RFC 5728 - The SatLabs Group DVB-RCS MIB";
+  }
+  identity x86Laps {
+    base iana-interface-type;
+    description
+      "LAPS based on ITU-T X.86/Y.1323.";
+  }
+  identity wwanPP {
+    base iana-interface-type;
+    description
+      "3GPP WWAN.";
+  }
+  identity wwanPP2 {
+    base iana-interface-type;
+    description
+      "3GPP2 WWAN.";
+  }
+  identity voiceEBS {
+    base iana-interface-type;
+    description
+      "Voice P-phone EBS physical interface.";
+  }
+  identity ifPwType {
+    base iana-interface-type;
+    description
+      "Pseudowire interface type.";
+    reference
+      "RFC 5601 - Pseudowire (PW) Management Information Base (MIB)";
+  }
+  identity ilan {
+    base iana-interface-type;
+    description
+      "Internal LAN on a bridge per IEEE 802.1ap.";
+  }
+  identity pip {
+    base iana-interface-type;
+    description
+      "Provider Instance Port on a bridge per IEEE 802.1ah PBB.";
+  }
+  identity aluELP {
+    base iana-interface-type;
+    description
+      "Alcatel-Lucent Ethernet Link Protection.";
+  }
+  identity gpon {
+    base iana-interface-type;
+    description
+      "Gigabit-capable passive optical networks (G-PON) as per
+       ITU-T G.948.";
+  }
+  identity vdsl2 {
+    base iana-interface-type;
+    description
+      "Very high speed digital subscriber line Version 2
+       (as per ITU-T Recommendation G.993.2).";
+    reference
+      "RFC 5650 - Definitions of Managed Objects for Very High
+                  Speed Digital Subscriber Line 2 (VDSL2)";
+  }
+  identity capwapDot11Profile {
+    base iana-interface-type;
+    description
+      "WLAN Profile Interface.";
+    reference
+      "RFC 5834 - Control and Provisioning of Wireless Access
+                  Points (CAPWAP) Protocol Binding MIB for
+                  IEEE 802.11";
+  }
+  identity capwapDot11Bss {
+    base iana-interface-type;
+    description
+      "WLAN BSS Interface.";
+    reference
+      "RFC 5834 - Control and Provisioning of Wireless Access
+                  Points (CAPWAP) Protocol Binding MIB for
+                  IEEE 802.11";
+  }
+  identity capwapWtpVirtualRadio {
+    base iana-interface-type;
+    description
+      "WTP Virtual Radio Interface.";
+    reference
+      "RFC 5833 - Control and Provisioning of Wireless Access
+                  Points (CAPWAP) Protocol Base MIB";
+  }
+  identity bits {
+    base iana-interface-type;
+    description
+      "bitsport.";
+  }
+  identity docsCableUpstreamRfPort {
+    base iana-interface-type;
+    description
+      "DOCSIS CATV Upstream RF Port.";
+  }
+
+
+  identity cableDownstreamRfPort {
+    base iana-interface-type;
+    description
+      "CATV downstream RF Port.";
+  }
+  identity vmwareVirtualNic {
+    base iana-interface-type;
+    description
+      "VMware Virtual Network Interface.";
+  }
+  identity ieee802154 {
+    base iana-interface-type;
+    description
+      "IEEE 802.15.4 WPAN interface.";
+    reference
+      "IEEE 802.15.4-2006";
+  }
+  identity otnOdu {
+    base iana-interface-type;
+    description
+      "OTN Optical Data Unit.";
+  }
+  identity otnOtu {
+    base iana-interface-type;
+    description
+      "OTN Optical channel Transport Unit.";
+  }
+  identity ifVfiType {
+    base iana-interface-type;
+    description
+      "VPLS Forwarding Instance Interface Type.";
+  }
+  identity g9981 {
+    base iana-interface-type;
+    description
+      "G.998.1 bonded interface.";
+  }
+  identity g9982 {
+    base iana-interface-type;
+    description
+      "G.998.2 bonded interface.";
+  }
+  identity g9983 {
+    base iana-interface-type;
+    description
+      "G.998.3 bonded interface.";
+  }
+
+  identity aluEpon {
+    base iana-interface-type;
+    description
+      "Ethernet Passive Optical Networks (E-PON).";
+  }
+  identity aluEponOnu {
+    base iana-interface-type;
+    description
+      "EPON Optical Network Unit.";
+  }
+  identity aluEponPhysicalUni {
+    base iana-interface-type;
+    description
+      "EPON physical User to Network interface.";
+  }
+  identity aluEponLogicalLink {
+    base iana-interface-type;
+    description
+      "The emulation of a point-to-point link over the EPON
+       layer.";
+  }
+  identity aluGponOnu {
+    base iana-interface-type;
+    description
+      "GPON Optical Network Unit.";
+    reference
+      "ITU-T G.984.2";
+  }
+  identity aluGponPhysicalUni {
+    base iana-interface-type;
+    description
+      "GPON physical User to Network interface.";
+    reference
+      "ITU-T G.984.2";
+  }
+  identity vmwareNicTeam {
+    base iana-interface-type;
+    description
+      "VMware NIC Team.";
+  }
+}
diff --git a/tools/lint/examples/ietf-interfaces.yang b/tools/lint/examples/ietf-interfaces.yang
new file mode 100644
index 0000000..ad64425
--- /dev/null
+++ b/tools/lint/examples/ietf-interfaces.yang
@@ -0,0 +1,725 @@
+module ietf-interfaces {
+
+  namespace "urn:ietf:params:xml:ns:yang:ietf-interfaces";
+  prefix if;
+
+  import ietf-yang-types {
+    prefix yang;
+  }
+
+  organization
+    "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+  contact
+    "WG Web:   <http://tools.ietf.org/wg/netmod/>
+     WG List:  <mailto:netmod@ietf.org>
+
+     WG Chair: Thomas Nadeau
+               <mailto:tnadeau@lucidvision.com>
+
+     WG Chair: Juergen Schoenwaelder
+               <mailto:j.schoenwaelder@jacobs-university.de>
+
+     Editor:   Martin Bjorklund
+               <mailto:mbj@tail-f.com>";
+
+  description
+    "This module contains a collection of YANG definitions for
+     managing network interfaces.
+
+     Copyright (c) 2014 IETF Trust and the persons identified as
+     authors of the code.  All rights reserved.
+
+     Redistribution and use in source and binary forms, with or
+     without modification, is permitted pursuant to, and subject
+     to the license terms contained in, the Simplified BSD License
+     set forth in Section 4.c of the IETF Trust's Legal Provisions
+     Relating to IETF Documents
+     (http://trustee.ietf.org/license-info).
+
+     This version of this YANG module is part of RFC 7223; see
+     the RFC itself for full legal notices.";
+
+  revision 2014-05-08 {
+    description
+      "Initial revision.";
+    reference
+      "RFC 7223: A YANG Data Model for Interface Management";
+  }
+
+  /*
+   * Typedefs
+   */
+
+  typedef interface-ref {
+    type leafref {
+      path "/if:interfaces/if:interface/if:name";
+    }
+    description
+      "This type is used by data models that need to reference
+       configured interfaces.";
+  }
+
+  typedef interface-state-ref {
+    type leafref {
+      path "/if:interfaces-state/if:interface/if:name";
+    }
+    description
+      "This type is used by data models that need to reference
+       the operationally present interfaces.";
+  }
+
+  /*
+   * Identities
+   */
+
+  identity interface-type {
+    description
+      "Base identity from which specific interface types are
+       derived.";
+  }
+
+  /*
+   * Features
+   */
+
+  feature arbitrary-names {
+    description
+      "This feature indicates that the device allows user-controlled
+       interfaces to be named arbitrarily.";
+  }
+  feature pre-provisioning {
+    description
+      "This feature indicates that the device supports
+       pre-provisioning of interface configuration, i.e., it is
+       possible to configure an interface whose physical interface
+       hardware is not present on the device.";
+  }
+
+  feature if-mib {
+    description
+      "This feature indicates that the device implements
+       the IF-MIB.";
+    reference
+      "RFC 2863: The Interfaces Group MIB";
+  }
+
+  /*
+   * Configuration data nodes
+   */
+
+  container interfaces {
+    description
+      "Interface configuration parameters.";
+
+    list interface {
+      key "name";
+
+      description
+        "The list of configured interfaces on the device.
+
+         The operational state of an interface is available in the
+         /interfaces-state/interface list.  If the configuration of a
+         system-controlled interface cannot be used by the system
+         (e.g., the interface hardware present does not match the
+         interface type), then the configuration is not applied to
+         the system-controlled interface shown in the
+         /interfaces-state/interface list.  If the configuration
+         of a user-controlled interface cannot be used by the system,
+         the configured interface is not instantiated in the
+         /interfaces-state/interface list.";
+
+     leaf name {
+        type string;
+        description
+          "The name of the interface.
+
+           A device MAY restrict the allowed values for this leaf,
+           possibly depending on the type of the interface.
+           For system-controlled interfaces, this leaf is the
+           device-specific name of the interface.  The 'config false'
+           list /interfaces-state/interface contains the currently
+           existing interfaces on the device.
+
+           If a client tries to create configuration for a
+           system-controlled interface that is not present in the
+           /interfaces-state/interface list, the server MAY reject
+           the request if the implementation does not support
+           pre-provisioning of interfaces or if the name refers to
+           an interface that can never exist in the system.  A
+           NETCONF server MUST reply with an rpc-error with the
+           error-tag 'invalid-value' in this case.
+
+           If the device supports pre-provisioning of interface
+           configuration, the 'pre-provisioning' feature is
+           advertised.
+
+           If the device allows arbitrarily named user-controlled
+           interfaces, the 'arbitrary-names' feature is advertised.
+
+           When a configured user-controlled interface is created by
+           the system, it is instantiated with the same name in the
+           /interface-state/interface list.";
+      }
+
+      leaf description {
+        type string;
+        description
+          "A textual description of the interface.
+
+           A server implementation MAY map this leaf to the ifAlias
+           MIB object.  Such an implementation needs to use some
+           mechanism to handle the differences in size and characters
+           allowed between this leaf and ifAlias.  The definition of
+           such a mechanism is outside the scope of this document.
+
+           Since ifAlias is defined to be stored in non-volatile
+           storage, the MIB implementation MUST map ifAlias to the
+           value of 'description' in the persistently stored
+           datastore.
+
+           Specifically, if the device supports ':startup', when
+           ifAlias is read the device MUST return the value of
+           'description' in the 'startup' datastore, and when it is
+           written, it MUST be written to the 'running' and 'startup'
+           datastores.  Note that it is up to the implementation to
+
+           decide whether to modify this single leaf in 'startup' or
+           perform an implicit copy-config from 'running' to
+           'startup'.
+
+           If the device does not support ':startup', ifAlias MUST
+           be mapped to the 'description' leaf in the 'running'
+           datastore.";
+        reference
+          "RFC 2863: The Interfaces Group MIB - ifAlias";
+      }
+
+      leaf type {
+        type identityref {
+          base interface-type;
+        }
+        mandatory true;
+        description
+          "The type of the interface.
+
+           When an interface entry is created, a server MAY
+           initialize the type leaf with a valid value, e.g., if it
+           is possible to derive the type from the name of the
+           interface.
+
+           If a client tries to set the type of an interface to a
+           value that can never be used by the system, e.g., if the
+           type is not supported or if the type does not match the
+           name of the interface, the server MUST reject the request.
+           A NETCONF server MUST reply with an rpc-error with the
+           error-tag 'invalid-value' in this case.";
+        reference
+          "RFC 2863: The Interfaces Group MIB - ifType";
+      }
+
+      leaf enabled {
+        type boolean;
+        default "true";
+        description
+          "This leaf contains the configured, desired state of the
+           interface.
+
+           Systems that implement the IF-MIB use the value of this
+           leaf in the 'running' datastore to set
+           IF-MIB.ifAdminStatus to 'up' or 'down' after an ifEntry
+           has been initialized, as described in RFC 2863.
+
+
+
+           Changes in this leaf in the 'running' datastore are
+           reflected in ifAdminStatus, but if ifAdminStatus is
+           changed over SNMP, this leaf is not affected.";
+        reference
+          "RFC 2863: The Interfaces Group MIB - ifAdminStatus";
+      }
+
+      leaf link-up-down-trap-enable {
+        if-feature if-mib;
+        type enumeration {
+          enum enabled {
+            value 1;
+          }
+          enum disabled {
+            value 2;
+          }
+        }
+        description
+          "Controls whether linkUp/linkDown SNMP notifications
+           should be generated for this interface.
+
+           If this node is not configured, the value 'enabled' is
+           operationally used by the server for interfaces that do
+           not operate on top of any other interface (i.e., there are
+           no 'lower-layer-if' entries), and 'disabled' otherwise.";
+        reference
+          "RFC 2863: The Interfaces Group MIB -
+                     ifLinkUpDownTrapEnable";
+      }
+    }
+  }
+
+  /*
+   * Operational state data nodes
+   */
+
+  container interfaces-state {
+    config false;
+    description
+      "Data nodes for the operational state of interfaces.";
+
+    list interface {
+      key "name";
+
+
+
+
+
+      description
+        "The list of interfaces on the device.
+
+         System-controlled interfaces created by the system are
+         always present in this list, whether they are configured or
+         not.";
+
+      leaf name {
+        type string;
+        description
+          "The name of the interface.
+
+           A server implementation MAY map this leaf to the ifName
+           MIB object.  Such an implementation needs to use some
+           mechanism to handle the differences in size and characters
+           allowed between this leaf and ifName.  The definition of
+           such a mechanism is outside the scope of this document.";
+        reference
+          "RFC 2863: The Interfaces Group MIB - ifName";
+      }
+
+      leaf type {
+        type identityref {
+          base interface-type;
+        }
+        mandatory true;
+        description
+          "The type of the interface.";
+        reference
+          "RFC 2863: The Interfaces Group MIB - ifType";
+      }
+
+      leaf admin-status {
+        if-feature if-mib;
+        type enumeration {
+          enum up {
+            value 1;
+            description
+              "Ready to pass packets.";
+          }
+          enum down {
+            value 2;
+            description
+              "Not ready to pass packets and not in some test mode.";
+          }
+
+
+
+          enum testing {
+            value 3;
+            description
+              "In some test mode.";
+          }
+        }
+        mandatory true;
+        description
+          "The desired state of the interface.
+
+           This leaf has the same read semantics as ifAdminStatus.";
+        reference
+          "RFC 2863: The Interfaces Group MIB - ifAdminStatus";
+      }
+
+      leaf oper-status {
+        type enumeration {
+          enum up {
+            value 1;
+            description
+              "Ready to pass packets.";
+          }
+          enum down {
+            value 2;
+            description
+              "The interface does not pass any packets.";
+          }
+          enum testing {
+            value 3;
+            description
+              "In some test mode.  No operational packets can
+               be passed.";
+          }
+          enum unknown {
+            value 4;
+            description
+              "Status cannot be determined for some reason.";
+          }
+          enum dormant {
+            value 5;
+            description
+              "Waiting for some external event.";
+          }
+          enum not-present {
+            value 6;
+            description
+              "Some component (typically hardware) is missing.";
+          }
+          enum lower-layer-down {
+            value 7;
+            description
+              "Down due to state of lower-layer interface(s).";
+          }
+        }
+        mandatory true;
+        description
+          "The current operational state of the interface.
+
+           This leaf has the same semantics as ifOperStatus.";
+        reference
+          "RFC 2863: The Interfaces Group MIB - ifOperStatus";
+      }
+
+      leaf last-change {
+        type yang:date-and-time;
+        description
+          "The time the interface entered its current operational
+           state.  If the current state was entered prior to the
+           last re-initialization of the local network management
+           subsystem, then this node is not present.";
+        reference
+          "RFC 2863: The Interfaces Group MIB - ifLastChange";
+      }
+
+      leaf if-index {
+        if-feature if-mib;
+        type int32 {
+          range "1..2147483647";
+        }
+        mandatory true;
+        description
+          "The ifIndex value for the ifEntry represented by this
+           interface.";
+        reference
+          "RFC 2863: The Interfaces Group MIB - ifIndex";
+      }
+
+      leaf phys-address {
+        type yang:phys-address;
+        description
+          "The interface's address at its protocol sub-layer.  For
+           example, for an 802.x interface, this object normally
+           contains a Media Access Control (MAC) address.  The
+           interface's media-specific modules must define the bit
+
+
+           and byte ordering and the format of the value of this
+           object.  For interfaces that do not have such an address
+           (e.g., a serial line), this node is not present.";
+        reference
+          "RFC 2863: The Interfaces Group MIB - ifPhysAddress";
+      }
+
+      leaf-list higher-layer-if {
+        type interface-state-ref;
+        description
+          "A list of references to interfaces layered on top of this
+           interface.";
+        reference
+          "RFC 2863: The Interfaces Group MIB - ifStackTable";
+      }
+
+      leaf-list lower-layer-if {
+        type interface-state-ref;
+        description
+          "A list of references to interfaces layered underneath this
+           interface.";
+        reference
+          "RFC 2863: The Interfaces Group MIB - ifStackTable";
+      }
+
+      leaf speed {
+        type yang:gauge64;
+        units "bits/second";
+        description
+            "An estimate of the interface's current bandwidth in bits
+             per second.  For interfaces that do not vary in
+             bandwidth or for those where no accurate estimation can
+             be made, this node should contain the nominal bandwidth.
+             For interfaces that have no concept of bandwidth, this
+             node is not present.";
+        reference
+          "RFC 2863: The Interfaces Group MIB -
+                     ifSpeed, ifHighSpeed";
+      }
+
+
+
+
+
+
+
+
+
+      container statistics {
+        description
+          "A collection of interface-related statistics objects.";
+
+        leaf discontinuity-time {
+          type yang:date-and-time;
+          mandatory true;
+          description
+            "The time on the most recent occasion at which any one or
+             more of this interface's counters suffered a
+             discontinuity.  If no such discontinuities have occurred
+             since the last re-initialization of the local management
+             subsystem, then this node contains the time the local
+             management subsystem re-initialized itself.";
+        }
+
+        leaf in-octets {
+          type yang:counter64;
+          description
+            "The total number of octets received on the interface,
+             including framing characters.
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB - ifHCInOctets";
+        }
+
+        leaf in-unicast-pkts {
+          type yang:counter64;
+          description
+            "The number of packets, delivered by this sub-layer to a
+             higher (sub-)layer, that were not addressed to a
+             multicast or broadcast address at this sub-layer.
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB - ifHCInUcastPkts";
+        }
+
+
+
+
+        leaf in-broadcast-pkts {
+          type yang:counter64;
+          description
+            "The number of packets, delivered by this sub-layer to a
+             higher (sub-)layer, that were addressed to a broadcast
+             address at this sub-layer.
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB -
+                       ifHCInBroadcastPkts";
+        }
+
+        leaf in-multicast-pkts {
+          type yang:counter64;
+          description
+            "The number of packets, delivered by this sub-layer to a
+             higher (sub-)layer, that were addressed to a multicast
+             address at this sub-layer.  For a MAC-layer protocol,
+             this includes both Group and Functional addresses.
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB -
+                       ifHCInMulticastPkts";
+        }
+
+        leaf in-discards {
+          type yang:counter32;
+          description
+            "The number of inbound packets that were chosen to be
+             discarded even though no errors had been detected to
+             prevent their being deliverable to a higher-layer
+             protocol.  One possible reason for discarding such a
+             packet could be to free up buffer space.
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+
+
+          reference
+            "RFC 2863: The Interfaces Group MIB - ifInDiscards";
+        }
+
+        leaf in-errors {
+          type yang:counter32;
+          description
+            "For packet-oriented interfaces, the number of inbound
+             packets that contained errors preventing them from being
+             deliverable to a higher-layer protocol.  For character-
+             oriented or fixed-length interfaces, the number of
+             inbound transmission units that contained errors
+             preventing them from being deliverable to a higher-layer
+             protocol.
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB - ifInErrors";
+        }
+
+        leaf in-unknown-protos {
+          type yang:counter32;
+          description
+            "For packet-oriented interfaces, the number of packets
+             received via the interface that were discarded because
+             of an unknown or unsupported protocol.  For
+             character-oriented or fixed-length interfaces that
+             support protocol multiplexing, the number of
+             transmission units received via the interface that were
+             discarded because of an unknown or unsupported protocol.
+             For any interface that does not support protocol
+             multiplexing, this counter is not present.
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB - ifInUnknownProtos";
+        }
+
+
+
+
+
+        leaf out-octets {
+          type yang:counter64;
+          description
+            "The total number of octets transmitted out of the
+             interface, including framing characters.
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB - ifHCOutOctets";
+        }
+
+        leaf out-unicast-pkts {
+          type yang:counter64;
+          description
+            "The total number of packets that higher-level protocols
+             requested be transmitted, and that were not addressed
+             to a multicast or broadcast address at this sub-layer,
+             including those that were discarded or not sent.
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB - ifHCOutUcastPkts";
+        }
+
+        leaf out-broadcast-pkts {
+          type yang:counter64;
+          description
+            "The total number of packets that higher-level protocols
+             requested be transmitted, and that were addressed to a
+             broadcast address at this sub-layer, including those
+             that were discarded or not sent.
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB -
+                       ifHCOutBroadcastPkts";
+        }
+
+
+        leaf out-multicast-pkts {
+          type yang:counter64;
+          description
+            "The total number of packets that higher-level protocols
+             requested be transmitted, and that were addressed to a
+             multicast address at this sub-layer, including those
+             that were discarded or not sent.  For a MAC-layer
+             protocol, this includes both Group and Functional
+             addresses.
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB -
+                       ifHCOutMulticastPkts";
+        }
+
+        leaf out-discards {
+          type yang:counter32;
+          description
+            "The number of outbound packets that were chosen to be
+             discarded even though no errors had been detected to
+             prevent their being transmitted.  One possible reason
+             for discarding such a packet could be to free up buffer
+             space.
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB - ifOutDiscards";
+        }
+
+        leaf out-errors {
+          type yang:counter32;
+          description
+            "For packet-oriented interfaces, the number of outbound
+             packets that could not be transmitted because of errors.
+             For character-oriented or fixed-length interfaces, the
+             number of outbound transmission units that could not be
+             transmitted because of errors.
+
+
+
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB - ifOutErrors";
+        }
+      }
+    }
+  }
+}
diff --git a/tools/lint/examples/ietf-ip.yang b/tools/lint/examples/ietf-ip.yang
new file mode 100644
index 0000000..1499120
--- /dev/null
+++ b/tools/lint/examples/ietf-ip.yang
@@ -0,0 +1,758 @@
+module ietf-ip {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-ip";
+ prefix ip;
+
+ import ietf-interfaces {
+   prefix if;
+ }
+ import ietf-inet-types {
+   prefix inet;
+ }
+ import ietf-yang-types {
+   prefix yang;
+ }
+
+ organization
+   "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+   "WG Web:   <http://tools.ietf.org/wg/netmod/>
+    WG List:  <mailto:netmod@ietf.org>
+
+    WG Chair: Thomas Nadeau
+              <mailto:tnadeau@lucidvision.com>
+
+    WG Chair: Juergen Schoenwaelder
+              <mailto:j.schoenwaelder@jacobs-university.de>
+
+    Editor:   Martin Bjorklund
+              <mailto:mbj@tail-f.com>";
+
+
+
+
+
+
+
+
+
+
+ description
+   "This module contains a collection of YANG definitions for
+    configuring IP implementations.
+
+    Copyright (c) 2014 IETF Trust and the persons identified as
+    authors of the code.  All rights reserved.
+
+    Redistribution and use in source and binary forms, with or
+    without modification, is permitted pursuant to, and subject
+    to the license terms contained in, the Simplified BSD License
+    set forth in Section 4.c of the IETF Trust's Legal Provisions
+    Relating to IETF Documents
+    (http://trustee.ietf.org/license-info).
+
+    This version of this YANG module is part of RFC 7277; see
+    the RFC itself for full legal notices.";
+
+ revision 2014-06-16 {
+   description
+     "Initial revision.";
+   reference
+     "RFC 7277: A YANG Data Model for IP Management";
+ }
+
+ /*
+
+  * Features
+  */
+
+ feature ipv4-non-contiguous-netmasks {
+   description
+     "Indicates support for configuring non-contiguous
+      subnet masks.";
+ }
+
+ feature ipv6-privacy-autoconf {
+   description
+     "Indicates support for Privacy Extensions for Stateless Address
+      Autoconfiguration in IPv6.";
+   reference
+     "RFC 4941: Privacy Extensions for Stateless Address
+                Autoconfiguration in IPv6";
+ }
+
+
+
+
+
+ /*
+  * Typedefs
+  */
+
+ typedef ip-address-origin {
+   type enumeration {
+     enum other {
+       description
+         "None of the following.";
+     }
+     enum static {
+       description
+         "Indicates that the address has been statically
+          configured - for example, using NETCONF or a Command Line
+          Interface.";
+     }
+     enum dhcp {
+       description
+         "Indicates an address that has been assigned to this
+          system by a DHCP server.";
+     }
+     enum link-layer {
+       description
+         "Indicates an address created by IPv6 stateless
+          autoconfiguration that embeds a link-layer address in its
+          interface identifier.";
+     }
+     enum random {
+       description
+         "Indicates an address chosen by the system at
+
+          random, e.g., an IPv4 address within 169.254/16, an
+          RFC 4941 temporary address, or an RFC 7217 semantically
+          opaque address.";
+       reference
+         "RFC 4941: Privacy Extensions for Stateless Address
+                    Autoconfiguration in IPv6
+          RFC 7217: A Method for Generating Semantically Opaque
+                    Interface Identifiers with IPv6 Stateless
+                    Address Autoconfiguration (SLAAC)";
+     }
+   }
+   description
+     "The origin of an address.";
+ }
+
+
+
+ typedef neighbor-origin {
+   type enumeration {
+     enum other {
+       description
+         "None of the following.";
+     }
+     enum static {
+       description
+         "Indicates that the mapping has been statically
+          configured - for example, using NETCONF or a Command Line
+          Interface.";
+     }
+     enum dynamic {
+       description
+         "Indicates that the mapping has been dynamically resolved
+          using, e.g., IPv4 ARP or the IPv6 Neighbor Discovery
+          protocol.";
+     }
+   }
+   description
+     "The origin of a neighbor entry.";
+ }
+
+ /*
+  * Configuration data nodes
+  */
+
+ augment "/if:interfaces/if:interface" {
+   description
+     "Parameters for configuring IP on interfaces.
+
+      If an interface is not capable of running IP, the server
+      must not allow the client to configure these parameters.";
+
+   container ipv4 {
+     presence
+       "Enables IPv4 unless the 'enabled' leaf
+        (which defaults to 'true') is set to 'false'";
+     description
+       "Parameters for the IPv4 address family.";
+
+
+
+
+
+
+
+
+     leaf enabled {
+       type boolean;
+       default true;
+       description
+         "Controls whether IPv4 is enabled or disabled on this
+          interface.  When IPv4 is enabled, this interface is
+          connected to an IPv4 stack, and the interface can send
+          and receive IPv4 packets.";
+     }
+     leaf forwarding {
+       type boolean;
+       default false;
+       description
+         "Controls IPv4 packet forwarding of datagrams received by,
+          but not addressed to, this interface.  IPv4 routers
+          forward datagrams.  IPv4 hosts do not (except those
+          source-routed via the host).";
+     }
+     leaf mtu {
+       type uint16 {
+         range "68..max";
+       }
+       units octets;
+       description
+         "The size, in octets, of the largest IPv4 packet that the
+          interface will send and receive.
+
+          The server may restrict the allowed values for this leaf,
+          depending on the interface's type.
+
+          If this leaf is not configured, the operationally used MTU
+          depends on the interface's type.";
+       reference
+         "RFC 791: Internet Protocol";
+     }
+     list address {
+       key "ip";
+       description
+         "The list of configured IPv4 addresses on the interface.";
+
+       leaf ip {
+         type inet:ipv4-address-no-zone;
+         description
+           "The IPv4 address on the interface.";
+       }
+
+
+
+       choice subnet {
+         mandatory true;
+         description
+           "The subnet can be specified as a prefix-length, or,
+            if the server supports non-contiguous netmasks, as
+            a netmask.";
+         leaf prefix-length {
+           type uint8 {
+             range "0..32";
+           }
+           description
+             "The length of the subnet prefix.";
+         }
+         leaf netmask {
+           if-feature ipv4-non-contiguous-netmasks;
+           type yang:dotted-quad;
+           description
+             "The subnet specified as a netmask.";
+         }
+       }
+     }
+     list neighbor {
+       key "ip";
+       description
+         "A list of mappings from IPv4 addresses to
+          link-layer addresses.
+
+          Entries in this list are used as static entries in the
+          ARP Cache.";
+       reference
+         "RFC 826: An Ethernet Address Resolution Protocol";
+
+       leaf ip {
+         type inet:ipv4-address-no-zone;
+         description
+           "The IPv4 address of the neighbor node.";
+       }
+       leaf link-layer-address {
+         type yang:phys-address;
+         mandatory true;
+         description
+           "The link-layer address of the neighbor node.";
+       }
+     }
+
+   }
+
+
+   container ipv6 {
+     presence
+       "Enables IPv6 unless the 'enabled' leaf
+        (which defaults to 'true') is set to 'false'";
+     description
+       "Parameters for the IPv6 address family.";
+
+     leaf enabled {
+       type boolean;
+       default true;
+       description
+         "Controls whether IPv6 is enabled or disabled on this
+          interface.  When IPv6 is enabled, this interface is
+          connected to an IPv6 stack, and the interface can send
+          and receive IPv6 packets.";
+     }
+     leaf forwarding {
+       type boolean;
+       default false;
+       description
+         "Controls IPv6 packet forwarding of datagrams received by,
+          but not addressed to, this interface.  IPv6 routers
+          forward datagrams.  IPv6 hosts do not (except those
+          source-routed via the host).";
+       reference
+         "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
+                    Section 6.2.1, IsRouter";
+     }
+     leaf mtu {
+       type uint32 {
+         range "1280..max";
+       }
+       units octets;
+       description
+         "The size, in octets, of the largest IPv6 packet that the
+          interface will send and receive.
+
+          The server may restrict the allowed values for this leaf,
+          depending on the interface's type.
+
+          If this leaf is not configured, the operationally used MTU
+          depends on the interface's type.";
+       reference
+         "RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
+                    Section 5";
+     }
+
+
+     list address {
+       key "ip";
+       description
+         "The list of configured IPv6 addresses on the interface.";
+
+       leaf ip {
+         type inet:ipv6-address-no-zone;
+         description
+           "The IPv6 address on the interface.";
+       }
+       leaf prefix-length {
+         type uint8 {
+           range "0..128";
+         }
+         mandatory true;
+         description
+           "The length of the subnet prefix.";
+       }
+     }
+     list neighbor {
+       key "ip";
+       description
+         "A list of mappings from IPv6 addresses to
+          link-layer addresses.
+
+          Entries in this list are used as static entries in the
+          Neighbor Cache.";
+       reference
+         "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)";
+
+       leaf ip {
+         type inet:ipv6-address-no-zone;
+         description
+           "The IPv6 address of the neighbor node.";
+       }
+       leaf link-layer-address {
+         type yang:phys-address;
+         mandatory true;
+         description
+           "The link-layer address of the neighbor node.";
+       }
+     }
+
+
+
+
+
+
+     leaf dup-addr-detect-transmits {
+       type uint32;
+       default 1;
+       description
+         "The number of consecutive Neighbor Solicitation messages
+          sent while performing Duplicate Address Detection on a
+          tentative address.  A value of zero indicates that
+          Duplicate Address Detection is not performed on
+          tentative addresses.  A value of one indicates a single
+          transmission with no follow-up retransmissions.";
+       reference
+         "RFC 4862: IPv6 Stateless Address Autoconfiguration";
+     }
+     container autoconf {
+       description
+         "Parameters to control the autoconfiguration of IPv6
+          addresses, as described in RFC 4862.";
+       reference
+         "RFC 4862: IPv6 Stateless Address Autoconfiguration";
+
+       leaf create-global-addresses {
+         type boolean;
+         default true;
+         description
+           "If enabled, the host creates global addresses as
+            described in RFC 4862.";
+         reference
+           "RFC 4862: IPv6 Stateless Address Autoconfiguration
+                      Section 5.5";
+       }
+       leaf create-temporary-addresses {
+         if-feature ipv6-privacy-autoconf;
+         type boolean;
+         default false;
+         description
+           "If enabled, the host creates temporary addresses as
+            described in RFC 4941.";
+         reference
+           "RFC 4941: Privacy Extensions for Stateless Address
+                      Autoconfiguration in IPv6";
+       }
+
+
+
+
+
+
+
+       leaf temporary-valid-lifetime {
+         if-feature ipv6-privacy-autoconf;
+         type uint32;
+         units "seconds";
+         default 604800;
+         description
+           "The time period during which the temporary address
+            is valid.";
+         reference
+           "RFC 4941: Privacy Extensions for Stateless Address
+                      Autoconfiguration in IPv6
+                      - TEMP_VALID_LIFETIME";
+       }
+       leaf temporary-preferred-lifetime {
+         if-feature ipv6-privacy-autoconf;
+         type uint32;
+         units "seconds";
+         default 86400;
+         description
+           "The time period during which the temporary address is
+            preferred.";
+         reference
+           "RFC 4941: Privacy Extensions for Stateless Address
+                      Autoconfiguration in IPv6
+                      - TEMP_PREFERRED_LIFETIME";
+       }
+     }
+   }
+ }
+
+ /*
+  * Operational state data nodes
+  */
+
+ augment "/if:interfaces-state/if:interface" {
+   description
+     "Data nodes for the operational state of IP on interfaces.";
+
+   container ipv4 {
+     presence "Present if IPv4 is enabled on this interface";
+     config false;
+     description
+       "Interface-specific parameters for the IPv4 address family.";
+
+
+
+
+
+     leaf forwarding {
+       type boolean;
+       description
+         "Indicates whether IPv4 packet forwarding is enabled or
+          disabled on this interface.";
+     }
+     leaf mtu {
+       type uint16 {
+         range "68..max";
+       }
+       units octets;
+       description
+         "The size, in octets, of the largest IPv4 packet that the
+          interface will send and receive.";
+       reference
+         "RFC 791: Internet Protocol";
+     }
+     list address {
+       key "ip";
+       description
+         "The list of IPv4 addresses on the interface.";
+
+       leaf ip {
+         type inet:ipv4-address-no-zone;
+         description
+           "The IPv4 address on the interface.";
+       }
+       choice subnet {
+         description
+           "The subnet can be specified as a prefix-length, or,
+            if the server supports non-contiguous netmasks, as
+            a netmask.";
+         leaf prefix-length {
+           type uint8 {
+             range "0..32";
+           }
+           description
+             "The length of the subnet prefix.";
+         }
+         leaf netmask {
+           if-feature ipv4-non-contiguous-netmasks;
+           type yang:dotted-quad;
+           description
+             "The subnet specified as a netmask.";
+         }
+       }
+
+
+       leaf origin {
+         type ip-address-origin;
+         description
+           "The origin of this address.";
+       }
+     }
+     list neighbor {
+       key "ip";
+       description
+         "A list of mappings from IPv4 addresses to
+          link-layer addresses.
+
+          This list represents the ARP Cache.";
+       reference
+         "RFC 826: An Ethernet Address Resolution Protocol";
+
+       leaf ip {
+         type inet:ipv4-address-no-zone;
+         description
+           "The IPv4 address of the neighbor node.";
+       }
+       leaf link-layer-address {
+         type yang:phys-address;
+         description
+           "The link-layer address of the neighbor node.";
+       }
+       leaf origin {
+         type neighbor-origin;
+         description
+           "The origin of this neighbor entry.";
+       }
+     }
+
+   }
+
+   container ipv6 {
+     presence "Present if IPv6 is enabled on this interface";
+     config false;
+     description
+       "Parameters for the IPv6 address family.";
+
+
+
+
+
+
+
+
+     leaf forwarding {
+       type boolean;
+       default false;
+       description
+         "Indicates whether IPv6 packet forwarding is enabled or
+          disabled on this interface.";
+       reference
+         "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
+                    Section 6.2.1, IsRouter";
+     }
+     leaf mtu {
+       type uint32 {
+         range "1280..max";
+       }
+       units octets;
+       description
+         "The size, in octets, of the largest IPv6 packet that the
+          interface will send and receive.";
+       reference
+         "RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
+                    Section 5";
+     }
+     list address {
+       key "ip";
+       description
+         "The list of IPv6 addresses on the interface.";
+
+       leaf ip {
+         type inet:ipv6-address-no-zone;
+         description
+           "The IPv6 address on the interface.";
+       }
+       leaf prefix-length {
+         type uint8 {
+           range "0..128";
+         }
+         mandatory true;
+         description
+           "The length of the subnet prefix.";
+       }
+       leaf origin {
+         type ip-address-origin;
+         description
+           "The origin of this address.";
+       }
+
+
+
+       leaf status {
+         type enumeration {
+           enum preferred {
+             description
+               "This is a valid address that can appear as the
+                destination or source address of a packet.";
+           }
+           enum deprecated {
+             description
+               "This is a valid but deprecated address that should
+                no longer be used as a source address in new
+                communications, but packets addressed to such an
+                address are processed as expected.";
+           }
+           enum invalid {
+             description
+               "This isn't a valid address, and it shouldn't appear
+                as the destination or source address of a packet.";
+           }
+           enum inaccessible {
+             description
+               "The address is not accessible because the interface
+                to which this address is assigned is not
+                operational.";
+           }
+           enum unknown {
+             description
+               "The status cannot be determined for some reason.";
+           }
+           enum tentative {
+             description
+               "The uniqueness of the address on the link is being
+                verified.  Addresses in this state should not be
+                used for general communication and should only be
+                used to determine the uniqueness of the address.";
+           }
+           enum duplicate {
+             description
+               "The address has been determined to be non-unique on
+                the link and so must not be used.";
+           }
+
+
+
+
+
+
+
+           enum optimistic {
+             description
+               "The address is available for use, subject to
+                restrictions, while its uniqueness on a link is
+                being verified.";
+           }
+         }
+         description
+           "The status of an address.  Most of the states correspond
+            to states from the IPv6 Stateless Address
+            Autoconfiguration protocol.";
+         reference
+           "RFC 4293: Management Information Base for the
+                      Internet Protocol (IP)
+                      - IpAddressStatusTC
+            RFC 4862: IPv6 Stateless Address Autoconfiguration";
+       }
+     }
+     list neighbor {
+       key "ip";
+       description
+         "A list of mappings from IPv6 addresses to
+          link-layer addresses.
+
+          This list represents the Neighbor Cache.";
+       reference
+         "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)";
+
+       leaf ip {
+         type inet:ipv6-address-no-zone;
+         description
+           "The IPv6 address of the neighbor node.";
+       }
+       leaf link-layer-address {
+         type yang:phys-address;
+         description
+           "The link-layer address of the neighbor node.";
+       }
+       leaf origin {
+         type neighbor-origin;
+         description
+           "The origin of this neighbor entry.";
+       }
+       leaf is-router {
+         type empty;
+         description
+           "Indicates that the neighbor node acts as a router.";
+       }
+       leaf state {
+         type enumeration {
+           enum incomplete {
+             description
+               "Address resolution is in progress, and the link-layer
+                address of the neighbor has not yet been
+                determined.";
+           }
+           enum reachable {
+             description
+               "Roughly speaking, the neighbor is known to have been
+                reachable recently (within tens of seconds ago).";
+           }
+           enum stale {
+             description
+               "The neighbor is no longer known to be reachable, but
+                until traffic is sent to the neighbor no attempt
+                should be made to verify its reachability.";
+           }
+           enum delay {
+             description
+               "The neighbor is no longer known to be reachable, and
+                traffic has recently been sent to the neighbor.
+                Rather than probe the neighbor immediately, however,
+                delay sending probes for a short while in order to
+                give upper-layer protocols a chance to provide
+                reachability confirmation.";
+           }
+           enum probe {
+             description
+               "The neighbor is no longer known to be reachable, and
+                unicast Neighbor Solicitation probes are being sent
+                to verify reachability.";
+           }
+         }
+         description
+           "The Neighbor Unreachability Detection state of this
+            entry.";
+         reference
+           "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
+                      Section 7.3.2";
+       }
+     }
+   }
+ }
+}
diff --git a/tools/lint/examples/ietf-netconf-acm-when.yang b/tools/lint/examples/ietf-netconf-acm-when.yang
new file mode 100644
index 0000000..df8f801
--- /dev/null
+++ b/tools/lint/examples/ietf-netconf-acm-when.yang
@@ -0,0 +1,412 @@
+module ietf-netconf-acm-when2 {
+  namespace "urn:ietf:params:xml:ns:yang:ietf-netconf-acm";
+  prefix nacm;
+
+  import ietf-yang-types {
+    prefix yang;
+  }
+
+  organization
+    "IETF NETCONF (Network Configuration) Working Group";
+  contact
+    "WG Web:   <http://tools.ietf.org/wg/netconf/>
+     WG List:  <mailto:netconf@ietf.org>
+     
+     WG Chair: Mehmet Ersue
+               <mailto:mehmet.ersue@nsn.com>
+     
+     WG Chair: Bert Wijnen
+               <mailto:bertietf@bwijnen.net>
+     
+     Editor:   Andy Bierman
+               <mailto:andy@yumaworks.com>
+     
+     Editor:   Martin Bjorklund
+               <mailto:mbj@tail-f.com>";
+  description
+    "NETCONF Access Control Model.
+     
+     Copyright (c) 2012 IETF Trust and the persons identified as
+     authors of the code.  All rights reserved.
+     
+     Redistribution and use in source and binary forms, with or
+     without modification, is permitted pursuant to, and subject
+     to the license terms contained in, the Simplified BSD
+     License set forth in Section 4.c of the IETF Trust's
+     Legal Provisions Relating to IETF Documents
+     (http://trustee.ietf.org/license-info).
+     
+     This version of this YANG module is part of RFC 6536; see
+     the RFC itself for full legal notices.";
+
+  revision 2012-02-22 {
+    description
+      "Initial version";
+    reference
+      "RFC 6536: Network Configuration Protocol (NETCONF)
+                 Access Control Model";
+  }
+
+  extension default-deny-write {
+    description
+      "Used to indicate that the data model node
+       represents a sensitive security system parameter.
+       
+       If present, and the NACM module is enabled (i.e.,
+       /nacm/enable-nacm object equals 'true'), the NETCONF server
+       will only allow the designated 'recovery session' to have
+       write access to the node.  An explicit access control rule is
+       required for all other users.
+       
+       The 'default-deny-write' extension MAY appear within a data
+       definition statement.  It is ignored otherwise.";
+  }
+
+  extension default-deny-all {
+    description
+      "Used to indicate that the data model node
+       controls a very sensitive security system parameter.
+       
+       If present, and the NACM module is enabled (i.e.,
+       /nacm/enable-nacm object equals 'true'), the NETCONF server
+       will only allow the designated 'recovery session' to have
+       read, write, or execute access to the node.  An explicit
+       access control rule is required for all other users.
+       
+       The 'default-deny-all' extension MAY appear within a data
+       definition statement, 'rpc' statement, or 'notification'
+       statement.  It is ignored otherwise.";
+  }
+
+  typedef user-name-type {
+    type string {
+      length "1..max";
+    }
+    description
+      "General Purpose Username string.";
+  }
+
+  typedef matchall-string-type {
+    type string {
+      pattern "\\*";
+    }
+    description
+      "The string containing a single asterisk '*' is used
+       to conceptually represent all possible values
+       for the particular leaf using this data type.";
+  }
+
+  typedef access-operations-type {
+    type bits {
+      bit create {
+        description
+          "Any protocol operation that creates a
+           new data node.";
+      }
+      bit read {
+        description
+          "Any protocol operation or notification that
+           returns the value of a data node.";
+      }
+      bit update {
+        description
+          "Any protocol operation that alters an existing
+           data node.";
+      }
+      bit delete {
+        description
+          "Any protocol operation that removes a data node.";
+      }
+      bit exec {
+        description
+          "Execution access to the specified protocol operation.";
+      }
+    }
+    description
+      "NETCONF Access Operation.";
+  }
+
+  typedef group-name-type {
+    type string {
+      length "1..max";
+      pattern "[^\\*].*";
+    }
+    description
+      "Name of administrative group to which
+       users can be assigned.";
+  }
+
+  typedef action-type {
+    type enumeration {
+      enum "permit" {
+        description
+          "Requested action is permitted.";
+      }
+      enum "deny" {
+        description
+          "Requested action is denied.";
+      }
+    }
+    description
+      "Action taken by the server when a particular
+       rule matches.";
+  }
+
+  typedef node-instance-identifier {
+    type yang:xpath1.0;
+    description
+      "Path expression used to represent a special
+       data node instance identifier string.
+       
+       A node-instance-identifier value is an
+       unrestricted YANG instance-identifier expression.
+       All the same rules as an instance-identifier apply
+       except predicates for keys are optional.  If a key
+       predicate is missing, then the node-instance-identifier
+       represents all possible server instances for that key.
+       
+       This XPath expression is evaluated in the following context:
+       
+        o  The set of namespace declarations are those in scope on
+           the leaf element where this type is used.
+       
+        o  The set of variable bindings contains one variable,
+           'USER', which contains the name of the user of the current
+            session.
+       
+        o  The function library is the core function library, but
+           note that due to the syntax restrictions of an
+           instance-identifier, no functions are allowed.
+       
+        o  The context node is the root node in the data tree.";
+  }
+
+  container nacm {
+    nacm:default-deny-all;
+    description
+      "Parameters for NETCONF Access Control Model.";
+    leaf enable-nacm {
+      type boolean;
+      default "true";
+      description
+        "Enables or disables all NETCONF access control
+         enforcement.  If 'true', then enforcement
+         is enabled.  If 'false', then enforcement
+         is disabled.";
+    }
+    leaf read-default {
+      type action-type;
+      default "permit";
+      description
+        "Controls whether read access is granted if
+         no appropriate rule is found for a
+         particular read request.";
+    }
+    leaf write-default {
+      type action-type;
+      default "deny";
+      description
+        "Controls whether create, update, or delete access
+         is granted if no appropriate rule is found for a
+         particular write request.";
+    }
+    leaf exec-default {
+      type action-type;
+      default "permit";
+      description
+        "Controls whether exec access is granted if no appropriate
+         rule is found for a particular protocol operation request.";
+    }
+    leaf enable-external-groups {
+      type boolean;
+      default "true";
+      description
+        "Controls whether the server uses the groups reported by the
+         NETCONF transport layer when it assigns the user to a set of
+         NACM groups.  If this leaf has the value 'false', any group
+         names reported by the transport layer are ignored by the
+         server.";
+    }
+    leaf denied-operations {
+      type yang:zero-based-counter32;
+      config false;
+      mandatory true;
+      description
+        "Number of times since the server last restarted that a
+         protocol operation request was denied.";
+    }
+    leaf denied-data-writes {
+      type yang:zero-based-counter32;
+      config false;
+      mandatory true;
+      when "../denied-operations > 0";
+      description
+        "Number of times since the server last restarted that a
+         protocol operation request to alter
+         a configuration datastore was denied.";
+    }
+    leaf denied-notifications {
+      type yang:zero-based-counter32;
+      config false;
+      mandatory true;
+      description
+        "Number of times since the server last restarted that
+         a notification was dropped for a subscription because
+         access to the event type was denied.";
+    }
+    container groups {
+      description
+        "NETCONF Access Control Groups.";
+      list group {
+        key "name";
+        description
+          "One NACM Group Entry.  This list will only contain
+           configured entries, not any entries learned from
+           any transport protocols.";
+        leaf name {
+          type group-name-type;
+          description
+            "Group name associated with this entry.";
+        }
+        leaf-list user-name {
+          type user-name-type;
+          description
+            "Each entry identifies the username of
+             a member of the group associated with
+             this entry.";
+        }
+      }
+    }
+    list rule-list {
+      key "name";
+      ordered-by user;
+      description
+        "An ordered collection of access control rules.";
+      leaf name {
+        type string {
+          length "1..max";
+        }
+        description
+          "Arbitrary name assigned to the rule-list.";
+      }
+      leaf-list group {
+        type union {
+          type matchall-string-type;
+          type group-name-type;
+        }
+        description
+          "List of administrative groups that will be
+           assigned the associated access rights
+           defined by the 'rule' list.
+           
+           The string '*' indicates that all groups apply to the
+           entry.";
+      }
+      list rule {
+        key "name";
+        ordered-by user;
+        description
+          "One access control rule.
+           
+           Rules are processed in user-defined order until a match is
+           found.  A rule matches if 'module-name', 'rule-type', and
+           'access-operations' match the request.  If a rule
+           matches, the 'action' leaf determines if access is granted
+           or not.";
+        leaf name {
+          type string {
+            length "1..max";
+          }
+          description
+            "Arbitrary name assigned to the rule.";
+        }
+        leaf module-name {
+          type union {
+            type matchall-string-type;
+            type string;
+          }
+          default "*";
+          description
+            "Name of the module associated with this rule.
+             
+             This leaf matches if it has the value '*' or if the
+             object being accessed is defined in the module with the
+             specified module name.";
+        }
+        choice rule-type {
+          description
+            "This choice matches if all leafs present in the rule
+             match the request.  If no leafs are present, the
+             choice matches all requests.";
+          case protocol-operation {
+            leaf rpc-name {
+              type union {
+                type matchall-string-type;
+                type string;
+              }
+              description
+                "This leaf matches if it has the value '*' or if
+                 its value equals the requested protocol operation
+                 name.";
+            }
+          }
+          case notification {
+            leaf notification-name {
+              type union {
+                type matchall-string-type;
+                type string;
+              }
+              description
+                "This leaf matches if it has the value '*' or if its
+                 value equals the requested notification name.";
+            }
+          }
+          case data-node {
+            leaf path {
+              type node-instance-identifier;
+              mandatory true;
+              description
+                "Data Node Instance Identifier associated with the
+                 data node controlled by this rule.
+                 
+                 Configuration data or state data instance
+                 identifiers start with a top-level data node.  A
+                 complete instance identifier is required for this
+                 type of path value.
+                 
+                 The special value '/' refers to all possible
+                 datastore contents.";
+            }
+          }
+        }
+        leaf access-operations {
+          type union {
+            type matchall-string-type;
+            type access-operations-type;
+          }
+          default "*";
+          description
+            "Access operations associated with this rule.
+             
+             This leaf matches if it has the value '*' or if the
+             bit corresponding to the requested operation is set.";
+        }
+        leaf action {
+          type action-type;
+          mandatory true;
+          description
+            "The access control action associated with the
+             rule.  If a rule is determined to match a
+             particular request, then this object is used
+             to determine whether to permit or deny the
+             request.";
+        }
+        leaf comment {
+          type string;
+          description
+            "A textual description of the access rule.";
+        }
+      }
+    }
+  }
+}
diff --git a/tools/lint/examples/ietf-netconf-acm-when.yin b/tools/lint/examples/ietf-netconf-acm-when.yin
new file mode 100644
index 0000000..cbff758
--- /dev/null
+++ b/tools/lint/examples/ietf-netconf-acm-when.yin
@@ -0,0 +1,447 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module xmlns="urn:ietf:params:xml:ns:yang:yin:1" xmlns:nacm="urn:ietf:params:xml:ns:yang:ietf-netconf-acm" xmlns:yang="urn:ietf:params:xml:ns:yang:ietf-yang-types" name="ietf-netconf-acm-when">
+  <namespace uri="urn:ietf:params:xml:ns:yang:ietf-netconf-acm"/>
+  <prefix value="nacm"/>
+  <import module="ietf-yang-types">
+    <prefix value="yang"/>
+  </import>
+  <organization>
+    <text>IETF NETCONF (Network Configuration) Working Group</text>
+  </organization>
+  <contact>
+    <text>WG Web:   &lt;http://tools.ietf.org/wg/netconf/&gt;
+WG List:  &lt;mailto:netconf@ietf.org&gt;
+
+WG Chair: Mehmet Ersue
+          &lt;mailto:mehmet.ersue@nsn.com&gt;
+
+WG Chair: Bert Wijnen
+          &lt;mailto:bertietf@bwijnen.net&gt;
+
+Editor:   Andy Bierman
+          &lt;mailto:andy@yumaworks.com&gt;
+
+Editor:   Martin Bjorklund
+          &lt;mailto:mbj@tail-f.com&gt;</text>
+  </contact>
+  <description>
+    <text>NETCONF Access Control Model.
+
+Copyright (c) 2012 IETF Trust and the persons identified as
+authors of the code.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or
+without modification, is permitted pursuant to, and subject
+to the license terms contained in, the Simplified BSD
+License set forth in Section 4.c of the IETF Trust's
+Legal Provisions Relating to IETF Documents
+(http://trustee.ietf.org/license-info).
+
+This version of this YANG module is part of RFC 6536; see
+the RFC itself for full legal notices.</text>
+  </description>
+  <revision date="2012-02-22">
+    <description>
+      <text>Initial version</text>
+    </description>
+    <reference>
+      <text>RFC 6536: Network Configuration Protocol (NETCONF)
+          Access Control Model</text>
+    </reference>
+  </revision>
+  <extension name="default-deny-write">
+    <description>
+      <text>Used to indicate that the data model node
+represents a sensitive security system parameter.
+
+If present, and the NACM module is enabled (i.e.,
+/nacm/enable-nacm object equals 'true'), the NETCONF server
+will only allow the designated 'recovery session' to have
+write access to the node.  An explicit access control rule is
+required for all other users.
+
+The 'default-deny-write' extension MAY appear within a data
+definition statement.  It is ignored otherwise.</text>
+    </description>
+  </extension>
+  <extension name="default-deny-all">
+    <description>
+      <text>Used to indicate that the data model node
+controls a very sensitive security system parameter.
+
+If present, and the NACM module is enabled (i.e.,
+/nacm/enable-nacm object equals 'true'), the NETCONF server
+will only allow the designated 'recovery session' to have
+read, write, or execute access to the node.  An explicit
+access control rule is required for all other users.
+
+The 'default-deny-all' extension MAY appear within a data
+definition statement, 'rpc' statement, or 'notification'
+statement.  It is ignored otherwise.</text>
+    </description>
+  </extension>
+  <typedef name="user-name-type">
+    <type name="string">
+      <length value="1..max"/>
+    </type>
+    <description>
+      <text>General Purpose Username string.</text>
+    </description>
+  </typedef>
+  <typedef name="matchall-string-type">
+    <type name="string">
+      <pattern value="\*"/>
+    </type>
+    <description>
+      <text>The string containing a single asterisk '*' is used
+to conceptually represent all possible values
+for the particular leaf using this data type.</text>
+    </description>
+  </typedef>
+  <typedef name="access-operations-type">
+    <type name="bits">
+      <bit name="create">
+        <description>
+          <text>Any protocol operation that creates a
+new data node.</text>
+        </description>
+      </bit>
+      <bit name="read">
+        <description>
+          <text>Any protocol operation or notification that
+returns the value of a data node.</text>
+        </description>
+      </bit>
+      <bit name="update">
+        <description>
+          <text>Any protocol operation that alters an existing
+data node.</text>
+        </description>
+      </bit>
+      <bit name="delete">
+        <description>
+          <text>Any protocol operation that removes a data node.</text>
+        </description>
+      </bit>
+      <bit name="exec">
+        <description>
+          <text>Execution access to the specified protocol operation.</text>
+        </description>
+      </bit>
+    </type>
+    <description>
+      <text>NETCONF Access Operation.</text>
+    </description>
+  </typedef>
+  <typedef name="group-name-type">
+    <type name="string">
+      <length value="1..max"/>
+      <pattern value="[^\*].*"/>
+    </type>
+    <description>
+      <text>Name of administrative group to which
+users can be assigned.</text>
+    </description>
+  </typedef>
+  <typedef name="action-type">
+    <type name="enumeration">
+      <enum name="permit">
+        <description>
+          <text>Requested action is permitted.</text>
+        </description>
+      </enum>
+      <enum name="deny">
+        <description>
+          <text>Requested action is denied.</text>
+        </description>
+      </enum>
+    </type>
+    <description>
+      <text>Action taken by the server when a particular
+rule matches.</text>
+    </description>
+  </typedef>
+  <typedef name="node-instance-identifier">
+    <type name="yang:xpath1.0"/>
+    <description>
+      <text>Path expression used to represent a special
+data node instance identifier string.
+
+A node-instance-identifier value is an
+unrestricted YANG instance-identifier expression.
+All the same rules as an instance-identifier apply
+except predicates for keys are optional.  If a key
+predicate is missing, then the node-instance-identifier
+represents all possible server instances for that key.
+
+This XPath expression is evaluated in the following context:
+
+ o  The set of namespace declarations are those in scope on
+    the leaf element where this type is used.
+
+ o  The set of variable bindings contains one variable,
+    'USER', which contains the name of the user of the current
+     session.
+
+ o  The function library is the core function library, but
+    note that due to the syntax restrictions of an
+    instance-identifier, no functions are allowed.
+
+ o  The context node is the root node in the data tree.</text>
+    </description>
+  </typedef>
+  <container name="nacm">
+    <nacm:default-deny-all/>
+    <description>
+      <text>Parameters for NETCONF Access Control Model.</text>
+    </description>
+    <leaf name="enable-nacm">
+      <type name="boolean"/>
+      <default value="true"/>
+      <description>
+        <text>Enables or disables all NETCONF access control
+enforcement.  If 'true', then enforcement
+is enabled.  If 'false', then enforcement
+is disabled.</text>
+      </description>
+    </leaf>
+    <leaf name="read-default">
+      <type name="action-type"/>
+      <default value="permit"/>
+      <description>
+        <text>Controls whether read access is granted if
+no appropriate rule is found for a
+particular read request.</text>
+      </description>
+    </leaf>
+    <leaf name="write-default">
+      <type name="action-type"/>
+      <default value="deny"/>
+      <description>
+        <text>Controls whether create, update, or delete access
+is granted if no appropriate rule is found for a
+particular write request.</text>
+      </description>
+    </leaf>
+    <leaf name="exec-default">
+      <type name="action-type"/>
+      <default value="permit"/>
+      <description>
+        <text>Controls whether exec access is granted if no appropriate
+rule is found for a particular protocol operation request.</text>
+      </description>
+    </leaf>
+    <leaf name="enable-external-groups">
+      <type name="boolean"/>
+      <default value="true"/>
+      <description>
+        <text>Controls whether the server uses the groups reported by the
+NETCONF transport layer when it assigns the user to a set of
+NACM groups.  If this leaf has the value 'false', any group
+names reported by the transport layer are ignored by the
+server.</text>
+      </description>
+    </leaf>
+    <leaf name="denied-operations">
+      <type name="yang:zero-based-counter32"/>
+      <config value="false"/>
+      <mandatory value="true"/>
+      <description>
+        <text>Number of times since the server last restarted that a
+protocol operation request was denied.</text>
+      </description>
+    </leaf>
+    <leaf name="denied-data-writes">
+      <type name="yang:zero-based-counter32"/>
+      <config value="false"/>
+      <mandatory value="true"/>
+      <when value="../denied-operations > 0"/>
+      <description>
+        <text>Number of times since the server last restarted that a
+protocol operation request to alter
+a configuration datastore was denied.</text>
+      </description>
+    </leaf>
+    <leaf name="denied-notifications">
+      <type name="yang:zero-based-counter32"/>
+      <config value="false"/>
+      <mandatory value="true"/>
+      <description>
+        <text>Number of times since the server last restarted that
+a notification was dropped for a subscription because
+access to the event type was denied.</text>
+      </description>
+    </leaf>
+    <container name="groups">
+      <description>
+        <text>NETCONF Access Control Groups.</text>
+      </description>
+      <list name="group">
+        <key value="name"/>
+        <description>
+          <text>One NACM Group Entry.  This list will only contain
+configured entries, not any entries learned from
+any transport protocols.</text>
+        </description>
+        <leaf name="name">
+          <type name="group-name-type"/>
+          <description>
+            <text>Group name associated with this entry.</text>
+          </description>
+        </leaf>
+        <leaf-list name="user-name">
+          <type name="user-name-type"/>
+          <description>
+            <text>Each entry identifies the username of
+a member of the group associated with
+this entry.</text>
+          </description>
+        </leaf-list>
+      </list>
+    </container>
+    <list name="rule-list">
+      <key value="name"/>
+      <ordered-by value="user"/>
+      <description>
+        <text>An ordered collection of access control rules.</text>
+      </description>
+      <leaf name="name">
+        <type name="string">
+          <length value="1..max"/>
+        </type>
+        <description>
+          <text>Arbitrary name assigned to the rule-list.</text>
+        </description>
+      </leaf>
+      <leaf-list name="group">
+        <type name="union">
+          <type name="matchall-string-type"/>
+          <type name="group-name-type"/>
+        </type>
+        <description>
+          <text>List of administrative groups that will be
+assigned the associated access rights
+defined by the 'rule' list.
+
+The string '*' indicates that all groups apply to the
+entry.</text>
+        </description>
+      </leaf-list>
+      <list name="rule">
+        <key value="name"/>
+        <ordered-by value="user"/>
+        <description>
+          <text>One access control rule.
+
+Rules are processed in user-defined order until a match is
+found.  A rule matches if 'module-name', 'rule-type', and
+'access-operations' match the request.  If a rule
+matches, the 'action' leaf determines if access is granted
+or not.</text>
+        </description>
+        <leaf name="name">
+          <type name="string">
+            <length value="1..max"/>
+          </type>
+          <description>
+            <text>Arbitrary name assigned to the rule.</text>
+          </description>
+        </leaf>
+        <leaf name="module-name">
+          <type name="union">
+            <type name="matchall-string-type"/>
+            <type name="string"/>
+          </type>
+          <default value="*"/>
+          <description>
+            <text>Name of the module associated with this rule.
+
+This leaf matches if it has the value '*' or if the
+object being accessed is defined in the module with the
+specified module name.</text>
+          </description>
+        </leaf>
+        <choice name="rule-type">
+          <description>
+            <text>This choice matches if all leafs present in the rule
+match the request.  If no leafs are present, the
+choice matches all requests.</text>
+          </description>
+          <case name="protocol-operation">
+            <leaf name="rpc-name">
+              <type name="union">
+                <type name="matchall-string-type"/>
+                <type name="string"/>
+              </type>
+              <description>
+                <text>This leaf matches if it has the value '*' or if
+its value equals the requested protocol operation
+name.</text>
+              </description>
+            </leaf>
+          </case>
+          <case name="notification">
+            <leaf name="notification-name">
+              <type name="union">
+                <type name="matchall-string-type"/>
+                <type name="string"/>
+              </type>
+              <description>
+                <text>This leaf matches if it has the value '*' or if its
+value equals the requested notification name.</text>
+              </description>
+            </leaf>
+          </case>
+          <case name="data-node">
+            <leaf name="path">
+              <type name="node-instance-identifier"/>
+              <mandatory value="true"/>
+              <description>
+                <text>Data Node Instance Identifier associated with the
+data node controlled by this rule.
+
+Configuration data or state data instance
+identifiers start with a top-level data node.  A
+complete instance identifier is required for this
+type of path value.
+
+The special value '/' refers to all possible
+datastore contents.</text>
+              </description>
+            </leaf>
+          </case>
+        </choice>
+        <leaf name="access-operations">
+          <type name="union">
+            <type name="matchall-string-type"/>
+            <type name="access-operations-type"/>
+          </type>
+          <default value="*"/>
+          <description>
+            <text>Access operations associated with this rule.
+
+This leaf matches if it has the value '*' or if the
+bit corresponding to the requested operation is set.</text>
+          </description>
+        </leaf>
+        <leaf name="action">
+          <type name="action-type"/>
+          <mandatory value="true"/>
+          <description>
+            <text>The access control action associated with the
+rule.  If a rule is determined to match a
+particular request, then this object is used
+to determine whether to permit or deny the
+request.</text>
+          </description>
+        </leaf>
+        <leaf name="comment">
+          <type name="string"/>
+          <description>
+            <text>A textual description of the access rule.</text>
+          </description>
+        </leaf>
+      </list>
+    </list>
+  </container>
+</module>
diff --git a/tools/lint/examples/ietf-netconf-acm-when2.yin b/tools/lint/examples/ietf-netconf-acm-when2.yin
new file mode 100644
index 0000000..f8f25a0
--- /dev/null
+++ b/tools/lint/examples/ietf-netconf-acm-when2.yin
@@ -0,0 +1,447 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module xmlns="urn:ietf:params:xml:ns:yang:yin:1" xmlns:nacm="urn:ietf:params:xml:ns:yang:ietf-netconf-acm" xmlns:yang="urn:ietf:params:xml:ns:yang:ietf-yang-types" name="ietf-netconf-acm-when2">
+  <namespace uri="urn:ietf:params:xml:ns:yang:ietf-netconf-acm"/>
+  <prefix value="nacm"/>
+  <import module="ietf-yang-types">
+    <prefix value="yang"/>
+  </import>
+  <organization>
+    <text>IETF NETCONF (Network Configuration) Working Group</text>
+  </organization>
+  <contact>
+    <text>WG Web:   &lt;http://tools.ietf.org/wg/netconf/&gt;
+WG List:  &lt;mailto:netconf@ietf.org&gt;
+
+WG Chair: Mehmet Ersue
+          &lt;mailto:mehmet.ersue@nsn.com&gt;
+
+WG Chair: Bert Wijnen
+          &lt;mailto:bertietf@bwijnen.net&gt;
+
+Editor:   Andy Bierman
+          &lt;mailto:andy@yumaworks.com&gt;
+
+Editor:   Martin Bjorklund
+          &lt;mailto:mbj@tail-f.com&gt;</text>
+  </contact>
+  <description>
+    <text>NETCONF Access Control Model.
+
+Copyright (c) 2012 IETF Trust and the persons identified as
+authors of the code.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or
+without modification, is permitted pursuant to, and subject
+to the license terms contained in, the Simplified BSD
+License set forth in Section 4.c of the IETF Trust's
+Legal Provisions Relating to IETF Documents
+(http://trustee.ietf.org/license-info).
+
+This version of this YANG module is part of RFC 6536; see
+the RFC itself for full legal notices.</text>
+  </description>
+  <revision date="2012-02-22">
+    <description>
+      <text>Initial version</text>
+    </description>
+    <reference>
+      <text>RFC 6536: Network Configuration Protocol (NETCONF)
+          Access Control Model</text>
+    </reference>
+  </revision>
+  <extension name="default-deny-write">
+    <description>
+      <text>Used to indicate that the data model node
+represents a sensitive security system parameter.
+
+If present, and the NACM module is enabled (i.e.,
+/nacm/enable-nacm object equals 'true'), the NETCONF server
+will only allow the designated 'recovery session' to have
+write access to the node.  An explicit access control rule is
+required for all other users.
+
+The 'default-deny-write' extension MAY appear within a data
+definition statement.  It is ignored otherwise.</text>
+    </description>
+  </extension>
+  <extension name="default-deny-all">
+    <description>
+      <text>Used to indicate that the data model node
+controls a very sensitive security system parameter.
+
+If present, and the NACM module is enabled (i.e.,
+/nacm/enable-nacm object equals 'true'), the NETCONF server
+will only allow the designated 'recovery session' to have
+read, write, or execute access to the node.  An explicit
+access control rule is required for all other users.
+
+The 'default-deny-all' extension MAY appear within a data
+definition statement, 'rpc' statement, or 'notification'
+statement.  It is ignored otherwise.</text>
+    </description>
+  </extension>
+  <typedef name="user-name-type">
+    <type name="string">
+      <length value="1..max"/>
+    </type>
+    <description>
+      <text>General Purpose Username string.</text>
+    </description>
+  </typedef>
+  <typedef name="matchall-string-type">
+    <type name="string">
+      <pattern value="\*"/>
+    </type>
+    <description>
+      <text>The string containing a single asterisk '*' is used
+to conceptually represent all possible values
+for the particular leaf using this data type.</text>
+    </description>
+  </typedef>
+  <typedef name="access-operations-type">
+    <type name="bits">
+      <bit name="create">
+        <description>
+          <text>Any protocol operation that creates a
+new data node.</text>
+        </description>
+      </bit>
+      <bit name="read">
+        <description>
+          <text>Any protocol operation or notification that
+returns the value of a data node.</text>
+        </description>
+      </bit>
+      <bit name="update">
+        <description>
+          <text>Any protocol operation that alters an existing
+data node.</text>
+        </description>
+      </bit>
+      <bit name="delete">
+        <description>
+          <text>Any protocol operation that removes a data node.</text>
+        </description>
+      </bit>
+      <bit name="exec">
+        <description>
+          <text>Execution access to the specified protocol operation.</text>
+        </description>
+      </bit>
+    </type>
+    <description>
+      <text>NETCONF Access Operation.</text>
+    </description>
+  </typedef>
+  <typedef name="group-name-type">
+    <type name="string">
+      <length value="1..max"/>
+      <pattern value="[^\*].*"/>
+    </type>
+    <description>
+      <text>Name of administrative group to which
+users can be assigned.</text>
+    </description>
+  </typedef>
+  <typedef name="action-type">
+    <type name="enumeration">
+      <enum name="permit">
+        <description>
+          <text>Requested action is permitted.</text>
+        </description>
+      </enum>
+      <enum name="deny">
+        <description>
+          <text>Requested action is denied.</text>
+        </description>
+      </enum>
+    </type>
+    <description>
+      <text>Action taken by the server when a particular
+rule matches.</text>
+    </description>
+  </typedef>
+  <typedef name="node-instance-identifier">
+    <type name="yang:xpath1.0"/>
+    <description>
+      <text>Path expression used to represent a special
+data node instance identifier string.
+
+A node-instance-identifier value is an
+unrestricted YANG instance-identifier expression.
+All the same rules as an instance-identifier apply
+except predicates for keys are optional.  If a key
+predicate is missing, then the node-instance-identifier
+represents all possible server instances for that key.
+
+This XPath expression is evaluated in the following context:
+
+ o  The set of namespace declarations are those in scope on
+    the leaf element where this type is used.
+
+ o  The set of variable bindings contains one variable,
+    'USER', which contains the name of the user of the current
+     session.
+
+ o  The function library is the core function library, but
+    note that due to the syntax restrictions of an
+    instance-identifier, no functions are allowed.
+
+ o  The context node is the root node in the data tree.</text>
+    </description>
+  </typedef>
+  <container name="nacm">
+    <nacm:default-deny-all/>
+    <description>
+      <text>Parameters for NETCONF Access Control Model.</text>
+    </description>
+    <leaf name="enable-nacm">
+      <type name="boolean"/>
+      <default value="true"/>
+      <description>
+        <text>Enables or disables all NETCONF access control
+enforcement.  If 'true', then enforcement
+is enabled.  If 'false', then enforcement
+is disabled.</text>
+      </description>
+    </leaf>
+    <leaf name="read-default">
+      <type name="action-type"/>
+      <default value="permit"/>
+      <description>
+        <text>Controls whether read access is granted if
+no appropriate rule is found for a
+particular read request.</text>
+      </description>
+    </leaf>
+    <leaf name="write-default">
+      <type name="action-type"/>
+      <default value="deny"/>
+      <description>
+        <text>Controls whether create, update, or delete access
+is granted if no appropriate rule is found for a
+particular write request.</text>
+      </description>
+    </leaf>
+    <leaf name="exec-default">
+      <type name="action-type"/>
+      <default value="permit"/>
+      <description>
+        <text>Controls whether exec access is granted if no appropriate
+rule is found for a particular protocol operation request.</text>
+      </description>
+    </leaf>
+    <leaf name="enable-external-groups">
+      <type name="boolean"/>
+      <default value="true"/>
+      <description>
+        <text>Controls whether the server uses the groups reported by the
+NETCONF transport layer when it assigns the user to a set of
+NACM groups.  If this leaf has the value 'false', any group
+names reported by the transport layer are ignored by the
+server.</text>
+      </description>
+    </leaf>
+    <leaf name="denied-operations">
+      <type name="yang:zero-based-counter32"/>
+      <config value="false"/>
+      <mandatory value="true"/>
+      <description>
+        <text>Number of times since the server last restarted that a
+protocol operation request was denied.</text>
+      </description>
+    </leaf>
+    <leaf name="denied-data-writes">
+      <type name="yang:zero-based-counter32"/>
+      <config value="false"/>
+      <mandatory value="true"/>
+      <when condition="../denied-operations > 0"/>
+      <description>
+        <text>Number of times since the server last restarted that a
+protocol operation request to alter
+a configuration datastore was denied.</text>
+      </description>
+    </leaf>
+    <leaf name="denied-notifications">
+      <type name="yang:zero-based-counter32"/>
+      <config value="false"/>
+      <mandatory value="true"/>
+      <description>
+        <text>Number of times since the server last restarted that
+a notification was dropped for a subscription because
+access to the event type was denied.</text>
+      </description>
+    </leaf>
+    <container name="groups">
+      <description>
+        <text>NETCONF Access Control Groups.</text>
+      </description>
+      <list name="group">
+        <key value="name"/>
+        <description>
+          <text>One NACM Group Entry.  This list will only contain
+configured entries, not any entries learned from
+any transport protocols.</text>
+        </description>
+        <leaf name="name">
+          <type name="group-name-type"/>
+          <description>
+            <text>Group name associated with this entry.</text>
+          </description>
+        </leaf>
+        <leaf-list name="user-name">
+          <type name="user-name-type"/>
+          <description>
+            <text>Each entry identifies the username of
+a member of the group associated with
+this entry.</text>
+          </description>
+        </leaf-list>
+      </list>
+    </container>
+    <list name="rule-list">
+      <key value="name"/>
+      <ordered-by value="user"/>
+      <description>
+        <text>An ordered collection of access control rules.</text>
+      </description>
+      <leaf name="name">
+        <type name="string">
+          <length value="1..max"/>
+        </type>
+        <description>
+          <text>Arbitrary name assigned to the rule-list.</text>
+        </description>
+      </leaf>
+      <leaf-list name="group">
+        <type name="union">
+          <type name="matchall-string-type"/>
+          <type name="group-name-type"/>
+        </type>
+        <description>
+          <text>List of administrative groups that will be
+assigned the associated access rights
+defined by the 'rule' list.
+
+The string '*' indicates that all groups apply to the
+entry.</text>
+        </description>
+      </leaf-list>
+      <list name="rule">
+        <key value="name"/>
+        <ordered-by value="user"/>
+        <description>
+          <text>One access control rule.
+
+Rules are processed in user-defined order until a match is
+found.  A rule matches if 'module-name', 'rule-type', and
+'access-operations' match the request.  If a rule
+matches, the 'action' leaf determines if access is granted
+or not.</text>
+        </description>
+        <leaf name="name">
+          <type name="string">
+            <length value="1..max"/>
+          </type>
+          <description>
+            <text>Arbitrary name assigned to the rule.</text>
+          </description>
+        </leaf>
+        <leaf name="module-name">
+          <type name="union">
+            <type name="matchall-string-type"/>
+            <type name="string"/>
+          </type>
+          <default value="*"/>
+          <description>
+            <text>Name of the module associated with this rule.
+
+This leaf matches if it has the value '*' or if the
+object being accessed is defined in the module with the
+specified module name.</text>
+          </description>
+        </leaf>
+        <choice name="rule-type">
+          <description>
+            <text>This choice matches if all leafs present in the rule
+match the request.  If no leafs are present, the
+choice matches all requests.</text>
+          </description>
+          <case name="protocol-operation">
+            <leaf name="rpc-name">
+              <type name="union">
+                <type name="matchall-string-type"/>
+                <type name="string"/>
+              </type>
+              <description>
+                <text>This leaf matches if it has the value '*' or if
+its value equals the requested protocol operation
+name.</text>
+              </description>
+            </leaf>
+          </case>
+          <case name="notification">
+            <leaf name="notification-name">
+              <type name="union">
+                <type name="matchall-string-type"/>
+                <type name="string"/>
+              </type>
+              <description>
+                <text>This leaf matches if it has the value '*' or if its
+value equals the requested notification name.</text>
+              </description>
+            </leaf>
+          </case>
+          <case name="data-node">
+            <leaf name="path">
+              <type name="node-instance-identifier"/>
+              <mandatory value="true"/>
+              <description>
+                <text>Data Node Instance Identifier associated with the
+data node controlled by this rule.
+
+Configuration data or state data instance
+identifiers start with a top-level data node.  A
+complete instance identifier is required for this
+type of path value.
+
+The special value '/' refers to all possible
+datastore contents.</text>
+              </description>
+            </leaf>
+          </case>
+        </choice>
+        <leaf name="access-operations">
+          <type name="union">
+            <type name="matchall-string-type"/>
+            <type name="access-operations-type"/>
+          </type>
+          <default value="*"/>
+          <description>
+            <text>Access operations associated with this rule.
+
+This leaf matches if it has the value '*' or if the
+bit corresponding to the requested operation is set.</text>
+          </description>
+        </leaf>
+        <leaf name="action">
+          <type name="action-type"/>
+          <mandatory value="true"/>
+          <description>
+            <text>The access control action associated with the
+rule.  If a rule is determined to match a
+particular request, then this object is used
+to determine whether to permit or deny the
+request.</text>
+          </description>
+        </leaf>
+        <leaf name="comment">
+          <type name="string"/>
+          <description>
+            <text>A textual description of the access rule.</text>
+          </description>
+        </leaf>
+      </list>
+    </list>
+  </container>
+</module>
diff --git a/tools/lint/examples/ietf-netconf-acm.yang b/tools/lint/examples/ietf-netconf-acm.yang
new file mode 100644
index 0000000..dc3655e
--- /dev/null
+++ b/tools/lint/examples/ietf-netconf-acm.yang
@@ -0,0 +1,411 @@
+module ietf-netconf-acm {
+  namespace "urn:ietf:params:xml:ns:yang:ietf-netconf-acm";
+  prefix nacm;
+
+  import ietf-yang-types {
+    prefix yang;
+  }
+
+  organization
+    "IETF NETCONF (Network Configuration) Working Group";
+  contact
+    "WG Web:   <http://tools.ietf.org/wg/netconf/>
+     WG List:  <mailto:netconf@ietf.org>
+     
+     WG Chair: Mehmet Ersue
+               <mailto:mehmet.ersue@nsn.com>
+     
+     WG Chair: Bert Wijnen
+               <mailto:bertietf@bwijnen.net>
+     
+     Editor:   Andy Bierman
+               <mailto:andy@yumaworks.com>
+     
+     Editor:   Martin Bjorklund
+               <mailto:mbj@tail-f.com>";
+  description
+    "NETCONF Access Control Model.
+     
+     Copyright (c) 2012 IETF Trust and the persons identified as
+     authors of the code.  All rights reserved.
+     
+     Redistribution and use in source and binary forms, with or
+     without modification, is permitted pursuant to, and subject
+     to the license terms contained in, the Simplified BSD
+     License set forth in Section 4.c of the IETF Trust's
+     Legal Provisions Relating to IETF Documents
+     (http://trustee.ietf.org/license-info).
+     
+     This version of this YANG module is part of RFC 6536; see
+     the RFC itself for full legal notices.";
+
+  revision 2012-02-22 {
+    description
+      "Initial version";
+    reference
+      "RFC 6536: Network Configuration Protocol (NETCONF)
+                 Access Control Model";
+  }
+
+  extension default-deny-write {
+    description
+      "Used to indicate that the data model node
+       represents a sensitive security system parameter.
+       
+       If present, and the NACM module is enabled (i.e.,
+       /nacm/enable-nacm object equals 'true'), the NETCONF server
+       will only allow the designated 'recovery session' to have
+       write access to the node.  An explicit access control rule is
+       required for all other users.
+       
+       The 'default-deny-write' extension MAY appear within a data
+       definition statement.  It is ignored otherwise.";
+  }
+
+  extension default-deny-all {
+    description
+      "Used to indicate that the data model node
+       controls a very sensitive security system parameter.
+       
+       If present, and the NACM module is enabled (i.e.,
+       /nacm/enable-nacm object equals 'true'), the NETCONF server
+       will only allow the designated 'recovery session' to have
+       read, write, or execute access to the node.  An explicit
+       access control rule is required for all other users.
+       
+       The 'default-deny-all' extension MAY appear within a data
+       definition statement, 'rpc' statement, or 'notification'
+       statement.  It is ignored otherwise.";
+  }
+
+  typedef user-name-type {
+    type string {
+      length "1..max";
+    }
+    description
+      "General Purpose Username string.";
+  }
+
+  typedef matchall-string-type {
+    type string {
+      pattern "\\*";
+    }
+    description
+      "The string containing a single asterisk '*' is used
+       to conceptually represent all possible values
+       for the particular leaf using this data type.";
+  }
+
+  typedef access-operations-type {
+    type bits {
+      bit create {
+        description
+          "Any protocol operation that creates a
+           new data node.";
+      }
+      bit read {
+        description
+          "Any protocol operation or notification that
+           returns the value of a data node.";
+      }
+      bit update {
+        description
+          "Any protocol operation that alters an existing
+           data node.";
+      }
+      bit delete {
+        description
+          "Any protocol operation that removes a data node.";
+      }
+      bit exec {
+        description
+          "Execution access to the specified protocol operation.";
+      }
+    }
+    description
+      "NETCONF Access Operation.";
+  }
+
+  typedef group-name-type {
+    type string {
+      length "1..max";
+      pattern "[^\\*].*";
+    }
+    description
+      "Name of administrative group to which
+       users can be assigned.";
+  }
+
+  typedef action-type {
+    type enumeration {
+      enum "permit" {
+        description
+          "Requested action is permitted.";
+      }
+      enum "deny" {
+        description
+          "Requested action is denied.";
+      }
+    }
+    description
+      "Action taken by the server when a particular
+       rule matches.";
+  }
+
+  typedef node-instance-identifier {
+    type yang:xpath1.0;
+    description
+      "Path expression used to represent a special
+       data node instance identifier string.
+       
+       A node-instance-identifier value is an
+       unrestricted YANG instance-identifier expression.
+       All the same rules as an instance-identifier apply
+       except predicates for keys are optional.  If a key
+       predicate is missing, then the node-instance-identifier
+       represents all possible server instances for that key.
+       
+       This XPath expression is evaluated in the following context:
+       
+        o  The set of namespace declarations are those in scope on
+           the leaf element where this type is used.
+       
+        o  The set of variable bindings contains one variable,
+           'USER', which contains the name of the user of the current
+            session.
+       
+        o  The function library is the core function library, but
+           note that due to the syntax restrictions of an
+           instance-identifier, no functions are allowed.
+       
+        o  The context node is the root node in the data tree.";
+  }
+
+  container nacm {
+    nacm:default-deny-all;
+    description
+      "Parameters for NETCONF Access Control Model.";
+    leaf enable-nacm {
+      type boolean;
+      default "true";
+      description
+        "Enables or disables all NETCONF access control
+         enforcement.  If 'true', then enforcement
+         is enabled.  If 'false', then enforcement
+         is disabled.";
+    }
+    leaf read-default {
+      type action-type;
+      default "permit";
+      description
+        "Controls whether read access is granted if
+         no appropriate rule is found for a
+         particular read request.";
+    }
+    leaf write-default {
+      type action-type;
+      default "deny";
+      description
+        "Controls whether create, update, or delete access
+         is granted if no appropriate rule is found for a
+         particular write request.";
+    }
+    leaf exec-default {
+      type action-type;
+      default "permit";
+      description
+        "Controls whether exec access is granted if no appropriate
+         rule is found for a particular protocol operation request.";
+    }
+    leaf enable-external-groups {
+      type boolean;
+      default "true";
+      description
+        "Controls whether the server uses the groups reported by the
+         NETCONF transport layer when it assigns the user to a set of
+         NACM groups.  If this leaf has the value 'false', any group
+         names reported by the transport layer are ignored by the
+         server.";
+    }
+    leaf denied-operations {
+      type yang:zero-based-counter32;
+      config false;
+      mandatory true;
+      description
+        "Number of times since the server last restarted that a
+         protocol operation request was denied.";
+    }
+    leaf denied-data-writes {
+      type yang:zero-based-counter32;
+      config false;
+      mandatory true;
+      description
+        "Number of times since the server last restarted that a
+         protocol operation request to alter
+         a configuration datastore was denied.";
+    }
+    leaf denied-notifications {
+      type yang:zero-based-counter32;
+      config false;
+      mandatory true;
+      description
+        "Number of times since the server last restarted that
+         a notification was dropped for a subscription because
+         access to the event type was denied.";
+    }
+    container groups {
+      description
+        "NETCONF Access Control Groups.";
+      list group {
+        key "name";
+        description
+          "One NACM Group Entry.  This list will only contain
+           configured entries, not any entries learned from
+           any transport protocols.";
+        leaf name {
+          type group-name-type;
+          description
+            "Group name associated with this entry.";
+        }
+        leaf-list user-name {
+          type user-name-type;
+          description
+            "Each entry identifies the username of
+             a member of the group associated with
+             this entry.";
+        }
+      }
+    }
+    list rule-list {
+      key "name";
+      ordered-by user;
+      description
+        "An ordered collection of access control rules.";
+      leaf name {
+        type string {
+          length "1..max";
+        }
+        description
+          "Arbitrary name assigned to the rule-list.";
+      }
+      leaf-list group {
+        type union {
+          type matchall-string-type;
+          type group-name-type;
+        }
+        description
+          "List of administrative groups that will be
+           assigned the associated access rights
+           defined by the 'rule' list.
+           
+           The string '*' indicates that all groups apply to the
+           entry.";
+      }
+      list rule {
+        key "name";
+        ordered-by user;
+        description
+          "One access control rule.
+           
+           Rules are processed in user-defined order until a match is
+           found.  A rule matches if 'module-name', 'rule-type', and
+           'access-operations' match the request.  If a rule
+           matches, the 'action' leaf determines if access is granted
+           or not.";
+        leaf name {
+          type string {
+            length "1..max";
+          }
+          description
+            "Arbitrary name assigned to the rule.";
+        }
+        leaf module-name {
+          type union {
+            type matchall-string-type;
+            type string;
+          }
+          default "*";
+          description
+            "Name of the module associated with this rule.
+             
+             This leaf matches if it has the value '*' or if the
+             object being accessed is defined in the module with the
+             specified module name.";
+        }
+        choice rule-type {
+          description
+            "This choice matches if all leafs present in the rule
+             match the request.  If no leafs are present, the
+             choice matches all requests.";
+          case protocol-operation {
+            leaf rpc-name {
+              type union {
+                type matchall-string-type;
+                type string;
+              }
+              description
+                "This leaf matches if it has the value '*' or if
+                 its value equals the requested protocol operation
+                 name.";
+            }
+          }
+          case notification {
+            leaf notification-name {
+              type union {
+                type matchall-string-type;
+                type string;
+              }
+              description
+                "This leaf matches if it has the value '*' or if its
+                 value equals the requested notification name.";
+            }
+          }
+          case data-node {
+            leaf path {
+              type node-instance-identifier;
+              mandatory true;
+              description
+                "Data Node Instance Identifier associated with the
+                 data node controlled by this rule.
+                 
+                 Configuration data or state data instance
+                 identifiers start with a top-level data node.  A
+                 complete instance identifier is required for this
+                 type of path value.
+                 
+                 The special value '/' refers to all possible
+                 datastore contents.";
+            }
+          }
+        }
+        leaf access-operations {
+          type union {
+            type matchall-string-type;
+            type access-operations-type;
+          }
+          default "*";
+          description
+            "Access operations associated with this rule.
+             
+             This leaf matches if it has the value '*' or if the
+             bit corresponding to the requested operation is set.";
+        }
+        leaf action {
+          type action-type;
+          mandatory true;
+          description
+            "The access control action associated with the
+             rule.  If a rule is determined to match a
+             particular request, then this object is used
+             to determine whether to permit or deny the
+             request.";
+        }
+        leaf comment {
+          type string;
+          description
+            "A textual description of the access rule.";
+        }
+      }
+    }
+  }
+}
diff --git a/tools/lint/examples/module1.yang b/tools/lint/examples/module1.yang
new file mode 100644
index 0000000..1df7bf1
--- /dev/null
+++ b/tools/lint/examples/module1.yang
@@ -0,0 +1,5 @@
+module module1 {
+  namespace "urn:yanglint:module";
+  prefix m;
+  leaf m { type string; }
+}
diff --git a/tools/lint/examples/module1b.yang b/tools/lint/examples/module1b.yang
new file mode 100644
index 0000000..463c936
--- /dev/null
+++ b/tools/lint/examples/module1b.yang
@@ -0,0 +1,5 @@
+module module1b {
+  namespace "urn:yanglint:module";
+  prefix m;
+  leaf mb { type string; }
+}
diff --git a/tools/lint/examples/module2.yang b/tools/lint/examples/module2.yang
new file mode 100644
index 0000000..c87c764
--- /dev/null
+++ b/tools/lint/examples/module2.yang
@@ -0,0 +1,5 @@
+module module2 {
+  namespace "urn:yanglint:module";
+  prefix m;
+  leaf m { ttype string; }
+}
diff --git a/tools/lint/examples/module2.yin b/tools/lint/examples/module2.yin
new file mode 100644
index 0000000..af6cb50
--- /dev/null
+++ b/tools/lint/examples/module2.yin
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module name="module2"
+        xmlns="urn:ietf:params:xml:ns:yang:yin:1"
+        xmlns:m="urn:yanglint:module">
+  <namespace uri="urn:yanglint:module"/>
+  <prefix value="m"/>
+  <leaf name="m">
+    <type value="string"/>
+  </leaf>
+</module>
diff --git a/tools/lint/examples/module3.yang b/tools/lint/examples/module3.yang
new file mode 100644
index 0000000..63754b1
--- /dev/null
+++ b/tools/lint/examples/module3.yang
@@ -0,0 +1,8 @@
+module module3 {
+  namespace "urn:yanglint:module";
+  prefix m;
+  leaf m { type string; must "../c/a"; }
+  container c {
+    leaf b { type string; }
+  }
+}
diff --git a/tools/lint/examples/module4.yang b/tools/lint/examples/module4.yang
new file mode 100644
index 0000000..23ea289
--- /dev/null
+++ b/tools/lint/examples/module4.yang
@@ -0,0 +1,52 @@
+module module4 {
+  yang-version 1.1;
+  namespace "urn:module4";
+  prefix m4;
+
+  container cont1 {
+    list list {
+      key "leaf1";
+      leaf leaf1 {
+        type string;
+      }
+      action act {
+        input {
+          leaf leaf2 {
+            type string;
+          }
+        }
+        output {
+          leaf leaf3 {
+            type string;
+          }
+        }
+      }
+      notification notif1 {
+        leaf leaf4 {
+          type string;
+        }
+      }
+    }
+  }
+
+  rpc rpc {
+    input {
+      leaf leaf5 {
+        type string;
+      }
+    }
+    output {
+      container cont2 {
+        leaf leaf6 {
+          type empty;
+        }
+      }
+    }
+  }
+
+  notification notif2 {
+    leaf leaf7 {
+      type empty;
+    }
+  }
+}
diff --git a/tools/lint/examples/nested-notification.xml b/tools/lint/examples/nested-notification.xml
new file mode 100644
index 0000000..024b65a
--- /dev/null
+++ b/tools/lint/examples/nested-notification.xml
@@ -0,0 +1,8 @@
+<cont1 xmlns="urn:module4">
+  <list>
+    <leaf1>key_val</leaf1>
+    <notif1>
+      <leaf4>some_value</leaf4>
+    </notif1>
+  </list>
+</cont1>
diff --git a/tools/lint/examples/notification.xml b/tools/lint/examples/notification.xml
new file mode 100644
index 0000000..803ddad
--- /dev/null
+++ b/tools/lint/examples/notification.xml
@@ -0,0 +1,3 @@
+<notif2 xmlns="urn:module4">
+  <leaf7/>
+</notif2>
diff --git a/tools/lint/examples/rpc-reply.xml b/tools/lint/examples/rpc-reply.xml
new file mode 100644
index 0000000..20469dd
--- /dev/null
+++ b/tools/lint/examples/rpc-reply.xml
@@ -0,0 +1,3 @@
+<cont2 xmlns="urn:module4">
+  <leaf6/>
+</cont2>
diff --git a/tools/lint/examples/rpc.xml b/tools/lint/examples/rpc.xml
new file mode 100644
index 0000000..ea8ca90
--- /dev/null
+++ b/tools/lint/examples/rpc.xml
@@ -0,0 +1,3 @@
+<rpc xmlns="urn:module4">
+  <leaf5>some_input</leaf5>
+</rpc>
diff --git a/tools/lint/linenoise/LICENSE b/tools/lint/linenoise/LICENSE
new file mode 100644
index 0000000..18e8148
--- /dev/null
+++ b/tools/lint/linenoise/LICENSE
@@ -0,0 +1,25 @@
+Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>
+Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+  this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/tools/lint/linenoise/linenoise.c b/tools/lint/linenoise/linenoise.c
new file mode 100644
index 0000000..eefbeb3
--- /dev/null
+++ b/tools/lint/linenoise/linenoise.c
@@ -0,0 +1,1226 @@
+/* linenoise.c -- VERSION 1.0
+ *
+ * Guerrilla line editing library against the idea that a line editing lib
+ * needs to be 20,000 lines of C code.
+ *
+ * You can find the latest source code at:
+ *
+ *   http://github.com/antirez/linenoise
+ *
+ * Does a number of crazy assumptions that happen to be true in 99.9999% of
+ * the 2010 UNIX computers around.
+ *
+ * ------------------------------------------------------------------------
+ *
+ * Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>
+ * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  *  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *  *  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ------------------------------------------------------------------------
+ *
+ * References:
+ * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
+ * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html
+ *
+ * Todo list:
+ * - Filter bogus Ctrl+<char> combinations.
+ * - Win32 support
+ *
+ * Bloat:
+ * - History search like Ctrl+r in readline?
+ *
+ * List of escape sequences used by this program, we do everything just
+ * with three sequences. In order to be so cheap we may have some
+ * flickering effect with some slow terminal, but the lesser sequences
+ * the more compatible.
+ *
+ * EL (Erase Line)
+ *    Sequence: ESC [ n K
+ *    Effect: if n is 0 or missing, clear from cursor to end of line
+ *    Effect: if n is 1, clear from beginning of line to cursor
+ *    Effect: if n is 2, clear entire line
+ *
+ * CUF (CUrsor Forward)
+ *    Sequence: ESC [ n C
+ *    Effect: moves cursor forward n chars
+ *
+ * CUB (CUrsor Backward)
+ *    Sequence: ESC [ n D
+ *    Effect: moves cursor backward n chars
+ *
+ * The following is used to get the terminal width if getting
+ * the width with the TIOCGWINSZ ioctl fails
+ *
+ * DSR (Device Status Report)
+ *    Sequence: ESC [ 6 n
+ *    Effect: reports the current cusor position as ESC [ n ; m R
+ *            where n is the row and m is the column
+ *
+ * When multi line mode is enabled, we also use an additional escape
+ * sequence. However multi line editing is disabled by default.
+ *
+ * CUU (Cursor Up)
+ *    Sequence: ESC [ n A
+ *    Effect: moves cursor up of n chars.
+ *
+ * CUD (Cursor Down)
+ *    Sequence: ESC [ n B
+ *    Effect: moves cursor down of n chars.
+ *
+ * When linenoiseClearScreen() is called, two additional escape sequences
+ * are used in order to clear the screen and position the cursor at home
+ * position.
+ *
+ * CUP (Cursor position)
+ *    Sequence: ESC [ H
+ *    Effect: moves the cursor to upper left corner
+ *
+ * ED (Erase display)
+ *    Sequence: ESC [ 2 J
+ *    Effect: clear the whole screen
+ *
+ */
+
+#define _GNU_SOURCE
+
+#include <termios.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "linenoise.h"
+
+#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
+#define LINENOISE_MAX_LINE 4096
+static char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
+static linenoiseCompletionCallback *completionCallback = NULL;
+
+static struct termios orig_termios; /* In order to restore at exit.*/
+static int mlmode = 0;  /* Multi line mode. Default is single line. */
+static int atexit_registered = 0; /* Register atexit just 1 time. */
+static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
+static int history_len = 0;
+static char **history = NULL;
+
+/* The linenoiseState structure represents the state during line editing.
+ * We pass this state to functions implementing specific editing
+ * functionalities. */
+struct linenoiseState ls;
+
+enum KEY_ACTION{
+	KEY_NULL = 0,	    /* NULL */
+	CTRL_A = 1,         /* Ctrl+a */
+	CTRL_B = 2,         /* Ctrl-b */
+	CTRL_C = 3,         /* Ctrl-c */
+	CTRL_D = 4,         /* Ctrl-d */
+	CTRL_E = 5,         /* Ctrl-e */
+	CTRL_F = 6,         /* Ctrl-f */
+	CTRL_H = 8,         /* Ctrl-h */
+	TAB = 9,            /* Tab */
+	CTRL_K = 11,        /* Ctrl+k */
+	CTRL_L = 12,        /* Ctrl+l */
+	ENTER = 13,         /* Enter */
+	CTRL_N = 14,        /* Ctrl-n */
+	CTRL_P = 16,        /* Ctrl-p */
+	CTRL_T = 20,        /* Ctrl-t */
+	CTRL_U = 21,        /* Ctrl+u */
+	CTRL_W = 23,        /* Ctrl+w */
+	ESC = 27,           /* Escape */
+	BACKSPACE =  127    /* Backspace */
+};
+
+static void linenoiseAtExit(void);
+int linenoiseHistoryAdd(const char *line);
+
+/* Debugging macro. */
+#if 0
+FILE *lndebug_fp = NULL;
+#define lndebug(...) \
+    do { \
+        if (lndebug_fp == NULL) { \
+            lndebug_fp = fopen("/tmp/lndebug.txt","a"); \
+            fprintf(lndebug_fp, \
+            "[%d %d %d] p: %d, rows: %d, rpos: %d, max: %d, oldmax: %d\n", \
+            (int)l->len,(int)l->pos,(int)l->oldpos,plen,rows,rpos, \
+            (int)l->maxrows,old_rows); \
+        } \
+        fprintf(lndebug_fp, ", " __VA_ARGS__); \
+        fflush(lndebug_fp); \
+    } while (0)
+#else
+#define lndebug(fmt, ...)
+#endif
+
+/* ======================= Low level terminal handling ====================== */
+
+/* Set if to use or not the multi line mode. */
+void linenoiseSetMultiLine(int ml) {
+    mlmode = ml;
+}
+
+/* Return true if the terminal name is in the list of terminals we know are
+ * not able to understand basic escape sequences. */
+static int isUnsupportedTerm(void) {
+    char *term = getenv("TERM");
+    int j;
+
+    if (term == NULL) return 0;
+    for (j = 0; unsupported_term[j]; j++)
+        if (!strcasecmp(term,unsupported_term[j])) return 1;
+    return 0;
+}
+
+/* Raw mode: 1960 magic shit. */
+int linenoiseEnableRawMode(int fd) {
+    struct termios raw;
+
+    if (!isatty(STDIN_FILENO)) goto fatal;
+    if (!atexit_registered) {
+        atexit(linenoiseAtExit);
+        atexit_registered = 1;
+    }
+    if (tcgetattr(fd,&orig_termios) == -1) goto fatal;
+
+    raw = orig_termios;  /* modify the original mode */
+    /* input modes: no break, no CR to NL, no parity check, no strip char,
+     * no start/stop output control. */
+    raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+    /* output modes - disable post processing */
+    raw.c_oflag &= ~(OPOST);
+    /* control modes - set 8 bit chars */
+    raw.c_cflag |= (CS8);
+    /* local modes - choing off, canonical off, no extended functions,
+     * no signal chars (^Z,^C) */
+    raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
+    /* control chars - set return condition: min number of bytes and timer.
+     * We want read to return every single byte, without timeout. */
+    raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
+
+    /* put terminal in raw mode after flushing */
+    if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) goto fatal;
+    ls.rawmode = 1;
+    return 0;
+
+fatal:
+    errno = ENOTTY;
+    return -1;
+}
+
+void linenoiseDisableRawMode(int fd) {
+    /* Don't even check the return value as it's too late. */
+    if (ls.rawmode && tcsetattr(fd,TCSAFLUSH,&orig_termios) != -1)
+        ls.rawmode = 0;
+}
+
+/* Use the ESC [6n escape sequence to query the horizontal cursor position
+ * and return it. On error -1 is returned, on success the position of the
+ * cursor. */
+static int getCursorPosition(int ifd, int ofd) {
+    char buf[32];
+    int cols, rows;
+    unsigned int i = 0;
+
+    /* Report cursor location */
+    if (write(ofd, "\x1b[6n", 4) != 4) return -1;
+
+    /* Read the response: ESC [ rows ; cols R */
+    while (i < sizeof(buf)-1) {
+        if (read(ifd,buf+i,1) != 1) break;
+        if (buf[i] == 'R') break;
+        i++;
+    }
+    buf[i] = '\0';
+
+    /* Parse it. */
+    if (buf[0] != ESC || buf[1] != '[') return -1;
+    if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1;
+    return cols;
+}
+
+/* Try to get the number of columns in the current terminal, or assume 80
+ * if it fails. */
+static int getColumns(int ifd, int ofd) {
+    struct winsize ws;
+
+    if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {
+        /* ioctl() failed. Try to query the terminal itself. */
+        int start, cols;
+
+        /* Get the initial position so we can restore it later. */
+        start = getCursorPosition(ifd,ofd);
+        if (start == -1) goto failed;
+
+        /* Go to right margin and get position. */
+        if (write(ofd,"\x1b[999C",6) != 6) goto failed;
+        cols = getCursorPosition(ifd,ofd);
+        if (cols == -1) goto failed;
+
+        /* Restore position. */
+        if (cols > start) {
+            char seq[32];
+            snprintf(seq,32,"\x1b[%dD",cols-start);
+            if (write(ofd,seq,strlen(seq)) == -1) {
+                /* Can't recover... */
+            }
+        }
+        return cols;
+    } else {
+        return ws.ws_col;
+    }
+
+failed:
+    return 80;
+}
+
+/* Clear the screen. Used to handle ctrl+l */
+void linenoiseClearScreen(void) {
+    if (write(STDOUT_FILENO,"\x1b[H\x1b[2J",7) <= 0) {
+        /* nothing to do, just to avoid warning. */
+    }
+}
+
+/* Beep, used for completion when there is nothing to complete or when all
+ * the choices were already shown. */
+static void linenoiseBeep(void) {
+    fprintf(stderr, "\x7");
+    fflush(stderr);
+}
+
+/* ============================== Completion ================================ */
+
+/* Free a list of completion option populated by linenoiseAddCompletion(). */
+static void freeCompletions(linenoiseCompletions *lc) {
+    size_t i;
+    for (i = 0; i < lc->len; i++)
+        free(lc->cvec[i]);
+    if (lc->cvec != NULL)
+        free(lc->cvec);
+}
+
+/* This is an helper function for linenoiseEdit() and is called when the
+ * user types the <tab> key in order to complete the string currently in the
+ * input.
+ *
+ * The state of the editing is encapsulated into the pointed linenoiseState
+ * structure as described in the structure definition. */
+static int completeLine(struct linenoiseState *ls) {
+    linenoiseCompletions lc = {0, 0, NULL};
+    int nread, nwritten, hint_len, hint_line_count, char_count;
+    char c = 0, *common, *hint;
+    struct winsize w;
+
+    /* Hint is only the string after the last space */
+    hint = strrchr(ls->buf, ' ');
+    if (!hint) {
+        hint = ls->buf;
+    } else {
+        ++hint;
+    }
+
+    completionCallback(ls->buf, hint, &lc);
+    if (lc.len == 0) {
+        linenoiseBeep();
+    } else {
+        unsigned int i, j;
+
+        /* Learn the longest common part */
+        common = strdup(lc.cvec[0]);
+        for (i = 1; i < lc.len; ++i) {
+            for (j = 0; j < strlen(lc.cvec[i]); ++j) {
+                if (lc.cvec[i][j] != common[j]) {
+                    break;
+                }
+            }
+            common[j] = '\0';
+        }
+
+        /* Path completions have a different hint */
+        if (lc.path && strrchr(hint, '/')) {
+            hint = strrchr(hint, '/');
+            ++hint;
+        }
+
+        /* Show completion */
+        if ((lc.len == 1) && (common[strlen(common) - 1] != '/')) {
+            nwritten = snprintf(hint, ls->buflen - (hint - ls->buf), "%s ", common);
+        } else {
+            nwritten = snprintf(hint, ls->buflen - (hint - ls->buf), "%s", common);
+        }
+        free(common);
+        ls->len = ls->pos = (hint - ls->buf) + nwritten;
+        linenoiseRefreshLine();
+
+        /* A single hint */
+        if (lc.len == 1) {
+            freeCompletions(&lc);
+            return 0;
+        }
+
+        /* Read a char */
+        nread = read(ls->ifd,&c,1);
+        if (nread <= 0) {
+            freeCompletions(&lc);
+            return -1;
+        }
+
+        /* Not a tab */
+        if (c != 9) {
+            freeCompletions(&lc);
+            return c;
+        }
+
+        /* Learn terminal window size */
+        ioctl(ls->ifd, TIOCGWINSZ, &w);
+
+        /* Learn the longest hint */
+        hint_len = strlen(lc.cvec[0]);
+        for (i = 1; i < lc.len; ++i) {
+            if (strlen(lc.cvec[i]) > (unsigned)hint_len) {
+                hint_len = strlen(lc.cvec[i]);
+            }
+        }
+
+        /* Learn the number of hints that fit a line */
+        hint_line_count = 0;
+        while (1) {
+            char_count = 0;
+            if (hint_line_count) {
+                char_count += hint_line_count * (hint_len + 2);
+            }
+            char_count += hint_len;
+
+            /* Too much */
+            if (char_count > w.ws_col) {
+                break;
+            }
+
+            /* Still fits */
+            ++hint_line_count;
+        }
+
+        /* No hint fits, too bad */
+        if (!hint_line_count) {
+            freeCompletions(&lc);
+            return c;
+        }
+
+        while (c == 9) {
+            /* Second tab */
+            linenoiseDisableRawMode(ls->ifd);
+            printf("\n");
+            for (i = 0; i < lc.len; ++i) {
+                printf("%-*s", hint_len, lc.cvec[i]);
+                /* Line full or last hint */
+                if (((i + 1) % hint_line_count == 0) || (i == lc.len - 1)) {
+                    printf("\n");
+                } else {
+                    printf("  ");
+                }
+            }
+            linenoiseEnableRawMode(ls->ifd);
+            linenoiseRefreshLine();
+
+            /* Read a char */
+            nread = read(ls->ifd,&c,1);
+            if (nread <= 0) {
+                freeCompletions(&lc);
+                return -1;
+            }
+        }
+    }
+
+    freeCompletions(&lc);
+    return c; /* Return last read character */
+}
+
+/* Register a callback function to be called for tab-completion. */
+void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {
+    completionCallback = fn;
+}
+
+/* This function can be called in user completion callback to fill
+ * path completion for them. hint parameter is actually the whole path
+ * and buf is unused, but included to match the completion callback prototype. */
+void linenoisePathCompletion(const char *buf, const char *hint, linenoiseCompletions *lc) {
+    const char *ptr;
+    char *full_path, *hint_ptr, match[FILENAME_MAX + 2];
+    DIR *dir;
+    struct dirent *ent;
+    struct stat st;
+
+    (void)buf;
+
+    lc->path = 1;
+
+    ptr = strrchr(hint, '/');
+
+    /* new relative path */
+    if (ptr == NULL) {
+        full_path = malloc(2 + FILENAME_MAX + 1);
+        strcpy(full_path, "./");
+
+        ptr = hint;
+    } else {
+        full_path = malloc((int)(ptr - hint) + FILENAME_MAX + 1);
+        ++ptr;
+        sprintf(full_path, "%.*s", (int)(ptr - hint), hint);
+    }
+    hint_ptr = full_path + strlen(full_path);
+
+    dir = opendir(full_path);
+    if (dir == NULL) {
+        free(full_path);
+        return;
+    }
+
+    while ((ent = readdir(dir))) {
+        if (ent->d_name[0] == '.') {
+            continue;
+        }
+
+        if (!strncmp(ptr, ent->d_name, strlen(ptr))) {
+            /* is it a directory? */
+            strcpy(hint_ptr, ent->d_name);
+            if (stat(full_path, &st)) {
+                /* skip this item */
+                continue;
+            }
+
+            strcpy(match, ent->d_name);
+            if (S_ISDIR(st.st_mode)) {
+                strcat(match, "/");
+            }
+
+            linenoiseAddCompletion(lc, match);
+        }
+    }
+
+    free(full_path);
+    closedir(dir);
+}
+
+/* This function is used by the callback function registered by the user
+ * in order to add completion options given the input string when the
+ * user typed <tab>. See the example.c source code for a very easy to
+ * understand example. */
+void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {
+    size_t len = strlen(str);
+    char *copy, **cvec;
+
+    copy = malloc(len+1);
+    if (copy == NULL) return;
+    memcpy(copy,str,len+1);
+    cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1));
+    if (cvec == NULL) {
+        free(copy);
+        return;
+    }
+    lc->cvec = cvec;
+    lc->cvec[lc->len++] = copy;
+}
+
+/* =========================== Line editing ================================= */
+
+/* We define a very simple "append buffer" structure, that is an heap
+ * allocated string where we can append to. This is useful in order to
+ * write all the escape sequences in a buffer and flush them to the standard
+ * output in a single call, to avoid flickering effects. */
+struct abuf {
+    char *b;
+    int len;
+};
+
+static void abInit(struct abuf *ab) {
+    ab->b = NULL;
+    ab->len = 0;
+}
+
+static void abAppend(struct abuf *ab, const char *s, int len) {
+    char *new = realloc(ab->b,ab->len+len);
+
+    if (new == NULL) return;
+    memcpy(new+ab->len,s,len);
+    ab->b = new;
+    ab->len += len;
+}
+
+static void abFree(struct abuf *ab) {
+    free(ab->b);
+}
+
+/* Single line low level line refresh.
+ *
+ * Rewrite the currently edited line accordingly to the buffer content,
+ * cursor position, and number of columns of the terminal. */
+static void refreshSingleLine(struct linenoiseState *l) {
+    char seq[64];
+    size_t plen = strlen(l->prompt);
+    int fd = l->ofd;
+    char *buf = l->buf;
+    size_t len = l->len;
+    size_t pos = l->pos;
+    struct abuf ab;
+
+    while((plen+pos) >= l->cols) {
+        buf++;
+        len--;
+        pos--;
+    }
+    while (plen+len > l->cols) {
+        len--;
+    }
+
+    abInit(&ab);
+    /* Cursor to left edge */
+    snprintf(seq,64,"\r");
+    abAppend(&ab,seq,strlen(seq));
+    /* Write the prompt and the current buffer content */
+    abAppend(&ab,l->prompt,strlen(l->prompt));
+    abAppend(&ab,buf,len);
+    /* Erase to right */
+    snprintf(seq,64,"\x1b[0K");
+    abAppend(&ab,seq,strlen(seq));
+    /* Move cursor to original position. */
+    snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen));
+    abAppend(&ab,seq,strlen(seq));
+    if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
+    abFree(&ab);
+}
+
+/* Multi line low level line refresh.
+ *
+ * Rewrite the currently edited line accordingly to the buffer content,
+ * cursor position, and number of columns of the terminal. */
+static void refreshMultiLine(struct linenoiseState *l) {
+    char seq[64];
+    int plen = strlen(l->prompt);
+    int rows = (plen+l->len+l->cols-1)/l->cols; /* rows used by current buf. */
+    int rpos = (plen+l->oldpos+l->cols)/l->cols; /* cursor relative row. */
+    int rpos2; /* rpos after refresh. */
+    int col; /* colum position, zero-based. */
+    int old_rows = l->maxrows;
+    int fd = l->ofd, j;
+    struct abuf ab;
+
+    /* Update maxrows if needed. */
+    if (rows > (int)l->maxrows) l->maxrows = rows;
+
+    /* First step: clear all the lines used before. To do so start by
+     * going to the last row. */
+    abInit(&ab);
+    if (old_rows-rpos > 0) {
+        lndebug("go down %d", old_rows-rpos);
+        snprintf(seq,64,"\x1b[%dB", old_rows-rpos);
+        abAppend(&ab,seq,strlen(seq));
+    }
+
+    /* Now for every row clear it, go up. */
+    for (j = 0; j < old_rows-1; j++) {
+        lndebug("clear+up");
+        snprintf(seq,64,"\r\x1b[0K\x1b[1A");
+        abAppend(&ab,seq,strlen(seq));
+    }
+
+    /* Clean the top line. */
+    lndebug("clear");
+    snprintf(seq,64,"\r\x1b[0K");
+    abAppend(&ab,seq,strlen(seq));
+
+    /* Write the prompt and the current buffer content */
+    abAppend(&ab,l->prompt,strlen(l->prompt));
+    abAppend(&ab,l->buf,l->len);
+
+    /* If we are at the very end of the screen with our prompt, we need to
+     * emit a newline and move the prompt to the first column. */
+    if (l->pos &&
+        l->pos == l->len &&
+        (l->pos+plen) % l->cols == 0)
+    {
+        lndebug("<newline>");
+        abAppend(&ab,"\n",1);
+        snprintf(seq,64,"\r");
+        abAppend(&ab,seq,strlen(seq));
+        rows++;
+        if (rows > (int)l->maxrows) l->maxrows = rows;
+    }
+
+    /* Move cursor to right position. */
+    rpos2 = (plen+l->pos+l->cols)/l->cols; /* current cursor relative row. */
+    lndebug("rpos2 %d", rpos2);
+
+    /* Go up till we reach the expected positon. */
+    if (rows-rpos2 > 0) {
+        lndebug("go-up %d", rows-rpos2);
+        snprintf(seq,64,"\x1b[%dA", rows-rpos2);
+        abAppend(&ab,seq,strlen(seq));
+    }
+
+    /* Set column. */
+    col = (plen+(int)l->pos) % (int)l->cols;
+    lndebug("set col %d", 1+col);
+    if (col)
+        snprintf(seq,64,"\r\x1b[%dC", col);
+    else
+        snprintf(seq,64,"\r");
+    abAppend(&ab,seq,strlen(seq));
+
+    lndebug("\n");
+    l->oldpos = l->pos;
+
+    if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
+    abFree(&ab);
+}
+
+/* Calls the two low level functions refreshSingleLine() or
+ * refreshMultiLine() according to the selected mode. */
+void linenoiseRefreshLine(void) {
+    if (mlmode)
+        refreshMultiLine(&ls);
+    else
+        refreshSingleLine(&ls);
+}
+
+/* Insert the character 'c' at cursor current position.
+ *
+ * On error writing to the terminal -1 is returned, otherwise 0. */
+int linenoiseEditInsert(struct linenoiseState *l, char c) {
+    if (l->len < l->buflen) {
+        if (l->len == l->pos) {
+            l->buf[l->pos] = c;
+            l->pos++;
+            l->len++;
+            l->buf[l->len] = '\0';
+            if ((!mlmode && l->plen+l->len < l->cols) /* || mlmode */) {
+                /* Avoid a full update of the line in the
+                 * trivial case. */
+                if (write(l->ofd,&c,1) == -1) return -1;
+            } else {
+                linenoiseRefreshLine();
+            }
+        } else {
+            memmove(l->buf+l->pos+1,l->buf+l->pos,l->len-l->pos);
+            l->buf[l->pos] = c;
+            l->len++;
+            l->pos++;
+            l->buf[l->len] = '\0';
+            linenoiseRefreshLine();
+        }
+    }
+    return 0;
+}
+
+/* Move cursor on the left. */
+void linenoiseEditMoveLeft(struct linenoiseState *l) {
+    if (l->pos > 0) {
+        l->pos--;
+        linenoiseRefreshLine();
+    }
+}
+
+/* Move cursor on the right. */
+void linenoiseEditMoveRight(struct linenoiseState *l) {
+    if (l->pos != l->len) {
+        l->pos++;
+        linenoiseRefreshLine();
+    }
+}
+
+/* Move cursor to the start of the line. */
+void linenoiseEditMoveHome(struct linenoiseState *l) {
+    if (l->pos != 0) {
+        l->pos = 0;
+        linenoiseRefreshLine();
+    }
+}
+
+/* Move cursor to the end of the line. */
+void linenoiseEditMoveEnd(struct linenoiseState *l) {
+    if (l->pos != l->len) {
+        l->pos = l->len;
+        linenoiseRefreshLine();
+    }
+}
+
+/* Substitute the currently edited line with the next or previous history
+ * entry as specified by 'dir'. */
+#define LINENOISE_HISTORY_NEXT 0
+#define LINENOISE_HISTORY_PREV 1
+void linenoiseEditHistoryNext(struct linenoiseState *l, int dir) {
+    if (history_len > 1) {
+        /* Update the current history entry before to
+         * overwrite it with the next one. */
+        free(history[history_len - 1 - l->history_index]);
+        history[history_len - 1 - l->history_index] = strdup(l->buf);
+        /* Show the new entry */
+        l->history_index += (dir == LINENOISE_HISTORY_PREV) ? 1 : -1;
+        if (l->history_index < 0) {
+            l->history_index = 0;
+            return;
+        } else if (l->history_index >= history_len) {
+            l->history_index = history_len-1;
+            return;
+        }
+        strncpy(l->buf,history[history_len - 1 - l->history_index],l->buflen);
+        l->buf[l->buflen-1] = '\0';
+        l->len = l->pos = strlen(l->buf);
+        linenoiseRefreshLine();
+    }
+}
+
+/* Delete the character at the right of the cursor without altering the cursor
+ * position. Basically this is what happens with the "Delete" keyboard key. */
+void linenoiseEditDelete(struct linenoiseState *l) {
+    if (l->len > 0 && l->pos < l->len) {
+        memmove(l->buf+l->pos,l->buf+l->pos+1,l->len-l->pos-1);
+        l->len--;
+        l->buf[l->len] = '\0';
+        linenoiseRefreshLine();
+    }
+}
+
+/* Backspace implementation. */
+void linenoiseEditBackspace(struct linenoiseState *l) {
+    if (l->pos > 0 && l->len > 0) {
+        memmove(l->buf+l->pos-1,l->buf+l->pos,l->len-l->pos);
+        l->pos--;
+        l->len--;
+        l->buf[l->len] = '\0';
+        linenoiseRefreshLine();
+    }
+}
+
+/* Delete the previosu word, maintaining the cursor at the start of the
+ * current word. */
+void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
+    size_t old_pos = l->pos;
+    size_t diff;
+
+    while (l->pos > 0 && l->buf[l->pos-1] == ' ')
+        l->pos--;
+    while (l->pos > 0 && l->buf[l->pos-1] != ' ')
+        l->pos--;
+    diff = old_pos - l->pos;
+    memmove(l->buf+l->pos,l->buf+old_pos,l->len-old_pos+1);
+    l->len -= diff;
+    linenoiseRefreshLine();
+}
+
+/* This function is the core of the line editing capability of linenoise.
+ * It expects 'fd' to be already in "raw mode" so that every key pressed
+ * will be returned ASAP to read().
+ *
+ * The resulting string is put into 'buf' when the user type enter, or
+ * when ctrl+d is typed.
+ *
+ * The function returns the length of the current buffer. */
+static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt)
+{
+    /* Populate the linenoise state that we pass to functions implementing
+     * specific editing functionalities. */
+    ls.ifd = stdin_fd;
+    ls.ofd = stdout_fd;
+    ls.buf = buf;
+    ls.buflen = buflen;
+    ls.prompt = prompt;
+    ls.plen = strlen(prompt);
+    ls.oldpos = ls.pos = 0;
+    ls.len = 0;
+    ls.cols = getColumns(stdin_fd, stdout_fd);
+    ls.maxrows = 0;
+    ls.history_index = 0;
+
+    /* Buffer starts empty. */
+    ls.buf[0] = '\0';
+    ls.buflen--; /* Make sure there is always space for the nulterm */
+
+    /* The latest history entry is always our current buffer, that
+     * initially is just an empty string. */
+    linenoiseHistoryAdd("");
+
+    if (write(ls.ofd,prompt,ls.plen) == -1) return -1;
+    while(1) {
+        int c = 0, nread;
+        char seq[3];
+
+        nread = read(ls.ifd,&c,1);
+        if (nread <= 0) return ls.len;
+
+        /* Only autocomplete when the callback is set. It returns < 0 when
+         * there was an error reading from fd. Otherwise it will return the
+         * character that should be handled next. */
+        if (c == 9 && completionCallback != NULL) {
+            c = completeLine(&ls);
+            /* Return on errors */
+            if (c < 0) return ls.len;
+            /* Read next character when 0 */
+            if (c == 0) continue;
+        }
+
+        switch(c) {
+        case ENTER:    /* enter */
+            history_len--;
+            free(history[history_len]);
+            if (mlmode) linenoiseEditMoveEnd(&ls);
+            return (int)ls.len;
+        case CTRL_C:     /* ctrl-c */
+            errno = EAGAIN;
+            return -1;
+        case BACKSPACE:   /* backspace */
+        case 8:     /* ctrl-h */
+            linenoiseEditBackspace(&ls);
+            break;
+        case CTRL_D:     /* ctrl-d, remove char at right of cursor, or if the
+                            line is empty, act as end-of-file. */
+            if (ls.len > 0) {
+                linenoiseEditDelete(&ls);
+            } else {
+                history_len--;
+                free(history[history_len]);
+                return -1;
+            }
+            break;
+        case CTRL_T:    /* ctrl-t, swaps current character with previous. */
+            if (ls.pos > 0 && ls.pos < ls.len) {
+                int aux = buf[ls.pos-1];
+                buf[ls.pos-1] = buf[ls.pos];
+                buf[ls.pos] = aux;
+                if (ls.pos != ls.len-1) ls.pos++;
+                linenoiseRefreshLine();
+            }
+            break;
+        case CTRL_B:     /* ctrl-b */
+            linenoiseEditMoveLeft(&ls);
+            break;
+        case CTRL_F:     /* ctrl-f */
+            linenoiseEditMoveRight(&ls);
+            break;
+        case CTRL_P:    /* ctrl-p */
+            linenoiseEditHistoryNext(&ls, LINENOISE_HISTORY_PREV);
+            break;
+        case CTRL_N:    /* ctrl-n */
+            linenoiseEditHistoryNext(&ls, LINENOISE_HISTORY_NEXT);
+            break;
+        case ESC:    /* escape sequence */
+            /* Read the next two bytes representing the escape sequence.
+             * Use two calls to handle slow terminals returning the two
+             * chars at different times. */
+            if (read(ls.ifd,seq,1) == -1) break;
+            if (read(ls.ifd,seq+1,1) == -1) break;
+
+            /* ESC [ sequences. */
+            if (seq[0] == '[') {
+                if (seq[1] >= '0' && seq[1] <= '9') {
+                    /* Extended escape, read additional byte. */
+                    if (read(ls.ifd,seq+2,1) == -1) break;
+                    if (seq[2] == '~') {
+                        switch(seq[1]) {
+                        case '3': /* Delete key. */
+                            linenoiseEditDelete(&ls);
+                            break;
+                        }
+                    }
+                } else {
+                    switch(seq[1]) {
+                    case 'A': /* Up */
+                        linenoiseEditHistoryNext(&ls, LINENOISE_HISTORY_PREV);
+                        break;
+                    case 'B': /* Down */
+                        linenoiseEditHistoryNext(&ls, LINENOISE_HISTORY_NEXT);
+                        break;
+                    case 'C': /* Right */
+                        linenoiseEditMoveRight(&ls);
+                        break;
+                    case 'D': /* Left */
+                        linenoiseEditMoveLeft(&ls);
+                        break;
+                    case 'H': /* Home */
+                        linenoiseEditMoveHome(&ls);
+                        break;
+                    case 'F': /* End*/
+                        linenoiseEditMoveEnd(&ls);
+                        break;
+                    }
+                }
+            }
+
+            /* ESC O sequences. */
+            else if (seq[0] == 'O') {
+                switch(seq[1]) {
+                case 'H': /* Home */
+                    linenoiseEditMoveHome(&ls);
+                    break;
+                case 'F': /* End*/
+                    linenoiseEditMoveEnd(&ls);
+                    break;
+                }
+            }
+            break;
+        default:
+            if (linenoiseEditInsert(&ls,c)) return -1;
+            break;
+        case CTRL_U: /* Ctrl+u, delete the whole line. */
+            buf[0] = '\0';
+            ls.pos = ls.len = 0;
+            linenoiseRefreshLine();
+            break;
+        case CTRL_K: /* Ctrl+k, delete from current to end of line. */
+            buf[ls.pos] = '\0';
+            ls.len = ls.pos;
+            linenoiseRefreshLine();
+            break;
+        case CTRL_A: /* Ctrl+a, go to the start of the line */
+            linenoiseEditMoveHome(&ls);
+            break;
+        case CTRL_E: /* ctrl+e, go to the end of the line */
+            linenoiseEditMoveEnd(&ls);
+            break;
+        case CTRL_L: /* ctrl+l, clear screen */
+            linenoiseClearScreen();
+            linenoiseRefreshLine();
+            break;
+        case CTRL_W: /* ctrl+w, delete previous word */
+            linenoiseEditDeletePrevWord(&ls);
+            break;
+        }
+    }
+    return ls.len;
+}
+
+/* This special mode is used by linenoise in order to print scan codes
+ * on screen for debugging / development purposes. It is implemented
+ * by the linenoise_example program using the --keycodes option. */
+void linenoisePrintKeyCodes(void) {
+    char quit[4];
+
+    printf("Linenoise key codes debugging mode.\n"
+            "Press keys to see scan codes. Type 'quit' at any time to exit.\n");
+    if (linenoiseEnableRawMode(STDIN_FILENO) == -1) return;
+    memset(quit,' ',4);
+    while(1) {
+        char c;
+        int nread;
+
+        nread = read(STDIN_FILENO,&c,1);
+        if (nread <= 0) continue;
+        memmove(quit,quit+1,sizeof(quit)-1); /* shift string to left. */
+        quit[sizeof(quit)-1] = c; /* Insert current char on the right. */
+        if (memcmp(quit,"quit",sizeof(quit)) == 0) break;
+
+        printf("'%c' %02x (%d) (type quit to exit)\n",
+            isprint(c) ? c : '?', (int)c, (int)c);
+        printf("\r"); /* Go left edge manually, we are in raw mode. */
+        fflush(stdout);
+    }
+    linenoiseDisableRawMode(STDIN_FILENO);
+}
+
+/* This function calls the line editing function linenoiseEdit() using
+ * the STDIN file descriptor set in raw mode. */
+static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
+    int count;
+
+    if (buflen == 0) {
+        errno = EINVAL;
+        return -1;
+    }
+    if (!isatty(STDIN_FILENO)) {
+        /* Not a tty: read from file / pipe. */
+        if (fgets(buf, buflen, stdin) == NULL) return -1;
+        count = strlen(buf);
+        if (count && buf[count-1] == '\n') {
+            count--;
+            buf[count] = '\0';
+        }
+    } else {
+        /* Interactive editing. */
+        if (linenoiseEnableRawMode(STDIN_FILENO) == -1) return -1;
+        count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt);
+        linenoiseDisableRawMode(STDIN_FILENO);
+        printf("\n");
+    }
+    return count;
+}
+
+/* The high level function that is the main API of the linenoise library.
+ * This function checks if the terminal has basic capabilities, just checking
+ * for a blacklist of stupid terminals, and later either calls the line
+ * editing function or uses dummy fgets() so that you will be able to type
+ * something even in the most desperate of the conditions. */
+char *linenoise(const char *prompt) {
+    char buf[LINENOISE_MAX_LINE];
+    int count;
+
+    if (isUnsupportedTerm()) {
+        size_t len;
+
+        printf("%s",prompt);
+        fflush(stdout);
+        if (fgets(buf,LINENOISE_MAX_LINE,stdin) == NULL) return NULL;
+        len = strlen(buf);
+        while(len && (buf[len-1] == '\n' || buf[len-1] == '\r')) {
+            len--;
+            buf[len] = '\0';
+        }
+        return strdup(buf);
+    } else {
+        count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt);
+        if (count == -1) return NULL;
+        return strdup(buf);
+    }
+}
+
+/* ================================ History ================================= */
+
+/* Free the history, but does not reset it. Only used when we have to
+ * exit() to avoid memory leaks are reported by valgrind & co. */
+static void freeHistory(void) {
+    if (history) {
+        int j;
+
+        for (j = 0; j < history_len; j++)
+            free(history[j]);
+        free(history);
+    }
+}
+
+/* At exit we'll try to fix the terminal to the initial conditions. */
+static void linenoiseAtExit(void) {
+    linenoiseDisableRawMode(STDIN_FILENO);
+    freeHistory();
+}
+
+/* This is the API call to add a new entry in the linenoise history.
+ * It uses a fixed array of char pointers that are shifted (memmoved)
+ * when the history max length is reached in order to remove the older
+ * entry and make room for the new one, so it is not exactly suitable for huge
+ * histories, but will work well for a few hundred of entries.
+ *
+ * Using a circular buffer is smarter, but a bit more complex to handle. */
+int linenoiseHistoryAdd(const char *line) {
+    char *linecopy;
+
+    if (history_max_len == 0) return 0;
+
+    /* Initialization on first call. */
+    if (history == NULL) {
+        history = malloc(sizeof(char*)*history_max_len);
+        if (history == NULL) return 0;
+        memset(history,0,(sizeof(char*)*history_max_len));
+    }
+
+    /* Don't add duplicated lines. */
+    if (history_len && !strcmp(history[history_len-1], line)) return 0;
+
+    /* Add an heap allocated copy of the line in the history.
+     * If we reached the max length, remove the older line. */
+    linecopy = strdup(line);
+    if (!linecopy) return 0;
+    if (history_len == history_max_len) {
+        free(history[0]);
+        memmove(history,history+1,sizeof(char*)*(history_max_len-1));
+        history_len--;
+    }
+    history[history_len] = linecopy;
+    history_len++;
+    return 1;
+}
+
+/* Set the maximum length for the history. This function can be called even
+ * if there is already some history, the function will make sure to retain
+ * just the latest 'len' elements if the new history length value is smaller
+ * than the amount of items already inside the history. */
+int linenoiseHistorySetMaxLen(int len) {
+    char **new;
+
+    if (len < 1) return 0;
+    if (history) {
+        int tocopy = history_len;
+
+        new = malloc(sizeof(char*)*len);
+        if (new == NULL) return 0;
+
+        /* If we can't copy everything, free the elements we'll not use. */
+        if (len < tocopy) {
+            int j;
+
+            for (j = 0; j < tocopy-len; j++) free(history[j]);
+            tocopy = len;
+        }
+        memset(new,0,sizeof(char*)*len);
+        memcpy(new,history+(history_len-tocopy), sizeof(char*)*tocopy);
+        free(history);
+        history = new;
+    }
+    history_max_len = len;
+    if (history_len > history_max_len)
+        history_len = history_max_len;
+    return 1;
+}
+
+/* Save the history in the specified file. On success 0 is returned
+ * otherwise -1 is returned. */
+int linenoiseHistorySave(const char *filename) {
+    FILE *fp = fopen(filename,"w");
+    int j;
+
+    if (fp == NULL) return -1;
+    for (j = 0; j < history_len; j++)
+        fprintf(fp,"%s\n",history[j]);
+    fclose(fp);
+    return 0;
+}
+
+/* Load the history from the specified file. If the file does not exist
+ * zero is returned and no operation is performed.
+ *
+ * If the file exists and the operation succeeded 0 is returned, otherwise
+ * on error -1 is returned. */
+int linenoiseHistoryLoad(const char *filename) {
+    FILE *fp = fopen(filename,"r");
+    char buf[LINENOISE_MAX_LINE];
+
+    if (fp == NULL) return -1;
+
+    while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) {
+        char *p;
+
+        p = strchr(buf,'\r');
+        if (!p) p = strchr(buf,'\n');
+        if (p) *p = '\0';
+        linenoiseHistoryAdd(buf);
+    }
+    fclose(fp);
+    return 0;
+}
diff --git a/tools/lint/linenoise/linenoise.h b/tools/lint/linenoise/linenoise.h
new file mode 100644
index 0000000..c708990
--- /dev/null
+++ b/tools/lint/linenoise/linenoise.h
@@ -0,0 +1,92 @@
+/* linenoise.h -- VERSION 1.0
+ *
+ * Guerrilla line editing library against the idea that a line editing lib
+ * needs to be 20,000 lines of C code.
+ *
+ * See linenoise.c for more information.
+ *
+ * ------------------------------------------------------------------------
+ *
+ * Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>
+ * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  *  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *  *  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __LINENOISE_H
+#define __LINENOISE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct linenoiseState {
+    int ifd;            /* Terminal stdin file descriptor. */
+    int ofd;            /* Terminal stdout file descriptor. */
+    char *buf;          /* Edited line buffer. */
+    size_t buflen;      /* Edited line buffer size. */
+    const char *prompt; /* Prompt to display. */
+    size_t plen;        /* Prompt length. */
+    size_t pos;         /* Current cursor position. */
+    size_t oldpos;      /* Previous refresh cursor position. */
+    size_t len;         /* Current edited line length. */
+    size_t cols;        /* Number of columns in terminal. */
+    size_t maxrows;     /* Maximum num of rows used so far (multiline mode) */
+    int rawmode;
+    int history_index;  /* The history index we are currently editing. */
+};
+
+extern struct linenoiseState ls;
+
+typedef struct linenoiseCompletions {
+    int path;
+    size_t len;
+    char **cvec;
+} linenoiseCompletions;
+
+typedef void(linenoiseCompletionCallback)(const char *, const char *, linenoiseCompletions *);
+void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
+void linenoiseAddCompletion(linenoiseCompletions *, const char *);
+
+char *linenoise(const char *prompt);
+int linenoiseHistoryAdd(const char *line);
+int linenoiseHistorySetMaxLen(int len);
+int linenoiseHistorySave(const char *filename);
+int linenoiseHistoryLoad(const char *filename);
+void linenoiseClearScreen(void);
+void linenoiseSetMultiLine(int ml);
+void linenoisePrintKeyCodes(void);
+
+void linenoisePathCompletion(const char *, const char *, linenoiseCompletions *);
+void linenoiseRefreshLine(void);
+int linenoiseEnableRawMode(int fd);
+void linenoiseDisableRawMode(int fd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LINENOISE_H */
diff --git a/tools/lint/main.c b/tools/lint/main.c
new file mode 100644
index 0000000..6b257da
--- /dev/null
+++ b/tools/lint/main.c
@@ -0,0 +1,111 @@
+/**
+ * @file main.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief libyang's yanglint tool
+ *
+ * Copyright (c) 2015-2017 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "commands.h"
+#include "configuration.h"
+#include "completion.h"
+#include "./linenoise/linenoise.h"
+#include "libyang.h"
+
+int done;
+struct ly_ctx *ctx = NULL;
+
+/* main_ni.c */
+int main_ni(int argc, char *argv[]);
+
+int
+main(int argc, char* argv[])
+{
+    char *cmd, *cmdline, *cmdstart;
+    int i, j;
+
+    if (argc > 1) {
+        /* run in non-interactive mode */
+        return main_ni(argc, argv);
+    }
+
+    /* continue in interactive mode */
+    linenoiseSetCompletionCallback(complete_cmd);
+    load_config();
+
+    if (ly_ctx_new(NULL, 0, &ctx)) {
+        fprintf(stderr, "Failed to create context.\n");
+        return 1;
+    }
+
+    while (!done) {
+        /* get the command from user */
+        cmdline = linenoise(PROMPT);
+
+        /* EOF -> exit */
+        if (cmdline == NULL) {
+            done = 1;
+            cmdline = strdup("quit");
+        }
+
+        /* empty line -> wait for another command */
+        if (*cmdline == '\0') {
+            free(cmdline);
+            continue;
+        }
+
+        /* isolate the command word. */
+        for (i = 0; cmdline[i] && (cmdline[i] == ' '); i++);
+        cmdstart = cmdline + i;
+        for (j = 0; cmdline[i] && (cmdline[i] != ' '); i++, j++);
+        cmd = strndup(cmdstart, j);
+
+        /* parse the command line */
+        for (i = 0; commands[i].name; i++) {
+            if (strcmp(cmd, commands[i].name) == 0) {
+                break;
+            }
+        }
+
+        /* execute the command if any valid specified */
+        if (commands[i].name) {
+            /* display help */
+            if ((strchr(cmdstart, ' ') != NULL) && ((strncmp(strchr(cmdstart, ' ')+1, "-h", 2) == 0)
+                    || (strncmp(strchr(cmdstart, ' ')+1, "--help", 6) == 0))) {
+                if (commands[i].help_func != NULL) {
+                    commands[i].help_func();
+                } else {
+                    printf("%s\n", commands[i].helpstring);
+                }
+            } else {
+                commands[i].func((const char *)cmdstart);
+            }
+        } else {
+            /* if unknown command specified, tell it to user */
+            fprintf(stderr, "%s: no such command, type 'help' for more information.\n", cmd);
+        }
+        linenoiseHistoryAdd(cmdline);
+
+        free(cmd);
+        free(cmdline);
+    }
+
+    store_config();
+    ly_ctx_destroy(ctx, NULL);
+
+    return 0;
+}
diff --git a/tools/lint/main_ni.c b/tools/lint/main_ni.c
new file mode 100644
index 0000000..892d242
--- /dev/null
+++ b/tools/lint/main_ni.c
@@ -0,0 +1,1099 @@
+/**
+ * @file main_ni.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief libyang's yanglint tool - noninteractive code
+ *
+ * Copyright (c) 2015-2018 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <errno.h>
+#include <libgen.h>
+#include <sys/stat.h>
+#include <sys/times.h>
+#include <sys/types.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "commands.h"
+#include "libyang.h"
+
+volatile uint8_t verbose = 0;
+
+#if 0
+/* from commands.c */
+int print_list(FILE *out, struct ly_ctx *ctx, LYD_FORMAT outformat);
+#endif
+
+void
+help(int shortout)
+{
+    fprintf(stdout, "Usage:\n");
+    fprintf(stdout, "    yanglint [options] [-f { yang | yin | tree | tree-rfc | jsons}] <file>...\n");
+    fprintf(stdout, "        Validates the YANG module in <file>, and all its dependencies.\n\n");
+    fprintf(stdout, "    yanglint [options] [-f { xml | json }] <schema>... <file>...\n");
+    fprintf(stdout, "        Validates the YANG modeled data in <file> according to the <schema>.\n\n");
+    fprintf(stdout, "    yanglint\n");
+    fprintf(stdout, "        Starts interactive mode with more features.\n\n");
+
+    if (shortout) {
+        return;
+    }
+    fprintf(stdout, "Options:\n"
+        "  -h, --help            Show this help message and exit.\n"
+        "  -v, --version         Show version number and exit.\n"
+        "  -V, --verbose         Show verbose messages, can be used multiple times to\n"
+        "                        increase verbosity.\n"
+#ifndef NDEBUG
+        "  -G GROUPS, --debug=GROUPS\n"
+        "                        Enable printing of specific debugging message group\n"
+        "                        (nothing will be printed unless verbosity is set to debug):\n"
+        "                        <group>[,<group>]* (dict, yang, yin, xpath, diff)\n\n"
+#endif
+        "  -p PATH, --path=PATH  Search path for schema (YANG/YIN) modules. The option can be used multiple times.\n"
+        "                        Current working directory and path of the module being added is used implicitly.\n\n"
+        "  -D, --disable-searchdir\n"
+        "                        Do not implicitly search in CWD for schema modules. If specified a second time,\n"
+        "                        do not even search the module directory (all modules must be explicitly specified).\n\n"
+        "  -s, --strict          Strict data parsing (do not skip unknown data),\n"
+        "                        has no effect for schemas.\n\n"
+        "  -m, --merge           Merge input data files into a single tree and validate at once,\n"
+        "                        has no effect for the auto, rpc, rpcreply and notif TYPEs.\n\n"
+        "  -f FORMAT, --format=FORMAT\n"
+        "                        Convert to FORMAT. Supported formats: \n"
+        "                        yang, yin, tree and jsons (JSON) for schemas,\n"
+        "                        xml, json for data.\n"
+        "  -a, --auto            Modify the xml output by adding envelopes for autodetection.\n\n"
+        "  -i, --allimplemented  Make all the imported modules implemented.\n\n"
+        "  -l, --list            Print info about the loaded schemas in ietf-yang-library format,\n"
+        "                        the -f option applies here to specify data encoding.\n"
+        "                        (i - imported module, I - implemented module)\n\n"
+        "  -o OUTFILE, --output=OUTFILE\n"
+        "                        Write the output to OUTFILE instead of stdout.\n\n"
+        "  -F FEATURES, --features=FEATURES\n"
+        "                        Features to support, default all.\n"
+        "                        <modname>:[<feature>,]*\n\n"
+        "  -d MODE, --default=MODE\n"
+        "                        Print data with default values, according to the MODE\n"
+        "                        (to print attributes, ietf-netconf-with-defaults model\n"
+        "                        must be loaded):\n"
+        "        all             - Add missing default nodes.\n"
+        "        all-tagged      - Add missing default nodes and mark all the default\n"
+        "                          nodes with the attribute.\n"
+        "        trim            - Remove all nodes with a default value.\n"
+        "        implicit-tagged - Add missing nodes and mark them with the attribute.\n\n"
+        "  -t TYPE, --type=TYPE\n"
+        "                        Specify data tree type in the input data file:\n"
+        "        auto            - Resolve data type (one of the following) automatically\n"
+        "                          (as pyang does) - applicable only on XML input data.\n"
+        "        data            - Complete datastore with status data (default type).\n"
+        "        config          - Configuration datastore (without status data).\n"
+        "        get             - Result of the NETCONF <get> operation.\n"
+        "        getconfig       - Result of the NETCONF <get-config> operation.\n"
+        "        edit            - Content of the NETCONF <edit-config> operation.\n"
+        "        rpc             - Content of the NETCONF <rpc> message, defined as YANG's rpc input statement.\n"
+        "        rpcreply        - Reply to the RPC. The input data <file>s are expected in pairs - each RPC reply\n"
+        "                          input data <file> must be followed by the origin RPC input data <file> for the reply.\n"
+        "                          The same rule of pairing applies also in case of 'auto' TYPE and input data file\n"
+        "                          containing RPC reply.\n"
+        "        notif           - Notification instance (content of the <notification> element without <eventTime>.\n\n"
+        "  -O FILE, --operational=FILE\n"
+        "                        - Optional parameter for 'rpc', 'rpcreply' and 'notif' TYPEs, the FILE contains running\n"
+        "                          configuration datastore and state data (operational datastore) referenced from\n"
+        "                          the RPC/Notification. The same data apply to all input data <file>s. Note that\n"
+        "                          the file is validated as 'data' TYPE. Special value '!' can be used as FILE argument\n"
+        "                          to ignore the external references.\n\n"
+        "  -y YANGLIB_PATH       - Path to a yang-library data describing the initial context.\n\n"
+        "Tree output specific options:\n"
+        "  --tree-help           - Print help on tree symbols and exit.\n"
+        "  --tree-print-groupings\n"
+        "                        Print top-level groupings in a separate section.\n"
+        "  --tree-print-uses     - Print uses nodes instead the resolved grouping nodes.\n"
+        "  --tree-no-leafref-target\n"
+        "                        Do not print target nodes of leafrefs.\n"
+        "  --tree-path=SCHEMA_PATH\n"
+        "                        Print only the specified subtree.\n"
+        "  --tree-line-length=LINE_LENGTH\n"
+        "                        Wrap lines if longer than the specified length (it is not a strict limit, longer lines\n"
+        "                        can often appear).\n"
+        "\n");
+}
+
+void
+tree_help(void)
+{
+    fprintf(stdout, "Each node is printed as:\n\n");
+    fprintf(stdout, "<status> <flags> <name> <opts> <type> <if-features>\n\n"
+                    "  <status> is one of:\n"
+                    "    + for current\n"
+                    "    x for deprecated\n"
+                    "    o for obsolete\n\n"
+                    "  <flags> is one of:\n"
+                    "    rw for configuration data\n"
+                    "    ro for status data\n"
+                    "    -x for RPCs\n"
+                    "    -n for Notification\n\n"
+                    "  <name> is the name of the node\n"
+                    "    (<name>) means that the node is a choice node\n"
+                    "    :(<name>) means that the node is a case node\n\n"
+                    "    if the node is augmented into the tree from another module,\n"
+                    "    it is printed with the module name as <module-name>:<name>.\n\n"
+                    "  <opts> is one of:\n"
+                    "    ? for an optional leaf or choice\n"
+                    "    ! for a presence container\n"
+                    "    * for a leaf-list or list\n"
+                    "    [<keys>] for a list's keys\n\n"
+                    "  <type> is the name of the type for leafs and leaf-lists\n"
+                    "    If there is a default value defined, it is printed within\n"
+                    "    angle brackets <default-value>.\n"
+                    "    If the type is a leafref, the type is printed as -> TARGET`\n\n"
+                    "  <if-features> is the list of features this node depends on,\n"
+                    "    printed within curly brackets and a question mark {...}?\n\n");
+}
+
+void
+version(void)
+{
+    fprintf(stdout, "yanglint %s\n", PROJECT_VERSION);
+}
+
+void
+libyang_verbclb(LY_LOG_LEVEL level, const char *msg, const char *path)
+{
+    char *levstr;
+
+    if (level <= verbose) {
+        switch(level) {
+        case LY_LLERR:
+            levstr = "err :";
+            break;
+        case LY_LLWRN:
+            levstr = "warn:";
+            break;
+        case LY_LLVRB:
+            levstr = "verb:";
+            break;
+        default:
+            levstr = "dbg :";
+            break;
+        }
+        if (path) {
+            fprintf(stderr, "%s %s (%s)\n", levstr, msg, path);
+        } else {
+            fprintf(stderr, "%s %s\n", levstr, msg);
+        }
+    }
+}
+
+/*
+ * return:
+ * 0 - error
+ * 1 - schema format
+ * 2 - data format
+ */
+static int
+get_fileformat(const char *filename, LYS_INFORMAT *schema/* TODO , LYD_FORMAT *data */)
+{
+    char *ptr;
+    LYS_INFORMAT informat_s;
+#if 0
+    LYD_FORMAT informat_d;
+#endif
+    /* get the file format */
+    if ((ptr = strrchr(filename, '.')) != NULL) {
+        ++ptr;
+        if (!strcmp(ptr, "yang")) {
+            informat_s = LYS_IN_YANG;
+#if 0
+            informat_d = 0;
+        } else if (!strcmp(ptr, "yin")) {
+            informat_s = LYS_IN_YIN;
+            informat_d = 0;
+        } else if (!strcmp(ptr, "xml")) {
+            informat_s = 0;
+            informat_d = LYD_XML;
+        } else if (!strcmp(ptr, "json")) {
+            informat_s = 0;
+            informat_d = LYD_JSON;
+#endif
+        } else {
+            fprintf(stderr, "yanglint error: input file in an unknown format \"%s\".\n", ptr);
+            return 0;
+        }
+    } else {
+        fprintf(stderr, "yanglint error: input file \"%s\" without file extension - unknown format.\n", filename);
+        return 0;
+    }
+#if 0
+    if (data) {
+        (*data) = informat_d;
+    }
+#endif
+    if (schema) {
+        (*schema) = informat_s;
+    }
+
+    if (informat_s) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+
+int
+main_ni(int argc, char* argv[])
+{
+    int ret = EXIT_FAILURE;
+    int opt, opt_index = 0, i, featsize = 0;
+    struct option options[] = {
+#if 0
+        {"auto",             no_argument,       NULL, 'a'},
+        {"default",          required_argument, NULL, 'd'},
+#endif
+        {"format",           required_argument, NULL, 'f'},
+        {"features",         required_argument, NULL, 'F'},
+#if 0
+        {"tree-print-groupings", no_argument,   NULL, 'g'},
+        {"tree-print-uses",  no_argument,       NULL, 'u'},
+        {"tree-no-leafref-target", no_argument, NULL, 'n'},
+        {"tree-path",        required_argument, NULL, 'P'},
+        {"tree-line-length", required_argument, NULL, 'L'},
+#endif
+        {"help",             no_argument,       NULL, 'h'},
+#if 0
+        {"tree-help",        no_argument,       NULL, 'H'},
+#endif
+        {"allimplemented",   no_argument,       NULL, 'i'},
+        {"disable-cwd-search", no_argument,     NULL, 'D'},
+        {"list",             no_argument,       NULL, 'l'},
+#if 0
+        {"merge",            no_argument,       NULL, 'm'},
+#endif
+        {"output",           required_argument, NULL, 'o'},
+        {"path",             required_argument, NULL, 'p'},
+#if 0
+        {"running",          required_argument, NULL, 'r'},
+        {"operational",      required_argument, NULL, 'O'},
+        {"strict",           no_argument,       NULL, 's'},
+        {"type",             required_argument, NULL, 't'},
+#endif
+        {"version",          no_argument,       NULL, 'v'},
+        {"verbose",          no_argument,       NULL, 'V'},
+#ifndef NDEBUG
+        {"debug",            required_argument, NULL, 'G'},
+#endif
+        {NULL,               required_argument, NULL, 'y'},
+        {NULL,               0,                 NULL, 0}
+    };
+    FILE *out = stdout;
+    struct ly_ctx *ctx = NULL;
+    const struct lys_module *mod;
+    LYS_OUTFORMAT outformat_s = 0;
+    LYS_INFORMAT informat_s;
+#if 0
+    LYD_FORMAT informat_d, outformat_d = 0, ylformat = 0;
+#endif
+    struct ly_set *searchpaths = NULL;
+    const char *outtarget_s = NULL;
+    char **feat = NULL, *ptr, *featlist, *dir;
+    struct stat st;
+    uint32_t u;
+    int options_ctx = LY_CTX_NOYANGLIBRARY, list = 0, outoptions_s = 0, outline_length_s = 0;
+#if 0
+    const char *oper_file = NULL, *envelope_s = NULL;
+    char *ylpath = NULL;
+    int options_dflt = 0, options_parser = 0, envelope = 0, autodetection = 0, merge = 0;
+    struct dataitem {
+        const char *filename;
+        struct lyxml_elem *xml;
+        struct lyd_node *tree;
+        struct dataitem *next;
+        LYD_FORMAT format;
+        int type;
+    } *data = NULL, *data_item, *data_prev = NULL;
+    struct lyxml_elem *iter, *elem;
+    struct lyd_node *oper = NULL, *subroot, *next, *node;
+#endif
+    struct ly_set *mods = NULL;
+    void *p;
+    int index = 0;
+
+    opterr = 0;
+#ifndef NDEBUG
+    while ((opt = getopt_long(argc, argv, "ad:f:F:gunP:L:hHiDlmo:p:r:O:st:vVG:y:", options, &opt_index)) != -1)
+#else
+    while ((opt = getopt_long(argc, argv, "ad:f:F:gunP:L:hHiDlmo:p:r:O:st:vVy:", options, &opt_index)) != -1)
+#endif
+    {
+        switch (opt) {
+#if 0
+        case 'a':
+            envelope = 1;
+            break;
+        case 'd':
+            if (!strcmp(optarg, "all")) {
+                options_dflt = (options_dflt & ~LYP_WD_MASK) | LYP_WD_ALL;
+            } else if (!strcmp(optarg, "all-tagged")) {
+                options_dflt = (options_dflt & ~LYP_WD_MASK) | LYP_WD_ALL_TAG;
+            } else if (!strcmp(optarg, "trim")) {
+                options_dflt = (options_dflt & ~LYP_WD_MASK) | LYP_WD_TRIM;
+            } else if (!strcmp(optarg, "implicit-tagged")) {
+                options_dflt = (options_dflt & ~LYP_WD_MASK) | LYP_WD_IMPL_TAG;
+            } else {
+                fprintf(stderr, "yanglint error: unknown default mode %s\n", optarg);
+                help(1);
+                goto cleanup;
+            }
+            break;
+#endif
+        case 'f':
+            if (!strcasecmp(optarg, "yang")) {
+                outformat_s = LYS_OUT_YANG;
+#if 0
+                outformat_d = 0;
+            } else if (!strcasecmp(optarg, "tree")) {
+                outformat_s = LYS_OUT_TREE;
+                outformat_d = 0;
+            } else if (!strcasecmp(optarg, "tree-rfc")) {
+                outformat_s = LYS_OUT_TREE;
+                outoptions_s |= LYS_OUTOPT_TREE_RFC;
+                outformat_d = 0;
+            } else if (!strcasecmp(optarg, "yin")) {
+                outformat_s = LYS_OUT_YIN;
+                outformat_d = 0;
+            } else if (!strcasecmp(optarg, "jsons")) {
+                outformat_s = LYS_OUT_JSON;
+                outformat_d = 0;
+            } else if (!strcasecmp(optarg, "xml")) {
+                outformat_s = 0;
+                outformat_d = LYD_XML;
+            } else if (!strcasecmp(optarg, "json")) {
+                outformat_s = 0;
+                outformat_d = LYD_JSON;
+#endif
+            } else {
+                fprintf(stderr, "yanglint error: unknown output format %s\n", optarg);
+                help(1);
+                goto cleanup;
+            }
+            break;
+        case 'F':
+            featsize++;
+            if (!feat) {
+                p = malloc(sizeof *feat);
+            } else {
+                p = realloc(feat, featsize * sizeof *feat);
+            }
+            if (!p) {
+                fprintf(stderr, "yanglint error: Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+                goto cleanup;
+            }
+            feat = p;
+            feat[featsize - 1] = strdup(optarg);
+            ptr = strchr(feat[featsize - 1], ':');
+            if (!ptr) {
+                fprintf(stderr, "yanglint error: Invalid format of the features specification (%s)", optarg);
+                goto cleanup;
+            }
+            *ptr = '\0';
+
+            break;
+#if 0
+        case 'g':
+            outoptions_s |= LYS_OUTOPT_TREE_GROUPING;
+            break;
+        case 'u':
+            outoptions_s |= LYS_OUTOPT_TREE_USES;
+            break;
+        case 'n':
+            outoptions_s |= LYS_OUTOPT_TREE_NO_LEAFREF;
+            break;
+        case 'P':
+            outtarget_s = optarg;
+            break;
+        case 'L':
+            outline_length_s = atoi(optarg);
+            break;
+#endif
+        case 'h':
+            help(0);
+            ret = EXIT_SUCCESS;
+            goto cleanup;
+#if 0
+        case 'H':
+            tree_help();
+            ret = EXIT_SUCCESS;
+            goto cleanup;
+#endif
+        case 'i':
+            options_ctx |= LY_CTX_ALLIMPLEMENTED;
+            break;
+        case 'D':
+            if (options_ctx & LY_CTX_DISABLE_SEARCHDIRS) {
+                fprintf(stderr, "yanglint error: -D specified too many times.\n");
+                goto cleanup;
+            } else if (options_ctx & LY_CTX_DISABLE_SEARCHDIR_CWD) {
+                options_ctx &= ~LY_CTX_DISABLE_SEARCHDIR_CWD;
+                options_ctx |= LY_CTX_DISABLE_SEARCHDIRS;
+            } else {
+                options_ctx |= LY_CTX_DISABLE_SEARCHDIR_CWD;
+            }
+            break;
+        case 'l':
+            list = 1;
+            break;
+#if 0
+        case 'm':
+            merge = 1;
+            break;
+#endif
+        case 'o':
+            if (out != stdout) {
+                fclose(out);
+            }
+            out = fopen(optarg, "w");
+            if (!out) {
+                fprintf(stderr, "yanglint error: unable open output file %s (%s)\n", optarg, strerror(errno));
+                goto cleanup;
+            }
+            break;
+        case 'p':
+            if (stat(optarg, &st) == -1) {
+                fprintf(stderr, "yanglint error: Unable to use search path (%s) - %s.\n", optarg, strerror(errno));
+                goto cleanup;
+            }
+            if (!S_ISDIR(st.st_mode)) {
+                fprintf(stderr, "yanglint error: Provided search path is not a directory.\n");
+                goto cleanup;
+            }
+            if (!searchpaths) {
+                searchpaths = ly_set_new();
+            }
+            ly_set_add(searchpaths, optarg, 0);
+            break;
+#if 0
+        case 'r':
+        case 'O':
+            if (oper_file || (options_parser & LYD_OPT_NOEXTDEPS)) {
+                fprintf(stderr, "yanglint error: The operational datastore (-O) cannot be set multiple times.\n");
+                goto cleanup;
+            }
+            if (optarg[0] == '!') {
+                /* ignore extenral dependencies to the operational datastore */
+                options_parser |= LYD_OPT_NOEXTDEPS;
+            } else {
+                /* external file with the operational datastore */
+                oper_file = optarg;
+            }
+            break;
+        case 's':
+            options_parser |= LYD_OPT_STRICT;
+            break;
+        case 't':
+            if (!strcmp(optarg, "auto")) {
+                options_parser = (options_parser & ~LYD_OPT_TYPEMASK);
+                autodetection = 1;
+            } else if (!strcmp(optarg, "config")) {
+                options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_CONFIG;
+            } else if (!strcmp(optarg, "get")) {
+                options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_GET;
+            } else if (!strcmp(optarg, "getconfig")) {
+                options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_GETCONFIG;
+            } else if (!strcmp(optarg, "edit")) {
+                options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_EDIT;
+            } else if (!strcmp(optarg, "data")) {
+                options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_DATA_NO_YANGLIB;
+            } else if (!strcmp(optarg, "rpc")) {
+                options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPC;
+            } else if (!strcmp(optarg, "rpcreply")) {
+                options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPCREPLY;
+            } else if (!strcmp(optarg, "notif")) {
+                options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_NOTIF;
+            } else {
+                fprintf(stderr, "yanglint error: unknown data tree type %s\n", optarg);
+                help(1);
+                goto cleanup;
+            }
+            break;
+#endif
+        case 'v':
+            version();
+            ret = EXIT_SUCCESS;
+            goto cleanup;
+        case 'V':
+            verbose++;
+            break;
+#ifndef NDEBUG
+        case 'G':
+            u = 0;
+            ptr = optarg;
+            while (ptr[0]) {
+                if (!strncmp(ptr, "dict", 4)) {
+                    u |= LY_LDGDICT;
+                    ptr += 4;
+                } else if (!strncmp(ptr, "yang", 4)) {
+                    u |= LY_LDGYANG;
+                    ptr += 4;
+                } else if (!strncmp(ptr, "yin", 3)) {
+                    u |= LY_LDGYIN;
+                    ptr += 3;
+                } else if (!strncmp(ptr, "xpath", 5)) {
+                    u |= LY_LDGXPATH;
+                    ptr += 5;
+                } else if (!strncmp(ptr, "diff", 4)) {
+                    u |= LY_LDGDIFF;
+                    ptr += 4;
+                }
+
+                if (ptr[0]) {
+                    if (ptr[0] != ',') {
+                        fprintf(stderr, "yanglint error: unknown debug group string \"%s\"\n", optarg);
+                        goto cleanup;
+                    }
+                    ++ptr;
+                }
+            }
+            ly_verb_dbg(u);
+            break;
+#endif
+#if 0
+        case 'y':
+            ptr = strrchr(optarg, '.');
+            if (ptr) {
+                ptr++;
+                if (!strcmp(ptr, "xml")) {
+                    ylformat = LYD_XML;
+                } else if (!strcmp(ptr, "json")) {
+                    ylformat = LYD_JSON;
+                } else {
+                    fprintf(stderr, "yanglint error: yang-library file in an unknown format \"%s\".\n", ptr);
+                    goto cleanup;
+                }
+            } else {
+                fprintf(stderr, "yanglint error: yang-library file in an unknown format.\n");
+                goto cleanup;
+            }
+            ylpath = optarg;
+            break;
+#endif
+        default:
+            help(1);
+            if (optopt) {
+                fprintf(stderr, "yanglint error: invalid option: -%c\n", optopt);
+            } else {
+                fprintf(stderr, "yanglint error: invalid option: %s\n", argv[optind - 1]);
+            }
+            goto cleanup;
+        }
+    }
+
+    /* check options compatibility */
+    if (!list && optind >= argc) {
+        help(1);
+        fprintf(stderr, "yanglint error: missing <file> to process\n");
+        goto cleanup;
+    }
+    if (outformat_s && outformat_s != LYS_OUT_TREE && (optind + 1) < argc) {
+        /* we have multiple schemas to be printed as YIN or YANG */
+        fprintf(stderr, "yanglint error: too many schemas to convert and store.\n");
+        goto cleanup;
+    }
+    if (outoptions_s || outtarget_s || outline_length_s) {
+#if 0
+        if (outformat_d || (outformat_s && outformat_s != LYS_OUT_TREE)) {
+            /* we have --tree-print-grouping with other output format than tree */
+            fprintf(stderr,
+                    "yanglint warning: --tree options take effect only in case of the tree output format.\n");
+        }
+    }
+    if (merge) {
+        if (autodetection || (options_parser & (LYD_OPT_RPC | LYD_OPT_RPCREPLY | LYD_OPT_NOTIF))) {
+            fprintf(stderr, "yanglint warning: merging not allowed, ignoring option -m.\n");
+            merge = 0;
+        } else {
+            /* first, files will be parsed as trusted to allow missing data, then the data trees will be merged
+             * and the result will be validated */
+            options_parser |= LYD_OPT_TRUSTED;
+        }
+#endif
+    }
+#if 0
+    if (!outformat_d && options_dflt) {
+        /* we have options for printing default nodes, but data output not specified */
+        fprintf(stderr, "yanglint warning: default mode is ignored when not printing data.\n");
+    }
+    if (outformat_s && (options_parser || autodetection)) {
+        /* we have options for printing data tree, but output is schema */
+        fprintf(stderr, "yanglint warning: data parser options are ignored when printing schema.\n");
+    }
+    if (oper_file && (!autodetection && !(options_parser & (LYD_OPT_RPC | LYD_OPT_RPCREPLY | LYD_OPT_NOTIF)))) {
+        fprintf(stderr, "yanglint warning: operational datastore applies only to RPCs or Notifications.\n");
+        /* ignore operational datastore file */
+        oper_file = NULL;
+    }
+    if ((options_parser & LYD_OPT_TYPEMASK) == LYD_OPT_DATA) {
+        /* add option to ignore ietf-yang-library data for implicit data type */
+        options_parser |= LYD_OPT_DATA_NO_YANGLIB;
+    }
+#endif
+
+    /* set callback for printing libyang messages */
+    ly_set_log_clb(libyang_verbclb, 1);
+#if 0
+    /* create libyang context */
+    if (ylpath) {
+        ctx = ly_ctx_new_ylpath(searchpaths ? (const char*)searchpaths->set.g[0] : NULL, ylpath, ylformat, options_ctx);
+    } else {
+#else
+    {
+#endif
+        ly_ctx_new(NULL, options_ctx, &ctx);
+    }
+    if (!ctx) {
+        goto cleanup;
+    }
+
+    /* set searchpaths */
+    if (searchpaths) {
+        for (u = 0; u < searchpaths->count; u++) {
+            ly_ctx_set_searchdir(ctx, (const char*)searchpaths->objs[u]);
+        }
+        index = u + 1;
+    }
+
+    /* derefered setting of verbosity in libyang after context initiation */
+    ly_verb(verbose);
+
+    mods = ly_set_new();
+
+
+    /* divide input files */
+    for (i = 0; i < argc - optind; i++) {
+        /* get the file format */
+        if (!get_fileformat(argv[optind + i], &informat_s/* TODO, &informat_d */)) {
+            goto cleanup;
+        }
+
+        if (informat_s) {
+            /* load/validate schema */
+            if (verbose >= 2) {
+                fprintf(stdout, "Validating %s schema file.\n", argv[optind + i]);
+            }
+            dir = strdup(argv[optind + i]);
+            ly_ctx_set_searchdir(ctx, ptr = dirname(dir));
+            mod = lys_parse_path(ctx, argv[optind + i], informat_s);
+            ly_ctx_unset_searchdir(ctx, index);
+            free(dir);
+            if (!mod) {
+                goto cleanup;
+            }
+            ly_set_add(mods, (void *)mod, 0);
+#if 0
+        } else {
+            if (autodetection && informat_d != LYD_XML) {
+                /* data file content autodetection is possible only for XML input */
+                fprintf(stderr, "yanglint error: data type autodetection is applicable only to XML files.\n");
+                goto cleanup;
+            }
+
+            /* remember data filename and its format */
+            if (!data) {
+                data = data_item = malloc(sizeof *data);
+            } else {
+                for (data_item = data; data_item->next; data_item = data_item->next);
+                data_item->next = malloc(sizeof *data_item);
+                data_item = data_item->next;
+            }
+            data_item->filename = argv[optind + i];
+            data_item->format = informat_d;
+            data_item->type = options_parser & LYD_OPT_TYPEMASK;
+            data_item->tree = NULL;
+            data_item->xml = NULL;
+            data_item->next = NULL;
+#endif
+        }
+    }
+#if 0
+    if (outformat_d && !data && !list) {
+        fprintf(stderr, "yanglint error: no input data file for the specified data output format.\n");
+        goto cleanup;
+    }
+#endif
+
+    /* enable specified features, if not specified, all the module's features are enabled */
+    u = 4; /* skip internal libyang modules */
+    while ((mod = ly_ctx_get_module_iter(ctx, &u))) {
+        for (i = 0; i < featsize; i++) {
+            if (!strcmp(feat[i], mod->name)) {
+                /* parse features spec */
+                featlist = strdup(feat[i] + strlen(feat[i]) + 1);
+                ptr = NULL;
+                while((ptr = strtok(ptr ? NULL : featlist, ","))) {
+                    if (verbose >= 2) {
+                        fprintf(stdout, "Enabling feature %s in module %s.\n", ptr, mod->name);
+                    }
+                    if (lys_feature_enable(mod, ptr)) {
+                        fprintf(stderr, "Feature %s not defined in module %s.\n", ptr, mod->name);
+                    }
+                }
+                free(featlist);
+                break;
+            }
+        }
+        if (i == featsize) {
+            if (verbose >= 2) {
+                fprintf(stdout, "Enabling all features in module %s.\n", mod->name);
+            }
+            lys_feature_enable(mod, "*");
+        }
+    }
+
+    /* convert (print) to FORMAT */
+    if (outformat_s) {
+        if (outformat_s == LYS_OUT_JSON && mods->count > 1) {
+            fputs("[", out);
+        }
+        for (u = 0; u < mods->count; u++) {
+            if (u) {
+                if (outformat_s == LYS_OUT_JSON) {
+                    fputs(",\n", out);
+                } else {
+                    fputs("\n", out);
+                }
+            }
+            lys_print_file(out, (struct lys_module *)mods->objs[u], outformat_s, outline_length_s, outoptions_s);
+        }
+        if (outformat_s == LYS_OUT_JSON) {
+            if (mods->count > 1) {
+                fputs("]\n", out);
+            } else if (mods->count == 1) {
+                fputs("\n", out);
+            }
+        }
+#if 0
+    } else if (data) {
+        ly_errno = 0;
+
+        /* prepare operational datastore when specified for RPC/Notification */
+        if (oper_file) {
+            /* get the file format */
+            if (!get_fileformat(oper_file, NULL, &informat_d)) {
+                goto cleanup;
+            } else if (!informat_d) {
+                fprintf(stderr, "yanglint error: The operational data are expected in XML or JSON format.\n");
+                goto cleanup;
+            }
+            oper = lyd_parse_path(ctx, oper_file, informat_d, LYD_OPT_DATA_NO_YANGLIB | LYD_OPT_TRUSTED);
+            if (!oper) {
+                fprintf(stderr, "yanglint error: Failed to parse the operational datastore file for RPC/Notification validation.\n");
+                goto cleanup;
+            }
+        }
+
+        for (data_item = data, data_prev = NULL; data_item; data_prev = data_item, data_item = data_item->next) {
+            /* parse data file - via LYD_OPT_TRUSTED postpone validation when all data are loaded and merged */
+            if (autodetection) {
+                /* erase option not covered by LYD_OPT_TYPEMASK, but used according to the type */
+                options_parser &= ~LYD_OPT_DATA_NO_YANGLIB;
+                /* automatically detect data type from the data top level */
+                data_item->xml = lyxml_parse_path(ctx, data_item->filename, 0);
+                if (!data_item->xml) {
+                    fprintf(stderr, "yanglint error: parsing XML data for data type autodetection failed.\n");
+                    goto cleanup;
+                }
+
+                /* NOTE: namespace is ignored to simplify usage of this feature */
+                if (!strcmp(data_item->xml->name, "data")) {
+                    if (verbose >= 2) {
+                        fprintf(stdout, "Parsing %s as complete datastore.\n", data_item->filename);
+                    }
+                    options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_DATA_NO_YANGLIB;
+                    data_item->type = LYD_OPT_DATA;
+                } else if (!strcmp(data_item->xml->name, "config")) {
+                    if (verbose >= 2) {
+                        fprintf(stdout, "Parsing %s as config data.\n", data_item->filename);
+                    }
+                    options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_CONFIG;
+                    data_item->type = LYD_OPT_CONFIG;
+                } else if (!strcmp(data_item->xml->name, "get-reply")) {
+                    if (verbose >= 2) {
+                        fprintf(stdout, "Parsing %s as <get> reply data.\n", data_item->filename);
+                    }
+                    options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_GET;
+                    data_item->type = LYD_OPT_GET;
+                } else if (!strcmp(data_item->xml->name, "get-config-reply")) {
+                    if (verbose >= 2) {
+                        fprintf(stdout, "Parsing %s as <get-config> reply data.\n", data_item->filename);
+                    }
+                    options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_GETCONFIG;
+                    data_item->type = LYD_OPT_GETCONFIG;
+                } else if (!strcmp(data_item->xml->name, "edit-config")) {
+                    if (verbose >= 2) {
+                        fprintf(stdout, "Parsing %s as <edit-config> data.\n", data_item->filename);
+                    }
+                    options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_EDIT;
+                    data_item->type = LYD_OPT_EDIT;
+                } else if (!strcmp(data_item->xml->name, "rpc")) {
+                    if (verbose >= 2) {
+                        fprintf(stdout, "Parsing %s as <rpc> data.\n", data_item->filename);
+                    }
+                    options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPC;
+                    data_item->type = LYD_OPT_RPC;
+                } else if (!strcmp(data_item->xml->name, "rpc-reply")) {
+                    if (verbose >= 2) {
+                        fprintf(stdout, "Parsing %s as <rpc-reply> data.\n", data_item->filename);
+                    }
+
+                    data_item->type = LYD_OPT_RPCREPLY;
+                    if (!data_item->next || (data_prev && !data_prev->tree)) {
+                        fprintf(stderr, "RPC reply (%s) must be paired with the original RPC, see help.\n", data_item->filename);
+                        goto cleanup;
+                    }
+
+                    continue;
+                } else if (!strcmp(data_item->xml->name, "notification")) {
+                    if (verbose >= 2) {
+                        fprintf(stdout, "Parsing %s as <notification> data.\n", data_item->filename);
+                    }
+                    options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_NOTIF;
+                    data_item->type = LYD_OPT_NOTIF;
+
+                    /* ignore eventTime element if present */
+                    while (data_item->xml->child && !strcmp(data_item->xml->child->name, "eventTime")) {
+                        lyxml_free(ctx, data_item->xml->child);
+                    }
+                } else {
+                    fprintf(stderr, "yanglint error: invalid top-level element \"%s\" for data type autodetection.\n",
+                            data_item->xml->name);
+                    goto cleanup;
+                }
+
+                data_item->tree = lyd_parse_xml(ctx, &data_item->xml->child, options_parser, oper);
+                if (data_prev && data_prev->type == LYD_OPT_RPCREPLY) {
+parse_reply:
+                    /* check result of the RPC parsing, we are going to do another parsing in this step */
+                    if (ly_errno) {
+                        goto cleanup;
+                    }
+
+                    /* check that we really have RPC for the reply */
+                    if (data_item->type != LYD_OPT_RPC) {
+                        fprintf(stderr, "yanglint error: RPC reply (%s) must be paired with the original RPC, see help.\n", data_prev->filename);
+                        goto cleanup;
+                    }
+
+                    if (data_prev->format == LYD_XML) {
+                        /* ignore <ok> and <rpc-error> elements if present */
+                        u = 0;
+                        LY_TREE_FOR_SAFE(data_prev->xml->child, iter, elem) {
+                            if (!strcmp(data_prev->xml->child->name, "ok")) {
+                                if (u) {
+                                    /* rpc-error or ok already present */
+                                    u = 0x8; /* error flag */
+                                } else {
+                                    u = 0x1 | 0x4; /* <ok> flag with lyxml_free() flag */
+                                }
+                            } else if (!strcmp(data_prev->xml->child->name, "rpc-error")) {
+                                if (u && (u & 0x1)) {
+                                    /* ok already present, rpc-error can be present multiple times */
+                                    u = 0x8; /* error flag */
+                                } else {
+                                    u = 0x2 | 0x4; /* <rpc-error> flag with lyxml_free() flag */
+                                }
+                            }
+
+                            if (u == 0x8) {
+                                fprintf(stderr, "yanglint error: Invalid RPC reply (%s) content.\n", data_prev->filename);
+                                goto cleanup;
+                            } else if (u & 0x4) {
+                                lyxml_free(ctx, data_prev->xml->child);
+                                u &= ~0x4; /* unset lyxml_free() flag */
+                            }
+                        }
+
+                        /* finally, parse RPC reply from the previous step */
+                        data_prev->tree = lyd_parse_xml(ctx, &data_prev->xml->child,
+                                                        (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPCREPLY, data_item->tree, oper);
+                    } else { /* LYD_JSON */
+                        data_prev->tree = lyd_parse_path(ctx, data_prev->filename, data_item->format,
+                                                         (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPCREPLY, data_item->tree, oper);
+                    }
+                }
+            } else if ((options_parser & LYD_OPT_TYPEMASK) == LYD_OPT_RPCREPLY) {
+                if (data_prev && !data_prev->tree) {
+                    /* now we should have RPC for the preceding RPC reply */
+                    data_item->tree = lyd_parse_path(ctx, data_item->filename, data_item->format,
+                                                     (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPC, oper);
+                    data_item->type = LYD_OPT_RPC;
+                    goto parse_reply;
+                } else {
+                    /* now we have RPC reply which will be parsed in next step together with its RPC */
+                    if (!data_item->next) {
+                        fprintf(stderr, "yanglint error: RPC reply (%s) must be paired with the original RPC, see help.\n", data_item->filename);
+                        goto cleanup;
+                    }
+                    if (data_item->format == LYD_XML) {
+                        /* create rpc-reply container to unify handling with autodetection */
+                        data_item->xml = calloc(1, sizeof *data_item->xml);
+                        if (!data_item->xml) {
+                            fprintf(stderr, "yanglint error: Memory allocation failed failed.\n");
+                            goto cleanup;
+                        }
+                        data_item->xml->name = lydict_insert(ctx, "rpc-reply", 9);
+                        data_item->xml->prev = data_item->xml;
+                        data_item->xml->child = lyxml_parse_path(ctx, data_item->filename, LYXML_PARSE_MULTIROOT | LYXML_PARSE_NOMIXEDCONTENT);
+                        if (data_item->xml->child) {
+                            data_item->xml->child->parent = data_item->xml;
+                        }
+                    }
+                    continue;
+                }
+            } else {
+                data_item->tree = lyd_parse_path(ctx, data_item->filename, data_item->format, options_parser, oper);
+            }
+            if (ly_errno) {
+                goto cleanup;
+            }
+
+            if (merge && data != data_item) {
+                if (!data->tree) {
+                    data->tree = data_item->tree;
+                } else if (data_item->tree) {
+                    /* merge results */
+                    if (lyd_merge(data->tree, data_item->tree, LYD_OPT_DESTRUCT | LYD_OPT_EXPLICIT)) {
+                        fprintf(stderr, "yanglint error: merging multiple data trees failed.\n");
+                        goto cleanup;
+                    }
+                }
+                data_item->tree = NULL;
+            }
+        }
+
+        if (merge) {
+            /* validate the merged data tree, do not trust the input, invalidate all the data first */
+            LY_TREE_FOR(data->tree, subroot) {
+                LY_TREE_DFS_BEGIN(subroot, next, node) {
+                    node->validity = LYD_VAL_OK;
+                    switch (node->schema->nodetype) {
+                    case LYS_LEAFLIST:
+                    case LYS_LEAF:
+                        if (((struct lys_node_leaf *)node->schema)->type.base == LY_TYPE_LEAFREF) {
+                            node->validity |= LYD_VAL_LEAFREF;
+                        }
+                        break;
+                    case LYS_LIST:
+                        node->validity |= LYD_VAL_UNIQUE;
+                        /* falls through */
+                    case LYS_CONTAINER:
+                    case LYS_NOTIF:
+                    case LYS_RPC:
+                    case LYS_ACTION:
+                        node->validity |= LYD_VAL_MAND;
+                        break;
+                    default:
+                        break;
+                    }
+                    LY_TREE_DFS_END(subroot, next, node)
+                }
+            }
+            if (lyd_validate(&data->tree, options_parser & ~LYD_OPT_TRUSTED, ctx)) {
+                goto cleanup;
+            }
+        }
+
+        /* print only if data output format specified */
+        if (outformat_d) {
+            for (data_item = data; data_item; data_item = data_item->next) {
+                if (!merge && verbose >= 2) {
+                    fprintf(stdout, "File %s:\n", data_item->filename);
+                }
+                if (outformat_d == LYD_XML && envelope) {
+                    switch (data_item->type) {
+                    case LYD_OPT_DATA:
+                        envelope_s = "data";
+                        break;
+                    case LYD_OPT_CONFIG:
+                        envelope_s = "config";
+                        break;
+                    case LYD_OPT_GET:
+                        envelope_s = "get-reply";
+                        break;
+                    case LYD_OPT_GETCONFIG:
+                        envelope_s = "get-config-reply";
+                        break;
+                    case LYD_OPT_EDIT:
+                        envelope_s = "edit-config";
+                        break;
+                    case LYD_OPT_RPC:
+                        envelope_s = "rpc";
+                        break;
+                    case LYD_OPT_RPCREPLY:
+                        envelope_s = "rpc-reply";
+                        break;
+                    case LYD_OPT_NOTIF:
+                        envelope_s = "notification";
+                        break;
+                    }
+                    fprintf(out, "<%s>\n", envelope_s);
+                    if (data_item->type == LYD_OPT_RPC && data_item->tree->schema->nodetype != LYS_RPC) {
+                        /* action */
+                        fprintf(out, "<action xmlns=\"urn:ietf:params:xml:ns:yang:1\">\n");
+                    }
+                }
+                lyd_print_file(out, (data_item->type == LYD_OPT_RPCREPLY) ? data_item->tree->child : data_item->tree,
+                               outformat_d, LYP_WITHSIBLINGS | LYP_FORMAT | options_dflt);
+                if (envelope_s) {
+                    if (data_item->type == LYD_OPT_RPC && data_item->tree->schema->nodetype != LYS_RPC) {
+                        fprintf(out, "</action>\n");
+                    }
+                    fprintf(out, "</%s>\n", envelope_s);
+                }
+                if (merge) {
+                    /* stop after first item */
+                    break;
+                }
+            }
+        }
+#endif
+    }
+#if 0
+    if (list) {
+        print_list(out, ctx, outformat_d);
+    }
+#endif
+
+    ret = EXIT_SUCCESS;
+
+cleanup:
+    if (out && out != stdout) {
+        fclose(out);
+    }
+    ly_set_free(mods, NULL);
+    ly_set_free(searchpaths, NULL);
+    for (i = 0; i < featsize; i++) {
+        free(feat[i]);
+    }
+    free(feat);
+#if 0
+    for (; data; data = data_item) {
+        data_item = data->next;
+        lyxml_free(ctx, data->xml);
+        lyd_free_withsiblings(data->tree);
+        free(data);
+    }
+    lyd_free_withsiblings(oper);
+#endif
+    ly_ctx_destroy(ctx, NULL);
+
+    return ret;
+}
diff --git a/tools/lint/yanglint.1 b/tools/lint/yanglint.1
new file mode 100644
index 0000000..4b7060d
--- /dev/null
+++ b/tools/lint/yanglint.1
@@ -0,0 +1,136 @@
+.\" Manpage for yanglint.
+.\" Process this file with
+.\" groff -man -Tascii yanglint.1
+.\"
+
+.TH YANGLINT 1 "2016-10-27" "libyang"
+.SH NAME
+yanglint \- YANG lint tool
+.
+.SH SYNOPSIS
+.B yanglint
+.br
+.B yanglint
+[\fIOPTIONS\fP]
+[\-f { \fByang\fP | \fByin\fP | \fBtree\fP } ]
+.I FILE ...
+.br
+.B yanglint
+[\fIOPTIONS\fP]
+[\-f { \fBxml\fP | \fBjson\fP } ]
+\fISCHEMA\fP...
+\fIFILE\fP...
+.
+.SH DESCRIPTION
+\fByanglint\fP is a command-line tool for validating and converting YANG
+schemas and the YANG modeled data. For a simple use, it validates the provided
+file and if the output format specified, it converts input data into the output
+format. If started with no argument, \fByanglint\fP opens interactive
+environment where the user is allowed to work with schemas and data in a more
+complex way.
+.
+.SH OPTIONS
+.TP
+.BR "\-h\fR,\fP \-\^\-help"
+Outputs usage help and exits.
+.TP
+.BR "\-v\fR,\fP \-\^\-version"
+Outputs the version number and exits.
+.TP
+.BR "\-V\fR,\fP \-\^\-verbose"
+Increases the verbosity level. If not specified, only errors are printed, with
+each appearance it adds: warnings, verbose messages, debug messages (if compiled
+with debug information).
+.TP
+.BR "\-p \fIPATH\fP\fR,\fP \-\^\-path=\fIPATH\fP"
+Specifies search path for getting imported modules or included submodules. The option
+can be used multiple times. The current working directory and path of the module
+being added is used implicitly.
+.TP
+.BR "\-s\fR,\fP \-\^\-strict"
+Changes handling of unknown data nodes - instead of silently ignoring unknown data,
+error is printed and data parsing fails. This option applies only on data parsing.
+.TP
+.BR "\-f \fIFORMAT\fP\fR,\fP \-\^\-format=\fIFORMAT\fP"
+Converts the content of the input \fIFILE\fPs into the specified \fIFORMAT\fP. If no
+\fIOUTFILE\fP is specified, the data are printed on the standard output. Only the
+compatible formats for the input \fIFILE\fPs are allowed, see the section \fBFORMATS\fP.
+.TP
+.BR "\-o \fIOUTFILE\fP\fR,\fP \-\^\-output=\fIOUTFILE\fP"
+Writes the output data into the specified \fIOUTFILE\fP. The option can be used
+only in combination with \fB--format\fR option. In case of converting schema, only
+a single input schema \fIFILE\fP is allowed. In case of data input \fIFILE\fPs,
+input is merged and printed into a single \fIOUTFILE\fP.
+.TP
+.BR "\-F \fIFEATURES\fP\fR,\fP \-\^\-features=\fIFEATURES\fP"
+Specifies the list of enabled features in the format
+\fIMODULE\fP:[\fIFEATURE\fP,...]. In case of processing multiple modules, the
+option can be used repeatedly. To disable all the features, use an empty list
+specified for the particular module.
+.TP
+.BR "\-d \fIMODE\fP\fR,\fP \-\^\-default=\fIMODE\fP"
+Print data with default values, according to the \fIMODE\fP (to print attributes,
+the ietf-netconf-with-defaults model must be loaded). The \fIMODE\fP is one of the following:
+ \[bu] \fBall\fP             - add missing default nodes
+ \[bu] \fBall-tagged\fP      - add missing default nodes and mark all the default nodes with the attribute
+ \[bu] \fBtrim\fP            - remove all nodes with a default value
+ \[bu] \fBimplicit-tagged\fP - add missing nodes and mark them with the attribute
+.TP
+.BR "\-t \fITYPE\fP\fR,\fP \-\^\-type=\fITYPE\fP"
+Specify data tree type in the input data \fIFILE\fPs. The \fITYPE\fP is one of the following:
+ \[bu] \fBauto\fP            - Resolve data type (one of the following) automatically (as pyang does). Applicable only on XML input data.
+ \[bu] \fBdata\fP            - Complete datastore with status data (default type).
+ \[bu] \fBconfig\fP          - Configuration datastore (without status data).
+ \[bu] \fBget\fP             - Result of the NETCONF <get> operation.
+ \[bu] \fBgetconfig\fP       - Result of the NETCONF <get-config> operation.
+ \[bu] \fBedit\fP            - Content of the NETCONF <edit-config> operation.
+ \[bu] \fBrpc\fP             - Content of the NETCONF <rpc> message, defined as YANG's rpc input statement.
+ \[bu] \fBrpcreply\fP        - Reply to the RPC. This is just a virtual \fITYPE\fP, for parsing replies, '\fBauto\fP' must be used since the data \fIFILE\fPs are expected in pairs.
+.br
+                     The first input data \fIFILE\fP is expected as '\fBrpc\fP' \fITYPE\fP, the second \fIFILE\fP is expected as reply to the previous RPC.
+ \[bu] \fBnotif\fP           - Notification instance (content of the <notification> element without <eventTime>.
+.TP
+.BR "\-O \fIFILE\fP\fR,\fP \-\^\-operational=\fIFILE\fP]
+Optional parameter for '\fBrpc\fP' and '\fBnotif\fP' \fITYPE\fPs, the \fIFILE\fP contains running configuration datastore and
+state data referenced from the RPC/Notification. The same data apply to all input data \fIFILE\fPs. Note that the file
+is validated as '\fBdata\fP' \fITYPE\fP. Special value '\fB!\fP' can be used as \fIFILE\fP argument to ignore the external references.
+.TP
+.BR "\-y \fIYANGLIB_PATH\fP"
+Specify path to a yang-library data file (XML or JSON) describing the initial context.
+If provided, yanglint loads the modules according to the content of the yang-library data tree.
+Otherwise, an empty content with only the internal libyang modules is used. This does
+not limit user to load another modules explicitly specified as command line parameters.
+.
+.SH FORMATS
+There are two types of formats to use.
+.TP
+.I Schemas
+In case of schemas, the content can be converted into the '\fByang\fP', '\fByin\fP'
+and '\fBtree\fP' formats. As input, only YANG and YIN files are
+accepted. Note, that the corresponding file extension is required.
+.TP
+.I Data\ \ \
+In case of YANG modeled data, the content can be converted between '\fBxml\fP'
+and '\fBjson\fP' formats. Remember that the corresponding file extension of the
+input file is required.
+.
+
+.SH EXAMPLES
+.IP \[bu] 2
+Open interactive environment:
+    yanglint
+.IP \[bu]
+Convert YANG model into YIN and print it to the stdout:
+    yanglint --format=yin ./ietf-system.yang
+.IP \[bu]
+Convert ietf-system configuration data from XML to JSON:
+    yanglint --format=json --type=config --output=data.json ./ietf-system.yang ./data.xml
+
+.SH SEE ALSO
+https://github.com/CESNET/libyang (libyang homepage and Git repository)
+.
+.SH AUTHORS
+Radek Krejci <rkrejci@cesnet.cz>, Michal Vasko <mvasko@cesnet.cz>
+.
+.SH COPYRIGHT
+Copyright \(co 2015-2017 CESNET, a.l.e.