From: Alan T. DeKok Date: Sun, 8 Jul 2018 13:23:28 +0000 (-0400) Subject: print out only one layer of help at a time X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ea5d53d38b9b02046ec7b780d66fe0806cf54edc;p=thirdparty%2Ffreeradius-server.git print out only one layer of help at a time --- diff --git a/src/include/command.h b/src/include/command.h index c5eb39875c3..92fab6dc530 100644 --- a/src/include/command.h +++ b/src/include/command.h @@ -39,6 +39,7 @@ typedef struct fr_cmd_info_t { bool runnable; //!< is the command runnable? char **argv; //!< text version of commands fr_value_box_t **box; //!< value_box version of commands. + fr_cmd_t **cmd; //!< cached commands at each offset } fr_cmd_info_t; typedef int (*fr_cmd_func_t)(FILE *fp, FILE *fp_err, void *ctx, fr_cmd_info_t const *info); @@ -73,7 +74,7 @@ int fr_command_tab_expand(TALLOC_CTX *ctx, fr_cmd_t *head, fr_cmd_info_t *info, char const *fr_command_help(fr_cmd_t *head, int argc, char *argv[]); int fr_command_run(FILE *fp, FILE *fp_err, fr_cmd_t *head, fr_cmd_info_t *info); void fr_command_debug(FILE *fp, fr_cmd_t *head); -void fr_command_list(FILE *fp, fr_cmd_t *head); +void fr_command_list(FILE *fp, int max_depth, fr_cmd_t *head, bool is_head); int fr_command_str_to_argv(fr_cmd_t *head, fr_cmd_info_t *info, char *str); #ifdef __cplusplus diff --git a/src/main/command.c b/src/main/command.c index d440473f891..1a6c7d8cc4d 100644 --- a/src/main/command.c +++ b/src/main/command.c @@ -1482,25 +1482,33 @@ static void fr_command_list_node(FILE *fp, fr_cmd_t *cmd, int depth, char const } } -static void fr_command_list_internal(FILE *fp, fr_cmd_t *head, int depth, char const **argv) +static void fr_command_list_internal(FILE *fp, fr_cmd_t *head, int depth, int max_depth, char const **argv) { fr_cmd_t *cmd; for (cmd = head; cmd != NULL; cmd = cmd->next) { - if (cmd->child) { + if (cmd->child && ((depth + 1) < max_depth)) { argv[depth] = cmd->name; - fr_command_list_internal(fp, cmd->child, depth + 1, argv); + fr_command_list_internal(fp, cmd->child, depth + 1, max_depth, argv); } else { fr_command_list_node(fp, cmd, depth, argv); } } } -void fr_command_list(FILE *fp, fr_cmd_t *head) +void fr_command_list(FILE *fp, int max_depth, fr_cmd_t *head, bool is_head) { char const *argv[CMD_MAX_ARGV]; - fr_command_list_internal(fp, head, 0, argv); + if ((max_depth <= 0) || !head) return; + if (max_depth > CMD_MAX_ARGV) max_depth = CMD_MAX_ARGV; + + if (!is_head) { + if (!head->child) return; + head = head->child; + } + + fr_command_list_internal(fp, head, 0, max_depth, argv); } @@ -1709,7 +1717,7 @@ int fr_command_str_to_argv(fr_cmd_t *head, fr_cmd_info_t *info, char *str) fr_cmd_t *cmd, *start; fr_cmd_argv_t *argv; - if ((info->argc < 0) || (info->max_argc <= 0) || !str) { + if ((info->argc < 0) || (info->max_argc <= 0) || !str || !head) { fr_strerror_printf("Invalid arguments passed to parse routine."); return -1; } @@ -1761,6 +1769,11 @@ int fr_command_str_to_argv(fr_cmd_t *head, fr_cmd_info_t *info, char *str) return -1; } + /* + * Cache the command for later consumption. + */ + if (info->cmd) info->cmd[i] = cmd; + /* * There's a child. Go match it. */ diff --git a/src/main/radmin.c b/src/main/radmin.c index 2f10d0e59c4..bcf8ff67b67 100644 --- a/src/main/radmin.c +++ b/src/main/radmin.c @@ -54,7 +54,7 @@ RCSID("$Id$") static pthread_t pthread_id; static bool stop = false; -static int context = 0; +static int context; static fr_cmd_info_t radmin_info; #ifndef USE_READLINE @@ -133,6 +133,7 @@ static fr_cmd_t *radmin_cmd = NULL; #define CMD_MAX_ARGV (32) static int cmd_help(FILE *fp, FILE *fp_err, UNUSED 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); static void *fr_radmin(UNUSED void *input_ctx) { @@ -192,6 +193,15 @@ static void *fr_radmin(UNUSED void *input_ctx) goto next; } + /* + * Special-case "quit", which works everywhere. + * It closes the CLI immediately. + */ + if (strcmp(line, "quit") == 0) { + cmd_exit(stdout, stderr, NULL, info); + goto next; + } + /* * Allow exiting from the current context. */ @@ -326,18 +336,33 @@ static int cmd_exit(UNUSED FILE *fp, UNUSED FILE *fp_err, UNUSED void *ctx, UNUS static int cmd_help(FILE *fp, UNUSED FILE *fp_err, UNUSED void *ctx, fr_cmd_info_t const *info) { - char const *help; +// char const *help; if (info->argc == 0) { - fr_command_list(fp, radmin_cmd); - return 0; + /* + * List only the top-level commands + */ + if (radmin_info.argc == 1) { + fr_command_list(fp, 1, radmin_cmd, true); + return 0; + } + } + /* + * List the current command, but it's children instead of + * itself. + */ + fr_command_list(fp, 1, radmin_info.cmd[radmin_info.argc - 1], false); + +#if 0 + // @todo - print out actual help from the above commands help = fr_command_help(radmin_cmd, info->argc, info->argv); if (help) { fprintf(fp, "%s\n", help); return 0; } +#endif return 0; } @@ -420,7 +445,14 @@ static fr_cmd_table_t cmd_table[] = { { .syntax = "exit", .func = cmd_exit, - .help = "Tell the server to exit immediately.", + .help = "Exit from the current context.", + .read_only = false + }, + + { + .syntax = "quit", + .func = cmd_exit, + .help = "Quit and close the command line immediately.", .read_only = false },