diff --git a/cli.c b/cli.c index 70d4f943..5ed6a739 100644 --- a/cli.c +++ b/cli.c @@ -4,19 +4,47 @@ #include "log.h" #include "serval.h" #include "rhizome.h" +#include "strbuf_helpers.h" -int cli_usage(const struct cli_schema *commands) { - printf("Usage:\n"); +int cli_usage(const struct cli_schema *commands, XPRINTF xpf) +{ + return cli_usage_args(0, NULL, commands, xpf); +} + +int cli_usage_parsed(const struct cli_parsed *parsed, XPRINTF xpf) +{ + if (parsed->varargi == -1) + return cli_usage(parsed->commands, xpf); + return cli_usage_args(parsed->argc - parsed->varargi, &parsed->args[parsed->varargi], parsed->commands, xpf); +} + +int cli_usage_args(const int argc, const char *const *args, const struct cli_schema *commands, XPRINTF xpf) +{ unsigned cmd; + int matched_any = 0; for (cmd = 0; commands[cmd].function; ++cmd) { unsigned opt; const char *word; - for (opt = 0; (word = commands[cmd].words[opt]); ++opt) { - if (word[0] == '\\') - ++word; - printf(" %s", word); + int matched = 1; + for (opt = 0; matched && opt < argc && (word = commands[cmd].words[opt]); ++opt) + if (strncmp(word, args[opt], strlen(args[opt])) != 0) + matched = 0; + if (matched) { + matched_any = 1; + for (opt = 0; (word = commands[cmd].words[opt]); ++opt) { + if (word[0] == '\\') + ++word; + xprintf(xpf, " %s", word); + } + xputc('\n', xpf); + if (commands[cmd].description && commands[cmd].description[0]) + xprintf(xpf, " %s\n", commands[cmd].description); } - printf("\n %s\n",commands[cmd].description); + } + if (!matched_any && argc) { + strbuf b = strbuf_alloca(160); + strbuf_append_argv(b, argc, args); + xprintf(xpf, " No commands matching %s\n", strbuf_str(b)); } return 0; } @@ -29,7 +57,8 @@ int cli_parse(const int argc, const char *const *args, const struct cli_schema * for (cmd = 0; commands[cmd].function; ++cmd) { struct cli_parsed cmdpa; memset(&cmdpa, 0, sizeof cmdpa); - cmdpa.command = &commands[cmd]; + cmdpa.commands = commands; + cmdpa.cmdi = cmd; cmdpa.args = args; cmdpa.argc = argc; cmdpa.labelc = 0; @@ -202,7 +231,7 @@ void _debug_cli_parsed(struct __sourceloc __whence, const struct cli_parsed *par int cli_invoke(const struct cli_parsed *parsed, void *context) { IN(); - int ret = parsed->command->function(parsed, context); + int ret = parsed->commands[parsed->cmdi].function(parsed, context); RETURN(ret); OUT(); } diff --git a/cli.h b/cli.h index cf17c824..caeb8fe2 100644 --- a/cli.h +++ b/cli.h @@ -20,6 +20,7 @@ #ifndef __SERVALD_CLI_H #define __SERVALD_CLI_H +#include "xprintf.h" #include "log.h" #define COMMAND_LINE_MAX_LABELS (32) @@ -37,7 +38,8 @@ struct cli_schema { }; struct cli_parsed { - const struct cli_schema *command; + const struct cli_schema *commands; + unsigned int cmdi; struct labelv { const char *label; unsigned int len; @@ -53,7 +55,9 @@ void _debug_cli_parsed(struct __sourceloc __whence, const struct cli_parsed *par #define DEBUG_cli_parsed(parsed) _debug_cli_parsed(__WHENCE__, parsed) -int cli_usage(const struct cli_schema *commands); +int cli_usage(const struct cli_schema *commands, XPRINTF xpf); +int cli_usage_args(const int argc, const char *const *args, const struct cli_schema *commands, XPRINTF xpf); +int cli_usage_parsed(const struct cli_parsed *parsed, XPRINTF xpf); int cli_parse(const int argc, const char *const *args, const struct cli_schema *commands, struct cli_parsed *parsed); int cli_invoke(const struct cli_parsed *parsed, void *context); int _cli_arg(struct __sourceloc __whence, const struct cli_parsed *parsed, char *label, const char **dst, int (*validator)(const char *arg), char *defaultvalue); diff --git a/commandline.c b/commandline.c index b4a0e0ed..7d437328 100644 --- a/commandline.c +++ b/commandline.c @@ -49,8 +49,8 @@ extern struct cli_schema command_line_options[]; int commandline_usage(const struct cli_parsed *parsed, void *context) { - printf("Serval DNA version %s\n", version_servald); - return cli_usage(command_line_options); + printf("Serval DNA version %s\nUsage:\n", version_servald); + return cli_usage_parsed(parsed, XPRINTF_STDIO(stdout)); } /* Data structures for accumulating output of a single JNI call. @@ -225,7 +225,7 @@ int parseCommandLine(const char *argv0, int argc, const char *const *args) int result = cli_parse(argc, args, command_line_options, &parsed); if (result != -1) { // Do not run the command if the configuration does not load ok - if (((parsed.command->flags & CLIFLAG_PERMISSIVE_CONFIG) ? cf_reload_permissive() : cf_reload()) != -1) + if (((parsed.commands[parsed.cmdi].flags & CLIFLAG_PERMISSIVE_CONFIG) ? cf_reload_permissive() : cf_reload()) != -1) result = cli_invoke(&parsed, NULL); else { strbuf b = strbuf_alloca(160); @@ -2354,7 +2354,7 @@ int app_network_scan(const struct cli_parsed *parsed, void *context) struct cli_schema command_line_options[]={ {app_dna_lookup,{"dna","lookup","","[]",NULL},0, "Lookup the SIP/MDP address of the supplied telephone number (DID)."}, - {commandline_usage,{"help",NULL},CLIFLAG_PERMISSIVE_CONFIG, + {commandline_usage,{"help","...",NULL},CLIFLAG_PERMISSIVE_CONFIG, "Display command usage."}, {app_echo,{"echo","[-e]","[--]","...",NULL},CLIFLAG_STANDALONE, "Output the supplied string."}, diff --git a/monitor.c b/monitor.c index b576800a..138ccab9 100644 --- a/monitor.c +++ b/monitor.c @@ -576,17 +576,7 @@ static int monitor_help(const struct cli_parsed *parsed, void *context) struct monitor_context *c=context; strbuf b = strbuf_alloca(16384); strbuf_puts(b, "\nINFO:Usage\n"); - unsigned cmd; - for (cmd = 0; monitor_commands[cmd].function; ++cmd) { - unsigned opt; - const char *word; - for (opt = 0; (word = monitor_commands[cmd].words[opt]); ++opt) { - if (word[0] == '\\') - ++word; - strbuf_sprintf(b, " %s", word); - } - strbuf_puts(b, "\n"); - } + cli_usage(monitor_commands, XPRINTF_STRBUF(b)); (void)write_all(c->alarm.poll.fd, strbuf_str(b), strbuf_len(b)); return 0; } diff --git a/vomp_console.c b/vomp_console.c index 63a7dd95..c563d626 100644 --- a/vomp_console.c +++ b/vomp_console.c @@ -256,7 +256,7 @@ struct cli_schema console_commands[]={ static int console_usage(const struct cli_parsed *parsed, void *context) { - cli_usage(console_commands); + cli_usage(console_commands, XPRINTF_STDIO(stdout)); fflush(stdout); return 0; }