From: Alan T. DeKok Date: Thu, 12 Jul 2018 17:41:50 +0000 (-0400) Subject: bind '?' to inline help X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=954d7e774cc72fb814d090b4e766ac6ed5498763;p=thirdparty%2Ffreeradius-server.git bind '?' to inline help --- diff --git a/src/include/command.h b/src/include/command.h index 7d49126fd5a..bdc55bdcb3b 100644 --- a/src/include/command.h +++ b/src/include/command.h @@ -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 } diff --git a/src/main/command.c b/src/main/command.c index f468feaf856..636d68b4155 100644 --- a/src/main/command.c +++ b/src/main/command.c @@ -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; +} diff --git a/src/main/radmin.c b/src/main/radmin.c index b9f234998cf..0c5f12488c1 100644 --- a/src/main/radmin.c +++ b/src/main/radmin.c @@ -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;