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);