]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
lldpcli: provide a hidden complete command for shell completion
authorVincent Bernat <vincent@bernat.im>
Sat, 12 Jul 2014 11:09:37 +0000 (13:09 +0200)
committerVincent Bernat <vincent@bernat.im>
Sat, 12 Jul 2014 11:09:37 +0000 (13:09 +0200)
debian/etc/bash_completion.d/lldpcli
src/client/client.h
src/client/commands.c
src/client/lldpcli.c

index 0779c5cc6a1639827098a28de21c07f0969e8ee2..f52539e6aa268f298f0922a2b194b57b564aa4a2 100755 (executable)
@@ -10,10 +10,8 @@ _lldpcli()
         unset cmd[COMP_CWORD]
     fi
 
-    local choices=$(sudo ${cmd[0]} help ${cmd[@]:1} 2>&1 | \
-        tail -n +3 | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" | \
-        sed -e 's/^[ \t]*//g' -e 's/<CR>//g' -e 's/WORD//g' -e '/^$/d' | \
-        tr -s " " | cut -d " " -f 1)
+    local choices=$(sudo ${cmd[0]} complete ${cmd[@]:1} | \
+        cut -d " " -f 1)
     COMPREPLY=($(compgen -W '${choices}' -- ${cur} ))
     return 0
 }
index 8c306edc1fd66bc94862335fb64d1ef01b451317..db60fd0b5a8622b166f8c540c0e003fc07380e95 100644 (file)
@@ -69,6 +69,7 @@ struct cmd_node *commands_new(
            struct cmd_env*, void *),
        void *);
 struct cmd_node* commands_privileged(struct cmd_node *);
+struct cmd_node* commands_hidden(struct cmd_node *);
 void commands_free(struct cmd_node *);
 const char *cmdenv_arg(struct cmd_env*);
 const char *cmdenv_get(struct cmd_env*, const char*);
index d1bf242baab27ad1903c682ab90357299198ece7..8092f8c2fa3310b8338761dfa868f62c4c8963a8 100644 (file)
@@ -68,6 +68,7 @@ struct cmd_node {
        const char *token;      /**< Token to enter this cnode */
        const char *doc;        /**< Documentation string */
        int privileged;         /**< Privileged command? */
+       int hidden;             /**< Hidden command? */
 
        /**
         * Function validating entry in this node. Can be @c NULL.
@@ -100,7 +101,7 @@ commands_root(void)
 /**
  * Make a node accessible only to privileged users.
  *
- * @param node Node to change privileges
+ * @param node node to change privileges
  * @return the modified node
  *
  * The node is modified. It is returned to ease chaining.
@@ -112,6 +113,21 @@ commands_privileged(struct cmd_node *node)
        return node;
 }
 
+/**
+ * Hide a node from help or completion.
+ *
+ * @param node node to hide
+ * @return the modified node
+ *
+ * The node is modified. It is returned to ease chaining.
+ */
+struct cmd_node*
+commands_hidden(struct cmd_node *node)
+{
+       if (node) node->hidden = 1;
+       return node;
+}
+
 /**
  * Create a new node acessible by any user.
  *
@@ -304,6 +320,7 @@ struct candidate_word {
        TAILQ_ENTRY(candidate_word) next;
        const char *word;
        const char *doc;
+       int hidden;
 };
 
 /**
@@ -326,6 +343,7 @@ _commands_execute(struct lldpctl_conn_t *conn, struct writer *w,
 {
        int n, rc = 0, completion = (word != NULL);
        int help = 0;           /* Are we asking for help? */
+       int complete = 0;       /* Are we asking for possible completions? */
        struct cmd_env env = {
                .elements = TAILQ_HEAD_INITIALIZER(env.elements),
                .stack = TAILQ_HEAD_INITIALIZER(env.stack),
@@ -348,12 +366,14 @@ _commands_execute(struct lldpctl_conn_t *conn, struct writer *w,
         * execution until we reach the cursor position. */
        struct cmd_node *current = NULL;
        while ((current = cmdenv_top(&env))) {
-               if (!completion)
+               if (!completion) {
                        help = !!cmdenv_get(&env, "help"); /* Are we asking for help? */
+                       complete = !!cmdenv_get(&env, "complete"); /* Or completion? */
+               }
 
                struct cmd_node *candidate, *best = NULL;
                const char *token = (env.argp < env.argc) ? env.argv[env.argp] :
-                   (env.argp == env.argc && !help) ? NEWLINE : NULL;
+                   (env.argp == env.argc && !help && !complete) ? NEWLINE : NULL;
                if (token == NULL ||
                    (completion && env.argp == env.argc - 1))
                        goto end;
@@ -408,21 +428,21 @@ _commands_execute(struct lldpctl_conn_t *conn, struct writer *w,
                env.argp++;
        }
 end:
-       if (!completion && !help) {
+       if (!completion && !help && !complete) {
                if (rc == 0 && env.argp != env.argc + 1) {
                        log_warnx("lldpctl", "incomplete command");
                        rc = -1;
                }
-       } else if (rc == 0 && (env.argp == env.argc - 1 || help)) {
+       } else if (rc == 0 && (env.argp == env.argc - 1 || help || complete)) {
                /* We need to complete. Let's build the list of candidate words. */
                struct cmd_node *candidate = NULL;
-               int maxl = 10;                      /* Max length of a word */
+               size_t maxl = 10;                   /* Max length of a word */
                TAILQ_HEAD(, candidate_word) words; /* List of subnodes */
                TAILQ_INIT(&words);
                current = cmdenv_top(&env);
                if (!TAILQ_EMPTY(&current->subentries)) {
                        TAILQ_FOREACH(candidate, &current->subentries, next) {
-                               if ((!candidate->token || help ||
+                               if ((!candidate->token || help || complete ||
                                        !strncmp(env.argv[env.argc - 1], candidate->token,
                                            strlen(env.argv[env.argc -1 ]))) &&
                                    CAN_EXECUTE(candidate)) {
@@ -431,6 +451,7 @@ end:
                                        if (!cword) break;
                                        cword->word = candidate->token;
                                        cword->doc = candidate->doc;
+                                       cword->hidden = candidate->hidden;
                                        if (cword->word && strlen(cword->word) > maxl)
                                                maxl = strlen(cword->word);
                                        TAILQ_INSERT_TAIL(&words, cword, next);
@@ -439,14 +460,14 @@ end:
                }
                if (!TAILQ_EMPTY(&words)) {
                        /* Search if there is a common prefix, then return it. */
-                       int c = 0;
                        char prefix[maxl + 2]; /* Extra space may be added at the end */
                        struct candidate_word *cword, *cword_next;
                        memset(prefix, 0, maxl+2);
-                       for (int n = 0; n < maxl; n++) {
-                               c = 1; /* Set to 0 to exit outer loop */
+                       for (size_t n = 0; n < maxl; n++) {
+                               int c = 1; /* Set to 0 to exit outer loop */
                                TAILQ_FOREACH(cword, &words, next) {
                                        c = 0;
+                                       if (cword->hidden) continue;
                                        if (cword->word == NULL) break;
                                        if (!strcmp(cword->word, NEWLINE)) break;
                                        if (strlen(cword->word) == n) break;
@@ -461,7 +482,7 @@ end:
                        }
                        /* If the prefix is complete, add a space, otherwise,
                         * just return it as is. */
-                       if (!all && !help && strcmp(prefix, NEWLINE) &&
+                       if (!all && !help && !complete && strcmp(prefix, NEWLINE) &&
                            strlen(prefix) > 0 &&
                            strlen(env.argv[env.argc-1]) < strlen(prefix)) {
                                TAILQ_FOREACH(cword, &words, next) {
@@ -473,16 +494,27 @@ end:
                                *word = strdup(prefix);
                        } else {
                                /* No common prefix, print possible completions */
-                               fprintf(stderr, "\n-- \033[1;34m%s\033[0m\n",
-                                   current->doc ? current->doc : "Help");
+                               if (!complete)
+                                       fprintf(stderr, "\n-- \033[1;34m%s\033[0m\n",
+                                           current->doc ? current->doc : "Help");
                                TAILQ_FOREACH(cword, &words, next) {
+                                       if (cword->hidden) continue;
+
                                        char fmt[100];
-                                       snprintf(fmt, sizeof(fmt),
-                                           "%s%%%ds%s  %%s\n",
-                                           "\033[1;30m", maxl, "\033[0m");
-                                       fprintf(stderr, fmt,
-                                           cword->word ? cword->word : "WORD",
-                                           cword->doc ?  cword->doc  : "...");
+                                       if (!complete) {
+                                               snprintf(fmt, sizeof(fmt),
+                                                   "%s%%%ds%s  %%s\n",
+                                                   "\033[1;30m", (int)maxl, "\033[0m");
+                                               fprintf(stderr, fmt,
+                                                   cword->word ? cword->word : "WORD",
+                                                   cword->doc ?  cword->doc  : "...");
+                                       } else {
+                                               if (!cword->word || !strcmp(cword->word, NEWLINE))
+                                                       continue;
+                                               fprintf(stdout, "%s %s\n",
+                                                   cword->word ? cword->word : "WORD",
+                                                   cword->doc ?  cword->doc  : "...");
+                                       }
                                }
                        }
                        for (cword = TAILQ_FIRST(&words); cword != NULL;
index f96b9c57b4cbbb773c9f5551867983cb1d4ac56e..964c6bbe712302bd2696da3aba0bd37015b0d726 100644 (file)
@@ -331,6 +331,8 @@ register_commands()
                NEWLINE, "Update information and send LLDPU on all ports",
                NULL, cmd_update, NULL));
        register_commands_configure(root);
+       commands_hidden(commands_new(root, "complete", "Get possible completions from a given command",
+               NULL, cmd_store_env_and_pop, "complete"));
        commands_new(root, "help", "Get help on a possible command",
            NULL, cmd_store_env_and_pop, "help");
        commands_new(