diff options
author | Edward Thomson <ethomson@edwardthomson.com> | 2021-11-26 09:37:29 -0500 |
---|---|---|
committer | Edward Thomson <ethomson@edwardthomson.com> | 2021-11-29 08:16:18 -0500 |
commit | e1ae135b27871e8fd8e87b3888fce63cfdc5a062 (patch) | |
tree | 0c456df4f204d048b941c7511b9a83474a52c985 | |
parent | 19d5d6ce16d75f778b93515c503c7bdf37b9fee5 (diff) | |
download | libgit2-e1ae135b27871e8fd8e87b3888fce63cfdc5a062.tar.gz |
opt: use a custom function to print usage
Our argument parser (https://github.com/ethomson/adopt) includes a
function to print a usage message based on the allowed options. Omit
this and use a cutom function that understands that we have subcommands
("checkout", "revert", etc) that each have their own options.
-rw-r--r-- | src/cli/cli.h | 1 | ||||
-rw-r--r-- | src/cli/main.c | 2 | ||||
-rw-r--r-- | src/cli/opt.c | 66 | ||||
-rw-r--r-- | src/cli/opt.h | 15 | ||||
-rw-r--r-- | src/cli/opt_usage.c | 125 | ||||
-rw-r--r-- | src/cli/opt_usage.h | 26 |
6 files changed, 155 insertions, 80 deletions
diff --git a/src/cli/cli.h b/src/cli/cli.h index 3fddae3b0..cc169511b 100644 --- a/src/cli/cli.h +++ b/src/cli/cli.h @@ -11,6 +11,7 @@ #include "git2_util.h" #include "opt.h" +#include "opt_usage.h" #define PROGRAM_NAME "git2" diff --git a/src/cli/main.c b/src/cli/main.c index 2c36c713c..b5f464012 100644 --- a/src/cli/main.c +++ b/src/cli/main.c @@ -33,7 +33,7 @@ int main(int argc, char **argv) while (cli_opt_parser_next(&opt, &optparser)) { if (!opt.spec) { cli_opt_status_fprint(stderr, &opt); - cli_opt_usage_fprint(stderr, PROGRAM_NAME, common_opts); + cli_opt_usage_fprint(stderr, PROGRAM_NAME, NULL, common_opts); error = 129; goto done; } diff --git a/src/cli/opt.c b/src/cli/opt.c index 40f013c35..ad1592dd1 100644 --- a/src/cli/opt.c +++ b/src/cli/opt.c @@ -10,7 +10,7 @@ * This file was produced by using the `rename.pl` script included with * adopt. The command-line specified was: * - * ./rename.pl cli_opt --filename=opt --include=cli.h --inline=GIT_INLINE --header-guard=CLI_opt_h__ --lowercase-status + * ./rename.pl cli_opt --filename=opt --include=cli.h --inline=GIT_INLINE --header-guard=CLI_opt_h__ --lowercase-status --without-usage */ #include <stdlib.h> @@ -283,67 +283,3 @@ int cli_opt_status_fprint( return error; } -int cli_opt_usage_fprint( - FILE *file, - const char *command, - const cli_opt_spec specs[]) -{ - const cli_opt_spec *spec; - int choice = 0; - int error; - - if ((error = fprintf(file, "usage: %s", command)) < 0) - goto done; - - for (spec = specs; spec->type; ++spec) { - int optional = !(spec->usage & CLI_OPT_USAGE_REQUIRED); - - if (spec->usage & CLI_OPT_USAGE_HIDDEN) - continue; - - if (choice) - error = fprintf(file, "|"); - else - error = fprintf(file, " "); - - if (error < 0) - goto done; - - if (optional && !choice && (error = fprintf(file, "[")) < 0) - goto done; - - if (spec->type == CLI_OPT_VALUE && spec->alias) - error = fprintf(file, "-%c <%s>", spec->alias, spec->value_name); - else if (spec->type == CLI_OPT_VALUE) - error = fprintf(file, "--%s=<%s>", spec->name, spec->value_name); - else if (spec->type == CLI_OPT_VALUE_OPTIONAL && spec->alias) - error = fprintf(file, "-%c [<%s>]", spec->alias, spec->value_name); - else if (spec->type == CLI_OPT_VALUE_OPTIONAL) - error = fprintf(file, "--%s[=<%s>]", spec->name, spec->value_name); - else if (spec->type == CLI_OPT_ARG) - error = fprintf(file, "<%s>", spec->value_name); - else if (spec->type == CLI_OPT_ARGS) - error = fprintf(file, "<%s...>", spec->value_name); - else if (spec->type == CLI_OPT_LITERAL) - error = fprintf(file, "--"); - else if (spec->alias && !(spec->usage & CLI_OPT_USAGE_SHOW_LONG)) - error = fprintf(file, "-%c", spec->alias); - else - error = fprintf(file, "--%s", spec->name); - - if (error < 0) - goto done; - - choice = !!((spec+1)->usage & CLI_OPT_USAGE_CHOICE); - - if (optional && !choice && (error = fprintf(file, "]")) < 0) - goto done; - } - - error = fprintf(file, "\n"); - -done: - error = (error < 0) ? -1 : 0; - return error; -} - diff --git a/src/cli/opt.h b/src/cli/opt.h index 24e605f39..9d178e97a 100644 --- a/src/cli/opt.h +++ b/src/cli/opt.h @@ -10,7 +10,7 @@ * This file was produced by using the `rename.pl` script included with * adopt. The command-line specified was: * - * ./rename.pl cli_opt --filename=opt --include=cli.h --inline=GIT_INLINE --header-guard=CLI_opt_h__ --lowercase-status + * ./rename.pl cli_opt --filename=opt --include=cli.h --inline=GIT_INLINE --header-guard=CLI_opt_h__ --lowercase-status --without-usage */ #ifndef CLI_opt_h__ @@ -241,17 +241,4 @@ int cli_opt_status_fprint( FILE *file, const cli_opt *opt); -/** - * Prints usage information to the given file handle. - * - * @param file The file to print information to - * @param command The name of the command to use when printing - * @param specs The specifications allowed by the command - * @return 0 on success, -1 on failure - */ -int cli_opt_usage_fprint( - FILE *file, - const char *command, - const cli_opt_spec specs[]); - #endif /* CLI_opt_h__ */ diff --git a/src/cli/opt_usage.c b/src/cli/opt_usage.c new file mode 100644 index 000000000..4739d3302 --- /dev/null +++ b/src/cli/opt_usage.c @@ -0,0 +1,125 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "cli.h" +#include "str.h" + +/* + * This is similar to adopt's function, but modified to understand + * that we have a command ("git") and a "subcommand" ("checkout"). + * It also understands a terminal's line length and wrap appropriately, + * using a `git_str` for storage. + */ +int cli_opt_usage_fprint( + FILE *file, + const char *command, + const char *subcommand, + const cli_opt_spec specs[]) +{ + git_str usage = GIT_BUF_INIT, opt = GIT_BUF_INIT; + const cli_opt_spec *spec; + size_t i, prefixlen, linelen; + bool choice = false; + int error; + + /* TODO: query actual console width. */ + int console_width = 80; + + if ((error = git_str_printf(&usage, "usage: %s", command)) < 0) + goto done; + + if (subcommand && + (error = git_str_printf(&usage, " %s", subcommand)) < 0) + goto done; + + linelen = git_str_len(&usage); + prefixlen = linelen + 1; + + for (spec = specs; spec->type; ++spec) { + int optional = !(spec->usage & CLI_OPT_USAGE_REQUIRED); + bool next_choice = !!((spec+1)->usage & CLI_OPT_USAGE_CHOICE); + + if (spec->usage & CLI_OPT_USAGE_HIDDEN) + continue; + + if (choice) + git_str_putc(&opt, '|'); + else + git_str_clear(&opt); + + if (optional && !choice) + git_str_putc(&opt, '['); + if (!optional && !choice && next_choice) + git_str_putc(&opt, '('); + + if (spec->type == CLI_OPT_VALUE && spec->alias) + error = git_str_printf(&opt, "-%c <%s>", spec->alias, spec->value_name); + else if (spec->type == CLI_OPT_VALUE) + error = git_str_printf(&opt, "--%s=<%s>", spec->name, spec->value_name); + else if (spec->type == CLI_OPT_VALUE_OPTIONAL && spec->alias) + error = git_str_printf(&opt, "-%c [<%s>]", spec->alias, spec->value_name); + else if (spec->type == CLI_OPT_VALUE_OPTIONAL) + error = git_str_printf(&opt, "--%s[=<%s>]", spec->name, spec->value_name); + else if (spec->type == CLI_OPT_ARG) + error = git_str_printf(&opt, "<%s>", spec->value_name); + else if (spec->type == CLI_OPT_ARGS) + error = git_str_printf(&opt, "<%s...>", spec->value_name); + else if (spec->type == CLI_OPT_LITERAL) + error = git_str_printf(&opt, "--"); + else if (spec->alias && !(spec->usage & CLI_OPT_USAGE_SHOW_LONG)) + error = git_str_printf(&opt, "-%c", spec->alias); + else + error = git_str_printf(&opt, "--%s", spec->name); + + if (error < 0) + goto done; + + if (!optional && choice && !next_choice) + git_str_putc(&opt, ')'); + else if (optional && !next_choice) + git_str_putc(&opt, ']'); + + if ((choice = next_choice)) + continue; + + if (git_str_oom(&opt)) { + error = -1; + goto done; + } + + if (linelen > prefixlen && + console_width > 0 && + linelen + git_str_len(&opt) + 1 > (size_t)console_width) { + git_str_putc(&usage, '\n'); + + for (i = 0; i < prefixlen; i++) + git_str_putc(&usage, ' '); + + linelen = prefixlen; + } else { + git_str_putc(&usage, ' '); + linelen += git_str_len(&opt) + 1; + } + + git_str_puts(&usage, git_str_cstr(&opt)); + + if (git_str_oom(&usage)) { + error = -1; + goto done; + } + } + + error = fprintf(file, "%s\n", git_str_cstr(&usage)); + +done: + error = (error < 0) ? -1 : 0; + + git_str_dispose(&usage); + git_str_dispose(&opt); + return error; +} + diff --git a/src/cli/opt_usage.h b/src/cli/opt_usage.h new file mode 100644 index 000000000..e1aef0960 --- /dev/null +++ b/src/cli/opt_usage.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef CLI_opt_usage_h__ +#define CLI_opt_usage_h__ + +/** + * Prints usage information to the given file handle. + * + * @param file The file to print information to + * @param command The name of the command to use when printing + * @param subcommand The name of the subcommand (eg "checkout") to use when printing, or NULL to skip + * @param specs The specifications allowed by the command + * @return 0 on success, -1 on failure + */ +int cli_opt_usage_fprint( + FILE *file, + const char *command, + const char *subcommand, + const cli_opt_spec specs[]); + +#endif /* CLI_opt_usage_h__ */ |