yanglint UPDATE choise/case completion

yanglint print -f info -P now supports choice and case schema nodes.
diff --git a/tools/lint/cmd_print.c b/tools/lint/cmd_print.c
index 2702fbf..c1a5359 100644
--- a/tools/lint/cmd_print.c
+++ b/tools/lint/cmd_print.c
@@ -243,15 +243,12 @@
     if (node_path) {
         const struct lysc_node *node;
 
-        node = lys_find_path(*ctx, NULL, node_path, 0);
+        node = find_schema_path(*ctx, node_path);
         if (!node) {
-            node = lys_find_path(*ctx, NULL, node_path, 1);
-
-            if (!node) {
-                YLMSG_E("The requested schema node \"%s\" does not exists.\n", node_path);
-                goto cleanup;
-            }
+            YLMSG_E("The requested schema node \"%s\" does not exists.\n", node_path);
+            goto cleanup;
         }
+
         if (lys_print_node(out, node, format, 0, options_print)) {
             YLMSG_E("Unable to print schema node %s.\n", node_path);
             goto cleanup;
diff --git a/tools/lint/common.c b/tools/lint/common.c
index 9033b9d..4d1f60f 100644
--- a/tools/lint/common.c
+++ b/tools/lint/common.c
@@ -781,3 +781,89 @@
     ly_set_free(set, NULL);
     return ret;
 }
+
+const struct lysc_node *
+find_schema_path(const struct ly_ctx *ctx, const char *schema_path)
+{
+    const char *end, *module_name_end;
+    char *module_name = NULL;
+    const struct lysc_node *node = NULL, *parent_node = NULL, *parent_node_tmp;
+    const struct lys_module *module;
+    size_t node_name_len;
+    ly_bool found_exact_match = 0;
+
+    /* iterate over each '/' in the path */
+    while (schema_path) {
+        /* example: schema_path = /listen/endpoint
+         * end == NULL for endpoint, end exists for listen */
+        end = strchr(schema_path + 1, '/');
+        if (end) {
+            node_name_len = end - schema_path - 1;
+        } else {
+            node_name_len = strlen(schema_path + 1);
+        }
+
+        /* ex: schema_path = /ietf-interfaces:interfaces/interface/ietf-ip:ipv4 */
+        module_name_end = strchr(schema_path, ':');
+        if (module_name_end) {
+            if (!end || (module_name_end < end)) {
+                /* only get module's name, if it is in the current scope */
+                free(module_name);
+                module_name = strndup(schema_path + 1, module_name_end - schema_path - 1);
+                if (!module_name) {
+                    YLMSG_E("Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+                    parent_node = NULL;
+                    goto cleanup;
+                }
+                schema_path = module_name_end;
+            }
+
+            if (module_name_end < end) {
+                /* recalculate the length of the node's name, because the module prefix mustn't be compared later */
+                if (end) {
+                    node_name_len = end - module_name_end - 1;
+                } else {
+                    node_name_len = strlen(module_name_end + 1);
+                }
+            }
+        }
+
+        module = ly_ctx_get_module_implemented(ctx, module_name);
+        if (!module) {
+            /* unknown module name */
+            parent_node = NULL;
+            goto cleanup;
+        }
+
+        /* iterate over the node's siblings / module's top level containers */
+        while ((node = lys_getnext(node, parent_node, module->compiled, LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHCHOICE))) {
+            if (end && !strncmp(node->name, schema_path + 1, node_name_len) && (node->name[node_name_len] == '\0')) {
+                /* check if the whole node's name matches and it's not just a common prefix */
+                parent_node = node;
+                break;
+            } else if (!strncmp(node->name, schema_path + 1, node_name_len)) {
+                /* do the same here, however if there is no exact match, use the last node with the same prefix */
+                if (strlen(node->name) == node_name_len) {
+                    parent_node = node;
+                    found_exact_match = 1;
+                    break;
+                } else {
+                    parent_node_tmp = node;
+                }
+            }
+        }
+
+        if (!end && !found_exact_match) {
+            /* no exact match */
+            parent_node = parent_node_tmp;
+        }
+        found_exact_match = 0;
+
+        /* next iter */
+        schema_path = strchr(schema_path + 1, '/');
+    }
+
+cleanup:
+    free(module_name);
+    return parent_node;
+}
diff --git a/tools/lint/common.h b/tools/lint/common.h
index a1e8139..6d61d38 100644
--- a/tools/lint/common.h
+++ b/tools/lint/common.h
@@ -239,4 +239,13 @@
         uint32_t options_parse, uint32_t options_validate, uint32_t options_print, struct cmdline_file *operational_f,
         struct cmdline_file *rpc_f, struct ly_set *inputs, struct ly_set *xpaths);
 
+/**
+ * @brief Get the node specified by the path.
+ *
+ * @param[in] ctx libyang context with schema.
+ * @param[in] schema_path Path to the wanted node.
+ * @return Pointer to the schema node specified by the path on success, NULL otherwise.
+ */
+const struct lysc_node * find_schema_path(const struct ly_ctx *ctx, const char *schema_path);
+
 #endif /* COMMON_H_ */
diff --git a/tools/lint/completion.c b/tools/lint/completion.c
index 9e2b366..9843816 100644
--- a/tools/lint/completion.c
+++ b/tools/lint/completion.c
@@ -122,8 +122,8 @@
         return;
     }
 
-    while ((node = lys_getnext(node, last_node, NULL, 0))) {
-        match = lysc_path(node, LYSC_PATH_DATA, NULL, 0);
+    while ((node = lys_getnext(node, last_node, NULL, LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHCHOICE))) {
+        match = lysc_path(node, LYSC_PATH_LOG, NULL, 0);
         cmd_completion_add_match(match, matches, match_count);
         free(match);
     }
@@ -153,7 +153,7 @@
     }
 
     node = NULL;
-    while ((node = lys_getnext(node, parent, module, 0))) {
+    while ((node = lys_getnext(node, parent, module, LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHCHOICE))) {
         if (parent && (node->module != parent->module)) {
             /* augmented node */
             if (asprintf(&node_name, "%s:%s", node->module->name, node->name) == -1) {
@@ -170,7 +170,7 @@
         if (!hint_node_name || !strncmp(hint_node_name, node_name, strlen(hint_node_name))) {
             /* adding just module names + their top level node(s) to the hint */
             *last_node = node;
-            match = lysc_path(node, LYSC_PATH_DATA, NULL, 0);
+            match = lysc_path(node, LYSC_PATH_LOG, NULL, 0);
             cmd_completion_add_match(match, matches, match_count);
             free(match);
         }
@@ -189,7 +189,7 @@
 get_schema_completion(const char *hint, char ***matches, unsigned int *match_count)
 {
     const struct lys_module *module;
-    uint32_t idx, prev_lo;
+    uint32_t idx;
     const char *start;
     char *end, *module_name = NULL, *path = NULL;
     const struct lysc_node *parent, *last_node;
@@ -260,10 +260,8 @@
             goto cleanup;
         }
 
-        /* silently get the last parent in the hint (it may not exist) */
-        prev_lo = ly_log_options(0);
-        parent = lys_find_path(ctx, NULL, path, 0);
-        ly_log_options(prev_lo);
+        /* get the last parent in the hint (it may not exist) */
+        parent = find_schema_path(ctx, path);
 
         /* add all (matching) child nodes of the parent */
         add_all_children_nodes(NULL, parent, start + 1, matches, match_count, &last_node);