From 74b7b948229af1a12938d06b1ec892562a2a573e Mon Sep 17 00:00:00 2001 From: Michael Meffie Date: Fri, 4 Apr 2014 10:27:10 -0400 Subject: [PATCH] cmd: improve help for programs without subcommands Some programs do not have subcommands (other than the standard "help", and "version" subcommands). The cmd library provides the "noopcode" mechanism for new subcommand-less programs, but older programs take advantage of the optional "initcmd" token to simulate subcommand-less programs. The "initcmd" token is optional to run the command, however it is required to display the command help. For example, running the xstat_cm_test program without any options gives a syntax error: $ xstat_cm_test xstat_cm_test: Missing required parameter '-cmname' ... Retrying with -help (or help, -h, --help), gives the rather unhelpful output: $ xstat_cm_test -help xstat_cm_test: Commands are: apropos search by help text help get help on commands initcmd initialize the program It is not obvious to the user how to get the command usage for the program, nor that the initcmd subcommand to "initialize the program" is actually is a placeholder to run the program. Instead, display the command usage when help is requested and initcmd is the only defined subcommand for a program. For example: $ xstat_cm_test -help Usage: src/xstat/xstat_cm_test [initcmd] -cmname + -collID + [-onceonly] [-frequency ] [-period ] [-debug] [-help] Where: -onceonly Collect results exactly once, then quit -debug turn on debugging output The libcmd library now supports an "noopcode", which should used for future subcommand-less programs, but converting old programs to remove the initcmd opcode could break scripts which actually specify the optional initcmd token. This commit adds a new libcmd flag called CMD_IMPLICIT which is used to denote built-in subcommands such as "version" and "help". Reviewed-on: https://gerrit.openafs.org/10983 Reviewed-by: Michael Meffie Tested-by: BuildBot Reviewed-by: Benjamin Kaduk (cherry picked from commit 77ae3dc899e89f327328c874628f100a765846c4) Change-Id: I5b31f12f844f14e6cf31ee28c1eb60c98fcf4b59 Reviewed-on: https://gerrit.openafs.org/13894 Reviewed-by: Andrew Deason Reviewed-by: Michael Meffie Reviewed-by: Cheyenne Wills Reviewed-by: Mark Vitale Reviewed-by: Marcio Brito Barbosa Tested-by: BuildBot Reviewed-by: Stephan Wiesand --- src/cmd/cmd.c | 48 ++++++++++++++++++++++++++++++++++++------------ src/cmd/cmd.p.h | 1 + 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/cmd/cmd.c b/src/cmd/cmd.c index e2e8e3a08..ffe49aa74 100644 --- a/src/cmd/cmd.c +++ b/src/cmd/cmd.c @@ -357,11 +357,35 @@ HelpProc(struct cmd_syndesc *as, void *arock) int code = 0; if (as->parms[0].items == 0) { - printf("%sCommands are:\n", NName(as->a0name, ": ")); + struct cmd_syndesc *initcmd = NULL; + int count = 0; + + /* + * Print the usage of the initcmd command when it is the only + * non-hidden, explicit command, otherwise, list the all the commands. + */ for (ts = allSyntax; ts; ts = ts->next) { - if ((ts->flags & CMD_ALIAS) || (ts->flags & CMD_HIDDEN)) + if (ts->flags & (CMD_ALIAS | CMD_HIDDEN | CMD_IMPLICIT)) { + continue; /* skip aliases, hidden, and implied commands */ + } + if (strcmp(ts->name, initcmd_opcode) == 0) { + initcmd = ts; /* save the initcmd */ continue; - printf("%-15s %s\n", ts->name, (ts->help ? ts->help : "")); + } + count++; + } + if (initcmd && count == 0) { + initcmd->a0name = as->a0name; + PrintAliases(initcmd); + PrintSyntax(initcmd); + PrintFlagHelp(initcmd); + } else { + printf("%sCommands are:\n", NName(as->a0name, ": ")); + for (ts = allSyntax; ts; ts = ts->next) { + if ((ts->flags & CMD_ALIAS) || (ts->flags & CMD_HIDDEN)) + continue; + printf("%-15s %s\n", ts->name, (ts->help ? ts->help : "")); + } } } else { /* print out individual help topics */ @@ -439,7 +463,7 @@ SortSyntax(struct cmd_syndesc *as) * \param[in] aname name used to invoke the command * \param[in] aproc procedure to be called when command is invoked * \param[in] arock opaque data pointer to be passed to aproc - * \param[in] aflags command option flags (CMD_HIDDEN) + * \param[in] aflags command option flags * \param[in] ahelp help string to display for this command * * \return a pointer to the cmd_syndesc or NULL if error. @@ -456,7 +480,7 @@ cmd_CreateSyntax(char *aname, return NULL; /* Allow only valid cmd flags. */ - if (aflags & ~CMD_HIDDEN) { + if (aflags & ~(CMD_HIDDEN | CMD_IMPLICIT)) { return NULL; } @@ -763,20 +787,20 @@ initSyntax(void) struct cmd_syndesc *ts; if (!noOpcodes) { - ts = cmd_CreateSyntax("help", HelpProc, NULL, 0, + ts = cmd_CreateSyntax("help", HelpProc, NULL, CMD_IMPLICIT, "get help on commands"); cmd_AddParm(ts, "-topic", CMD_LIST, CMD_OPTIONAL, "help string"); - ts = cmd_CreateSyntax("apropos", AproposProc, NULL, 0, + ts = cmd_CreateSyntax("apropos", AproposProc, NULL, CMD_IMPLICIT, "search by help text"); cmd_AddParm(ts, "-topic", CMD_SINGLE, CMD_REQUIRED, "help string"); - cmd_CreateSyntax("version", VersionProc, NULL, 0, + cmd_CreateSyntax("version", VersionProc, NULL, CMD_IMPLICIT, "show version"); - cmd_CreateSyntax("-version", VersionProc, NULL, CMD_HIDDEN, NULL); - cmd_CreateSyntax("-help", HelpProc, NULL, CMD_HIDDEN, NULL); - cmd_CreateSyntax("--version", VersionProc, NULL, CMD_HIDDEN, NULL); - cmd_CreateSyntax("--help", HelpProc, NULL, CMD_HIDDEN, NULL); + cmd_CreateSyntax("-version", VersionProc, NULL, (CMD_HIDDEN | CMD_IMPLICIT), NULL); + cmd_CreateSyntax("-help", HelpProc, NULL, (CMD_HIDDEN | CMD_IMPLICIT), NULL); + cmd_CreateSyntax("--version", VersionProc, NULL, (CMD_HIDDEN | CMD_IMPLICIT), NULL); + cmd_CreateSyntax("--help", HelpProc, NULL, (CMD_HIDDEN | CMD_IMPLICIT), NULL); } } diff --git a/src/cmd/cmd.p.h b/src/cmd/cmd.p.h index 4a5f3031a..30ce7d127 100644 --- a/src/cmd/cmd.p.h +++ b/src/cmd/cmd.p.h @@ -19,6 +19,7 @@ /* syndesc flags */ #define CMD_ALIAS 1 /* this is an alias */ #define CMD_HIDDEN 4 /* A hidden command - similar to CMD_HIDE */ +#define CMD_IMPLICIT 8 /* A built-in command - apropos, help, version (and variations) */ #define CMD_HELPPARM (CMD_MAXPARMS-1) /* last one is used by -help switch */ #define CMD_MAXPARMS 64 /* max number of parm types to a cmd line */ -- 2.39.5