X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=help.c;h=f1dd39460bc63b3741e449fea13bbd7e4bc03a51;hb=43dea2af140fe21111e7ce8491cad2724d73b2d4;hp=6d042931830f7cca221ebaa651c0f962e3ea4378;hpb=f01d6a8cc87e8aad49416e57290138d7bf18434a;p=platform%2Fupstream%2Fbtrfs-progs.git diff --git a/help.c b/help.c index 6d04293..f1dd394 100644 --- a/help.c +++ b/help.c @@ -17,32 +17,150 @@ #include #include #include +#include +#include #include "commands.h" - -extern char argv0_buf[ARGV0_BUF_SIZE]; +#include "utils.h" +#include "help.h" #define USAGE_SHORT 1U #define USAGE_LONG 2U #define USAGE_OPTIONS 4U #define USAGE_LISTING 8U +static char argv0_buf[ARGV0_BUF_SIZE] = "btrfs"; + +const char *get_argv0_buf(void) +{ + return argv0_buf; +} + +void fixup_argv0(char **argv, const char *token) +{ + int len = strlen(argv0_buf); + + snprintf(argv0_buf + len, sizeof(argv0_buf) - len, " %s", token); + argv[0] = argv0_buf; +} + +void set_argv0(char **argv) +{ + strncpy(argv0_buf, argv[0], sizeof(argv0_buf)); + argv0_buf[sizeof(argv0_buf) - 1] = 0; +} + +int check_argc_exact(int nargs, int expected) +{ + if (nargs < expected) + fprintf(stderr, "%s: too few arguments\n", argv0_buf); + if (nargs > expected) + fprintf(stderr, "%s: too many arguments\n", argv0_buf); + + return nargs != expected; +} + +int check_argc_min(int nargs, int expected) +{ + if (nargs < expected) { + fprintf(stderr, "%s: too few arguments\n", argv0_buf); + return 1; + } + + return 0; +} + +int check_argc_max(int nargs, int expected) +{ + if (nargs > expected) { + fprintf(stderr, "%s: too many arguments\n", argv0_buf); + return 1; + } + + return 0; +} + +/* + * Preprocess @argv with getopt_long to reorder options and consume the "--" + * option separator. + * Unknown short and long options are reported, optionally the @usage is printed + * before exit. + */ +void clean_args_no_options(int argc, char *argv[], const char * const *usagestr) +{ + static const struct option long_options[] = { + {NULL, 0, NULL, 0} + }; + + while (1) { + int c = getopt_long(argc, argv, "", long_options, NULL); + + if (c < 0) + break; + + switch (c) { + default: + if (usagestr) + usage(usagestr); + } + } +} + +/* + * Same as clean_args_no_options but pass through arguments that could look + * like short options. Eg. reisze which takes a negative resize argument like + * '-123M' . + * + * This accepts only two forms: + * - "-- option1 option2 ..." + * - "option1 option2 ..." + */ +void clean_args_no_options_relaxed(int argc, char *argv[]) +{ + if (argc <= 1) + return; + + if (strcmp(argv[1], "--") == 0) + optind = 2; +} + static int do_usage_one_command(const char * const *usagestr, unsigned int flags, FILE *outf) { int pad = 4; + const char *prefix = "usage: "; + const char *pad_listing = " "; if (!usagestr || !*usagestr) return -1; - fprintf(outf, "%s%s\n", (flags & USAGE_LISTING) ? " " : "usage: ", - *usagestr++); + if (flags & USAGE_LISTING) + prefix = pad_listing; + + fputs(prefix, outf); + if (strchr(*usagestr, '\n') == NULL) { + fputs(*usagestr, outf); + } else { + const char *c = *usagestr; + const char *nprefix = " "; + + if (flags & USAGE_LISTING) + nprefix = pad_listing; + + for (c = *usagestr; *c; c++) { + fputc(*c, outf); + if (*c == '\n') + fputs(nprefix, outf); + } + } + usagestr++; /* a short one-line description (mandatory) */ if ((flags & USAGE_SHORT) == 0) return 0; else if (!*usagestr) return -2; + fputc('\n', outf); if (flags & USAGE_LISTING) pad = 8; @@ -79,11 +197,13 @@ static int do_usage_one_command(const char * const *usagestr, static int usage_command_internal(const char * const *usagestr, const char *token, int full, int lst, - FILE *outf) + int alias, FILE *outf) { - unsigned int flags = USAGE_SHORT; + unsigned int flags = 0; int ret; + if (!alias) + flags |= USAGE_SHORT; if (full) flags |= USAGE_LONG | USAGE_OPTIONS; if (lst) @@ -108,7 +228,7 @@ static void usage_command_usagestr(const char * const *usagestr, FILE *outf = err ? stderr : stdout; int ret; - ret = usage_command_internal(usagestr, token, full, 0, outf); + ret = usage_command_internal(usagestr, token, full, 0, 0, outf); if (!ret) fputc('\n', outf); } @@ -118,10 +238,11 @@ void usage_command(const struct cmd_struct *cmd, int full, int err) usage_command_usagestr(cmd->usagestr, cmd->token, full, err); } +__attribute__((noreturn)) void usage(const char * const *usagestr) { usage_command_usagestr(usagestr, NULL, 1, 1); - exit(129); + exit(1); } static void usage_command_group_internal(const struct cmd_group *grp, int full, @@ -131,7 +252,7 @@ static void usage_command_group_internal(const struct cmd_group *grp, int full, int do_sep = 0; for (; cmd->token; cmd++) { - if (cmd->hidden) + if (cmd->flags & CMD_HIDDEN) continue; if (full && cmd != grp->commands) @@ -144,7 +265,9 @@ static void usage_command_group_internal(const struct cmd_group *grp, int full, } usage_command_internal(cmd->usagestr, cmd->token, full, - 1, outf); + 1, cmd->flags & CMD_ALIAS, outf); + if (cmd->flags & CMD_ALIAS) + putchar('\n'); continue; } @@ -160,6 +283,50 @@ static void usage_command_group_internal(const struct cmd_group *grp, int full, } } +void usage_command_group_short(const struct cmd_group *grp) +{ + const char * const *usagestr = grp->usagestr; + FILE *outf = stdout; + const struct cmd_struct *cmd; + + if (usagestr && *usagestr) { + fprintf(outf, "usage: %s\n", *usagestr++); + while (*usagestr) + fprintf(outf, " or: %s\n", *usagestr++); + } + + fputc('\n', outf); + + fprintf(outf, "Command groups:\n"); + for (cmd = grp->commands; cmd->token; cmd++) { + if (cmd->flags & CMD_HIDDEN) + continue; + + if (!cmd->next) + continue; + + fprintf(outf, " %-16s %s\n", cmd->token, cmd->next->infostr); + } + + fprintf(outf, "\nCommands:\n"); + for (cmd = grp->commands; cmd->token; cmd++) { + if (cmd->flags & CMD_HIDDEN) + continue; + + if (cmd->next) + continue; + + fprintf(outf, " %-16s %s\n", cmd->token, cmd->usagestr[1]); + } + + fputc('\n', outf); + fprintf(stderr, "For an overview of a given command use 'btrfs command --help'\n"); + fprintf(stderr, "or 'btrfs [command...] --help --full' to print all available options.\n"); + fprintf(stderr, "Any command name can be shortened as far as it stays unambiguous,\n"); + fprintf(stderr, "however it is recommended to use full command names in scripts.\n"); + fprintf(stderr, "All command groups have their manual page named 'btrfs-'.\n"); +} + void usage_command_group(const struct cmd_group *grp, int full, int err) { const char * const *usagestr = grp->usagestr; @@ -179,18 +346,20 @@ void usage_command_group(const struct cmd_group *grp, int full, int err) fprintf(outf, "%s\n", grp->infostr); } +__attribute__((noreturn)) void help_unknown_token(const char *arg, const struct cmd_group *grp) { - fprintf(stderr, "%s: unknown token '%s'\n", argv0_buf, arg); + fprintf(stderr, "%s: unknown token '%s'\n", get_argv0_buf(), arg); usage_command_group(grp, 0, 1); exit(1); } +__attribute__((noreturn)) void help_ambiguous_token(const char *arg, const struct cmd_group *grp) { const struct cmd_struct *cmd = grp->commands; - fprintf(stderr, "%s: ambiguous token '%s'\n", argv0_buf, arg); + fprintf(stderr, "%s: ambiguous token '%s'\n", get_argv0_buf(), arg); fprintf(stderr, "\nDid you mean one of these ?\n"); for (; cmd->token; cmd++) { @@ -212,3 +381,4 @@ void help_command_group(const struct cmd_group *grp, int argc, char **argv) usage_command_group(grp, full, 0); } +