diff options
author | Tiago Gomes <tiago.gomes@codethink.co.uk> | 2013-05-20 15:42:24 +0100 |
---|---|---|
committer | Tiago Gomes <tiago.gomes@codethink.co.uk> | 2013-05-20 15:42:24 +0100 |
commit | 304f215abb836811e6d78e0a3da53d48aa0e7ca7 (patch) | |
tree | efdecffd52c35757d962965f89805721a47e7fec /help.c | |
parent | aab0fcb8ae7386475598fd2bef887cf0f9f3b65a (diff) | |
parent | ad5f1f2d34cbb2f235ff3c1bc7dd28450759b2c7 (diff) | |
download | btrfs-progs-baserock/morph.tar.gz |
Merge branch 'baserock/tiagogomes/btrfs2' into baserock/morphbaserock/morph
Diffstat (limited to 'help.c')
-rw-r--r-- | help.c | 214 |
1 files changed, 214 insertions, 0 deletions
@@ -0,0 +1,214 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "commands.h" + +extern char argv0_buf[ARGV0_BUF_SIZE]; + +#define USAGE_SHORT 1U +#define USAGE_LONG 2U +#define USAGE_OPTIONS 4U +#define USAGE_LISTING 8U + +static int do_usage_one_command(const char * const *usagestr, + unsigned int flags, FILE *outf) +{ + int pad = 4; + + if (!usagestr || !*usagestr) + return -1; + + fprintf(outf, "%s%s\n", (flags & USAGE_LISTING) ? " " : "usage: ", + *usagestr++); + + /* a short one-line description (mandatory) */ + if ((flags & USAGE_SHORT) == 0) + return 0; + else if (!*usagestr) + return -2; + + if (flags & USAGE_LISTING) + pad = 8; + else + fputc('\n', outf); + + fprintf(outf, "%*s%s\n", pad, "", *usagestr++); + + /* a long (possibly multi-line) description (optional) */ + if (!*usagestr || ((flags & USAGE_LONG) == 0)) + return 0; + + if (**usagestr) + fputc('\n', outf); + while (*usagestr && **usagestr) + fprintf(outf, "%*s%s\n", pad, "", *usagestr++); + + /* options (optional) */ + if (!*usagestr || ((flags & USAGE_OPTIONS) == 0)) + return 0; + + /* + * options (if present) should always (even if there is no long + * description) be prepended with an empty line, skip it + */ + usagestr++; + + fputc('\n', outf); + while (*usagestr) + fprintf(outf, "%*s%s\n", pad, "", *usagestr++); + + return 0; +} + +static int usage_command_internal(const char * const *usagestr, + const char *token, int full, int lst, + FILE *outf) +{ + unsigned int flags = USAGE_SHORT; + int ret; + + if (full) + flags |= USAGE_LONG | USAGE_OPTIONS; + if (lst) + flags |= USAGE_LISTING; + + ret = do_usage_one_command(usagestr, flags, outf); + switch (ret) { + case -1: + fprintf(outf, "No usage for '%s'\n", token); + break; + case -2: + fprintf(outf, "No short description for '%s'\n", token); + break; + } + + return ret; +} + +static void usage_command_usagestr(const char * const *usagestr, + const char *token, int full, int err) +{ + FILE *outf = err ? stderr : stdout; + int ret; + + ret = usage_command_internal(usagestr, token, full, 0, outf); + if (!ret) + fputc('\n', outf); +} + +void usage_command(const struct cmd_struct *cmd, int full, int err) +{ + usage_command_usagestr(cmd->usagestr, cmd->token, full, err); +} + +void usage(const char * const *usagestr) +{ + usage_command_usagestr(usagestr, NULL, 1, 1); + exit(129); +} + +static void usage_command_group_internal(const struct cmd_group *grp, int full, + FILE *outf) +{ + const struct cmd_struct *cmd = grp->commands; + int do_sep = 0; + + for (; cmd->token; cmd++) { + if (cmd->hidden) + continue; + + if (full && cmd != grp->commands) + fputc('\n', outf); + + if (!cmd->next) { + if (do_sep) { + fputc('\n', outf); + do_sep = 0; + } + + usage_command_internal(cmd->usagestr, cmd->token, full, + 1, outf); + continue; + } + + /* this is an entry point to a nested command group */ + + if (!full && cmd != grp->commands) + fputc('\n', outf); + + usage_command_group_internal(cmd->next, full, outf); + + if (!full) + do_sep = 1; + } +} + +void usage_command_group(const struct cmd_group *grp, int full, int err) +{ + const char * const *usagestr = grp->usagestr; + FILE *outf = err ? stderr : stdout; + + if (usagestr && *usagestr) { + fprintf(outf, "usage: %s\n", *usagestr++); + while (*usagestr) + fprintf(outf, " or: %s\n", *usagestr++); + } + + fputc('\n', outf); + usage_command_group_internal(grp, full, outf); + fputc('\n', outf); + + if (grp->infostr) + fprintf(outf, "%s\n", grp->infostr); +} + +void help_unknown_token(const char *arg, const struct cmd_group *grp) +{ + fprintf(stderr, "%s: unknown token '%s'\n", argv0_buf, arg); + usage_command_group(grp, 0, 1); + exit(1); +} + +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, "\nDid you mean one of these ?\n"); + + for (; cmd->token; cmd++) { + if (!prefixcmp(cmd->token, arg)) + fprintf(stderr, "\t%s\n", cmd->token); + } + + exit(1); +} + +void help_command_group(const struct cmd_group *grp, int argc, char **argv) +{ + int full = 0; + + if (argc > 1) { + if (!strcmp(argv[1], "--full")) + full = 1; + } + + usage_command_group(grp, full, 0); +} |