]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
bind '?' to inline help
authorAlan T. DeKok <aland@freeradius.org>
Thu, 12 Jul 2018 17:41:50 +0000 (13:41 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Thu, 12 Jul 2018 17:41:50 +0000 (13:41 -0400)
src/include/command.h
src/main/command.c
src/main/radmin.c

index 7d49126fd5a14c3e8fe92a8ce2c3ac59136fb304..bdc55bdcb3be2edb06e2944c6a54fefce69437c0 100644 (file)
@@ -89,6 +89,7 @@ void fr_command_info_init(TALLOC_CTX *ctx, fr_cmd_info_t *info);
 
 int fr_command_complete(fr_cmd_t *head, char const *text, int start,
                        int max_expansions, char **expansions);
+int fr_command_print_help(FILE *fp, fr_cmd_t *head, char const *text);
 
 #ifdef __cplusplus
 }
index f468feaf85618cf1fb592327c73d41806eb91946..636d68b41559e29dbcf32746c28b18fae8782e0b 100644 (file)
@@ -2112,6 +2112,9 @@ static int expand_syntax(fr_cmd_argv_t *argv, char const *text, int start, char
  * @param start offset in the text where the completions should start
  * @param max_expansions how many entries in the "expansions" array.
  * @param[in,out] expansions where the expansions are stored.
+ * @return
+ *     - <0 on error
+ *     - >= 0 number of expansions in the array
  */
 int fr_command_complete(fr_cmd_t *head, char const *text, int start,
                        int max_expansions, char **expansions)
@@ -2201,3 +2204,90 @@ int fr_command_complete(fr_cmd_t *head, char const *text, int start,
 
        return expand_syntax(cmd->syntax_argv, text, start, &word, count, max_expansions, expansions);
 }
+
+/** Do readline-style command completions
+ *
+ *  Most useful as part of readline tab expansions.  The expansions
+ *  are strdup() strings, and MUST be free'd by the caller.
+ *
+ * @param head of the command tree
+ * @param text the text to check
+ */
+int fr_command_print_help(FILE *fp, fr_cmd_t *head, char const *text)
+{
+       char const *word, *p, *q;
+       fr_cmd_t *cmd;
+
+       cmd = head;
+       word = text;
+
+       /*
+        *      Try to do this without mangling "text".
+        */
+       while (cmd) {
+               while (isspace((int) *word)) word++;
+
+               /*
+                *      End of the input.  Tab expand everything here.
+                */
+               if (!*word) {
+                       while (cmd) {
+                               if (!cmd->help) {
+                                       fprintf(fp, "%s\n", cmd->name);
+                               } else {
+                                       fprintf(fp, "%-30s%s\n", cmd->name, cmd->help);
+                               }
+                               cmd = cmd->next;
+                       }
+                       return 0;
+               }
+
+               /*
+                *      Try to find a matching cmd->name
+                */
+               p = word;
+               q = cmd->name;
+
+               while (*p == *q) {
+                       p++;
+                       q++;
+               }
+
+               /*
+                *      The only matching exit condition is *p is a
+                *      space, and *q is the NUL character.
+                */
+               if (!(isspace((int) *p) && !*q)) {
+                       cmd = cmd->next;
+                       continue;
+               }
+
+               if (cmd->intermediate) {
+                       rad_assert(cmd->child != NULL);
+                       word = p;
+                       cmd = cmd->child;
+                       continue;
+               }
+
+               /*
+                *      Skip the command name we matched.
+                */
+               word = p;
+               break;
+       }
+
+       /*
+        *      No match, can't do anything.
+        */
+       if (!cmd) {
+               return 0;
+       }
+
+       if (!cmd->help) {
+               fprintf(fp, "%s\n", cmd->name);
+       } else {
+               fprintf(fp, "%-30s%s\n", cmd->name, cmd->help);
+       }
+
+       return 0;
+}
index b9f234998cf3dd32a6a0b48724844c2e2eaa442f..0c5f12488c1fdcdcf8a6ccb21229769d1458c197 100644 (file)
@@ -137,6 +137,7 @@ static char *radmin_buffer = NULL;
 static int cmd_help(FILE *fp, FILE *fp_err, void *ctx, fr_cmd_info_t const *info);
 static int cmd_exit(FILE *fp, FILE *fp_err, UNUSED void *ctx, fr_cmd_info_t const *info);
 
+#ifdef USE_READLINE
 /*
  *     Global variables because readline() is stupid.
  */
@@ -184,6 +185,27 @@ radmin_completion(const char *text, int start, UNUSED int end)
        return rl_completion_matches(text, radmin_expansion_walk);
 }
 
+static int radmin_help(UNUSED int count, UNUSED int key)
+{
+       char buffer[8192];
+
+       printf("\n");
+
+       /*
+        *      @todo make this not retarded.
+        */
+       strlcpy(buffer, radmin_buffer, sizeof(buffer));
+       strlcat(buffer, " ", sizeof(buffer));
+       strlcat(buffer, rl_line_buffer, sizeof(buffer));
+
+       (void) fr_command_print_help(stdout, radmin_cmd, buffer);
+       rl_on_new_line();
+       return 0;
+}
+
+#endif /* USE_READLINE */
+
+
 static void *fr_radmin(UNUSED void *input_ctx)
 {
        int argc;
@@ -201,8 +223,8 @@ static void *fr_radmin(UNUSED void *input_ctx)
        ctx = talloc_init("radmin");
 
        size = room = 8192;
-       radmin_buffer = talloc_array(ctx, char, size);
-       argv_buffer = talloc_array(ctx, char, size);
+       radmin_buffer = talloc_zero_array(ctx, char, size);
+       argv_buffer = talloc_zero_array(ctx, char, size);
        current_str = argv_buffer;
 
        fr_command_info_init(ctx, info);
@@ -213,8 +235,12 @@ static void *fr_radmin(UNUSED void *input_ctx)
 
        fflush(stdout);
 
+#ifdef USE_READLINE
        rl_attempted_completion_function = radmin_completion;
 
+       (void) rl_bind_key('?', radmin_help);
+#endif
+
        while (true) {
                char *line;