Merge branch 'nd/diff-parseopt'
The diff machinery, one of the oldest parts of the system, which long predates the parse-options API, uses fairly long and complex handcrafted option parser. This is being rewritten to use the parse-options API. * nd/diff-parseopt: diff.c: convert --raw diff.c: convert -W|--[no-]function-context diff.c: convert -U|--unified diff.c: convert -u|-p|--patch diff.c: prepare to use parse_options() for parsing diff.h: avoid bit fields in struct diff_flags diff.h: keep forward struct declarations sorted parse-options: allow ll_callback with OPTION_CALLBACK parse-options: avoid magic return codes parse-options: stop abusing 'callback' for lowlevel callbacks parse-options: add OPT_BITOP() parse-options: disable option abbreviation with PARSE_OPT_KEEP_UNKNOWN parse-options: add one-shot mode parse-options.h: remove extern on function prototypes
This commit is contained in:
@ -36,7 +36,7 @@ endif::git-format-patch[]
|
|||||||
-U<n>::
|
-U<n>::
|
||||||
--unified=<n>::
|
--unified=<n>::
|
||||||
Generate diffs with <n> lines of context instead of
|
Generate diffs with <n> lines of context instead of
|
||||||
the usual three.
|
the usual three. Implies `--patch`.
|
||||||
ifndef::git-format-patch[]
|
ifndef::git-format-patch[]
|
||||||
Implies `-p`.
|
Implies `-p`.
|
||||||
endif::git-format-patch[]
|
endif::git-format-patch[]
|
||||||
|
@ -814,7 +814,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
|
|||||||
* and are only included here to get included in the "-h"
|
* and are only included here to get included in the "-h"
|
||||||
* output:
|
* output:
|
||||||
*/
|
*/
|
||||||
{ OPTION_LOWLEVEL_CALLBACK, 0, "indent-heuristic", NULL, NULL, N_("Use an experimental heuristic to improve diffs"), PARSE_OPT_NOARG, parse_opt_unknown_cb },
|
{ OPTION_LOWLEVEL_CALLBACK, 0, "indent-heuristic", NULL, NULL, N_("Use an experimental heuristic to improve diffs"), PARSE_OPT_NOARG, NULL, 0, parse_opt_unknown_cb },
|
||||||
|
|
||||||
OPT_BIT(0, "minimal", &xdl_opts, N_("Spend extra cycles to find better match"), XDF_NEED_MINIMAL),
|
OPT_BIT(0, "minimal", &xdl_opts, N_("Spend extra cycles to find better match"), XDF_NEED_MINIMAL),
|
||||||
OPT_STRING('S', NULL, &revs_file, N_("file"), N_("Use revisions from <file> instead of calling git-rev-list")),
|
OPT_STRING('S', NULL, &revs_file, N_("file"), N_("Use revisions from <file> instead of calling git-rev-list")),
|
||||||
|
@ -113,12 +113,15 @@ static int option_parse_message(const struct option *opt,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int option_read_message(struct parse_opt_ctx_t *ctx,
|
static enum parse_opt_result option_read_message(struct parse_opt_ctx_t *ctx,
|
||||||
const struct option *opt, int unset)
|
const struct option *opt,
|
||||||
|
const char *arg_not_used,
|
||||||
|
int unset)
|
||||||
{
|
{
|
||||||
struct strbuf *buf = opt->value;
|
struct strbuf *buf = opt->value;
|
||||||
const char *arg;
|
const char *arg;
|
||||||
|
|
||||||
|
BUG_ON_OPT_ARG(arg_not_used);
|
||||||
if (unset)
|
if (unset)
|
||||||
BUG("-F cannot be negated");
|
BUG("-F cannot be negated");
|
||||||
|
|
||||||
@ -262,7 +265,7 @@ static struct option builtin_merge_options[] = {
|
|||||||
option_parse_message),
|
option_parse_message),
|
||||||
{ OPTION_LOWLEVEL_CALLBACK, 'F', "file", &merge_msg, N_("path"),
|
{ OPTION_LOWLEVEL_CALLBACK, 'F', "file", &merge_msg, N_("path"),
|
||||||
N_("read message from file"), PARSE_OPT_NONEG,
|
N_("read message from file"), PARSE_OPT_NONEG,
|
||||||
(parse_opt_cb *) option_read_message },
|
NULL, 0, option_read_message },
|
||||||
OPT__VERBOSITY(&verbosity),
|
OPT__VERBOSITY(&verbosity),
|
||||||
OPT_BOOL(0, "abort", &abort_current_merge,
|
OPT_BOOL(0, "abort", &abort_current_merge,
|
||||||
N_("abort the current in-progress merge")),
|
N_("abort the current in-progress merge")),
|
||||||
|
@ -848,14 +848,16 @@ static int parse_new_style_cacheinfo(const char *arg,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cacheinfo_callback(struct parse_opt_ctx_t *ctx,
|
static enum parse_opt_result cacheinfo_callback(
|
||||||
const struct option *opt, int unset)
|
struct parse_opt_ctx_t *ctx, const struct option *opt,
|
||||||
|
const char *arg, int unset)
|
||||||
{
|
{
|
||||||
struct object_id oid;
|
struct object_id oid;
|
||||||
unsigned int mode;
|
unsigned int mode;
|
||||||
const char *path;
|
const char *path;
|
||||||
|
|
||||||
BUG_ON_OPT_NEG(unset);
|
BUG_ON_OPT_NEG(unset);
|
||||||
|
BUG_ON_OPT_ARG(arg);
|
||||||
|
|
||||||
if (!parse_new_style_cacheinfo(ctx->argv[1], &mode, &oid, &path)) {
|
if (!parse_new_style_cacheinfo(ctx->argv[1], &mode, &oid, &path)) {
|
||||||
if (add_cacheinfo(mode, &oid, path, 0))
|
if (add_cacheinfo(mode, &oid, path, 0))
|
||||||
@ -874,12 +876,14 @@ static int cacheinfo_callback(struct parse_opt_ctx_t *ctx,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int stdin_cacheinfo_callback(struct parse_opt_ctx_t *ctx,
|
static enum parse_opt_result stdin_cacheinfo_callback(
|
||||||
const struct option *opt, int unset)
|
struct parse_opt_ctx_t *ctx, const struct option *opt,
|
||||||
|
const char *arg, int unset)
|
||||||
{
|
{
|
||||||
int *nul_term_line = opt->value;
|
int *nul_term_line = opt->value;
|
||||||
|
|
||||||
BUG_ON_OPT_NEG(unset);
|
BUG_ON_OPT_NEG(unset);
|
||||||
|
BUG_ON_OPT_ARG(arg);
|
||||||
|
|
||||||
if (ctx->argc != 1)
|
if (ctx->argc != 1)
|
||||||
return error("option '%s' must be the last argument", opt->long_name);
|
return error("option '%s' must be the last argument", opt->long_name);
|
||||||
@ -888,12 +892,14 @@ static int stdin_cacheinfo_callback(struct parse_opt_ctx_t *ctx,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int stdin_callback(struct parse_opt_ctx_t *ctx,
|
static enum parse_opt_result stdin_callback(
|
||||||
const struct option *opt, int unset)
|
struct parse_opt_ctx_t *ctx, const struct option *opt,
|
||||||
|
const char *arg, int unset)
|
||||||
{
|
{
|
||||||
int *read_from_stdin = opt->value;
|
int *read_from_stdin = opt->value;
|
||||||
|
|
||||||
BUG_ON_OPT_NEG(unset);
|
BUG_ON_OPT_NEG(unset);
|
||||||
|
BUG_ON_OPT_ARG(arg);
|
||||||
|
|
||||||
if (ctx->argc != 1)
|
if (ctx->argc != 1)
|
||||||
return error("option '%s' must be the last argument", opt->long_name);
|
return error("option '%s' must be the last argument", opt->long_name);
|
||||||
@ -901,13 +907,15 @@ static int stdin_callback(struct parse_opt_ctx_t *ctx,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int unresolve_callback(struct parse_opt_ctx_t *ctx,
|
static enum parse_opt_result unresolve_callback(
|
||||||
const struct option *opt, int unset)
|
struct parse_opt_ctx_t *ctx, const struct option *opt,
|
||||||
|
const char *arg, int unset)
|
||||||
{
|
{
|
||||||
int *has_errors = opt->value;
|
int *has_errors = opt->value;
|
||||||
const char *prefix = startup_info->prefix;
|
const char *prefix = startup_info->prefix;
|
||||||
|
|
||||||
BUG_ON_OPT_NEG(unset);
|
BUG_ON_OPT_NEG(unset);
|
||||||
|
BUG_ON_OPT_ARG(arg);
|
||||||
|
|
||||||
/* consume remaining arguments. */
|
/* consume remaining arguments. */
|
||||||
*has_errors = do_unresolve(ctx->argc, ctx->argv,
|
*has_errors = do_unresolve(ctx->argc, ctx->argv,
|
||||||
@ -920,13 +928,15 @@ static int unresolve_callback(struct parse_opt_ctx_t *ctx,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int reupdate_callback(struct parse_opt_ctx_t *ctx,
|
static enum parse_opt_result reupdate_callback(
|
||||||
const struct option *opt, int unset)
|
struct parse_opt_ctx_t *ctx, const struct option *opt,
|
||||||
|
const char *arg, int unset)
|
||||||
{
|
{
|
||||||
int *has_errors = opt->value;
|
int *has_errors = opt->value;
|
||||||
const char *prefix = startup_info->prefix;
|
const char *prefix = startup_info->prefix;
|
||||||
|
|
||||||
BUG_ON_OPT_NEG(unset);
|
BUG_ON_OPT_NEG(unset);
|
||||||
|
BUG_ON_OPT_ARG(arg);
|
||||||
|
|
||||||
/* consume remaining arguments. */
|
/* consume remaining arguments. */
|
||||||
setup_work_tree();
|
setup_work_tree();
|
||||||
@ -986,7 +996,8 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
|
|||||||
N_("add the specified entry to the index"),
|
N_("add the specified entry to the index"),
|
||||||
PARSE_OPT_NOARG | /* disallow --cacheinfo=<mode> form */
|
PARSE_OPT_NOARG | /* disallow --cacheinfo=<mode> form */
|
||||||
PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
|
PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
|
||||||
(parse_opt_cb *) cacheinfo_callback},
|
NULL, 0,
|
||||||
|
cacheinfo_callback},
|
||||||
{OPTION_CALLBACK, 0, "chmod", &set_executable_bit, "(+|-)x",
|
{OPTION_CALLBACK, 0, "chmod", &set_executable_bit, "(+|-)x",
|
||||||
N_("override the executable bit of the listed files"),
|
N_("override the executable bit of the listed files"),
|
||||||
PARSE_OPT_NONEG,
|
PARSE_OPT_NONEG,
|
||||||
@ -1012,19 +1023,19 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
|
|||||||
{OPTION_LOWLEVEL_CALLBACK, 0, "stdin", &read_from_stdin, NULL,
|
{OPTION_LOWLEVEL_CALLBACK, 0, "stdin", &read_from_stdin, NULL,
|
||||||
N_("read list of paths to be updated from standard input"),
|
N_("read list of paths to be updated from standard input"),
|
||||||
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
|
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
|
||||||
(parse_opt_cb *) stdin_callback},
|
NULL, 0, stdin_callback},
|
||||||
{OPTION_LOWLEVEL_CALLBACK, 0, "index-info", &nul_term_line, NULL,
|
{OPTION_LOWLEVEL_CALLBACK, 0, "index-info", &nul_term_line, NULL,
|
||||||
N_("add entries from standard input to the index"),
|
N_("add entries from standard input to the index"),
|
||||||
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
|
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
|
||||||
(parse_opt_cb *) stdin_cacheinfo_callback},
|
NULL, 0, stdin_cacheinfo_callback},
|
||||||
{OPTION_LOWLEVEL_CALLBACK, 0, "unresolve", &has_errors, NULL,
|
{OPTION_LOWLEVEL_CALLBACK, 0, "unresolve", &has_errors, NULL,
|
||||||
N_("repopulate stages #2 and #3 for the listed paths"),
|
N_("repopulate stages #2 and #3 for the listed paths"),
|
||||||
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
|
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
|
||||||
(parse_opt_cb *) unresolve_callback},
|
NULL, 0, unresolve_callback},
|
||||||
{OPTION_LOWLEVEL_CALLBACK, 'g', "again", &has_errors, NULL,
|
{OPTION_LOWLEVEL_CALLBACK, 'g', "again", &has_errors, NULL,
|
||||||
N_("only update entries that differ from HEAD"),
|
N_("only update entries that differ from HEAD"),
|
||||||
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
|
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
|
||||||
(parse_opt_cb *) reupdate_callback},
|
NULL, 0, reupdate_callback},
|
||||||
OPT_BIT(0, "ignore-missing", &refresh_args.flags,
|
OPT_BIT(0, "ignore-missing", &refresh_args.flags,
|
||||||
N_("ignore files missing from worktree"),
|
N_("ignore files missing from worktree"),
|
||||||
REFRESH_IGNORE_MISSING),
|
REFRESH_IGNORE_MISSING),
|
||||||
|
71
diff.c
71
diff.c
@ -23,6 +23,7 @@
|
|||||||
#include "argv-array.h"
|
#include "argv-array.h"
|
||||||
#include "graph.h"
|
#include "graph.h"
|
||||||
#include "packfile.h"
|
#include "packfile.h"
|
||||||
|
#include "parse-options.h"
|
||||||
#include "help.h"
|
#include "help.h"
|
||||||
|
|
||||||
#ifdef NO_FAST_WORKING_DIRECTORY
|
#ifdef NO_FAST_WORKING_DIRECTORY
|
||||||
@ -4491,6 +4492,8 @@ static void run_checkdiff(struct diff_filepair *p, struct diff_options *o)
|
|||||||
builtin_checkdiff(name, other, attr_path, p->one, p->two, o);
|
builtin_checkdiff(name, other, attr_path, p->one, p->two, o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void prep_parse_options(struct diff_options *options);
|
||||||
|
|
||||||
void repo_diff_setup(struct repository *r, struct diff_options *options)
|
void repo_diff_setup(struct repository *r, struct diff_options *options)
|
||||||
{
|
{
|
||||||
memcpy(options, &default_diff_options, sizeof(*options));
|
memcpy(options, &default_diff_options, sizeof(*options));
|
||||||
@ -4532,6 +4535,8 @@ void repo_diff_setup(struct repository *r, struct diff_options *options)
|
|||||||
|
|
||||||
options->color_moved = diff_color_moved_default;
|
options->color_moved = diff_color_moved_default;
|
||||||
options->color_moved_ws_handling = diff_color_moved_ws_default;
|
options->color_moved_ws_handling = diff_color_moved_ws_default;
|
||||||
|
|
||||||
|
prep_parse_options(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
void diff_setup_done(struct diff_options *options)
|
void diff_setup_done(struct diff_options *options)
|
||||||
@ -4635,6 +4640,8 @@ void diff_setup_done(struct diff_options *options)
|
|||||||
|
|
||||||
if (!options->use_color || external_diff())
|
if (!options->use_color || external_diff())
|
||||||
options->color_moved = 0;
|
options->color_moved = 0;
|
||||||
|
|
||||||
|
FREE_AND_NULL(options->parseopts);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int opt_arg(const char *arg, int arg_short, const char *arg_long, int *val)
|
static int opt_arg(const char *arg, int arg_short, const char *arg_long, int *val)
|
||||||
@ -4926,6 +4933,47 @@ static int parse_objfind_opt(struct diff_options *opt, const char *arg)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int diff_opt_unified(const struct option *opt,
|
||||||
|
const char *arg, int unset)
|
||||||
|
{
|
||||||
|
struct diff_options *options = opt->value;
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
BUG_ON_OPT_NEG(unset);
|
||||||
|
|
||||||
|
options->context = strtol(arg, &s, 10);
|
||||||
|
if (*s)
|
||||||
|
return error(_("%s expects a numerical value"), "--unified");
|
||||||
|
enable_patch_output(&options->output_format);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prep_parse_options(struct diff_options *options)
|
||||||
|
{
|
||||||
|
struct option parseopts[] = {
|
||||||
|
OPT_GROUP(N_("Diff output format options")),
|
||||||
|
OPT_BITOP('p', "patch", &options->output_format,
|
||||||
|
N_("generate patch"),
|
||||||
|
DIFF_FORMAT_PATCH, DIFF_FORMAT_NO_OUTPUT),
|
||||||
|
OPT_BITOP('u', NULL, &options->output_format,
|
||||||
|
N_("generate patch"),
|
||||||
|
DIFF_FORMAT_PATCH, DIFF_FORMAT_NO_OUTPUT),
|
||||||
|
OPT_CALLBACK_F('U', "unified", options, N_("<n>"),
|
||||||
|
N_("generate diffs with <n> lines context"),
|
||||||
|
PARSE_OPT_NONEG, diff_opt_unified),
|
||||||
|
OPT_BOOL('W', "function-context", &options->flags.funccontext,
|
||||||
|
N_("generate diffs with <n> lines context")),
|
||||||
|
OPT_BIT_F(0, "raw", &options->output_format,
|
||||||
|
N_("generate the diff in raw format"),
|
||||||
|
DIFF_FORMAT_RAW, PARSE_OPT_NONEG),
|
||||||
|
OPT_END()
|
||||||
|
};
|
||||||
|
|
||||||
|
ALLOC_ARRAY(options->parseopts, ARRAY_SIZE(parseopts));
|
||||||
|
memcpy(options->parseopts, parseopts, sizeof(parseopts));
|
||||||
|
}
|
||||||
|
|
||||||
int diff_opt_parse(struct diff_options *options,
|
int diff_opt_parse(struct diff_options *options,
|
||||||
const char **av, int ac, const char *prefix)
|
const char **av, int ac, const char *prefix)
|
||||||
{
|
{
|
||||||
@ -4936,13 +4984,18 @@ int diff_opt_parse(struct diff_options *options,
|
|||||||
if (!prefix)
|
if (!prefix)
|
||||||
prefix = "";
|
prefix = "";
|
||||||
|
|
||||||
|
ac = parse_options(ac, av, prefix, options->parseopts, NULL,
|
||||||
|
PARSE_OPT_KEEP_DASHDASH |
|
||||||
|
PARSE_OPT_KEEP_UNKNOWN |
|
||||||
|
PARSE_OPT_NO_INTERNAL_HELP |
|
||||||
|
PARSE_OPT_ONE_SHOT |
|
||||||
|
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||||
|
|
||||||
|
if (ac)
|
||||||
|
return ac;
|
||||||
|
|
||||||
/* Output format options */
|
/* Output format options */
|
||||||
if (!strcmp(arg, "-p") || !strcmp(arg, "-u") || !strcmp(arg, "--patch")
|
if (!strcmp(arg, "--patch-with-raw")) {
|
||||||
|| opt_arg(arg, 'U', "unified", &options->context))
|
|
||||||
enable_patch_output(&options->output_format);
|
|
||||||
else if (!strcmp(arg, "--raw"))
|
|
||||||
options->output_format |= DIFF_FORMAT_RAW;
|
|
||||||
else if (!strcmp(arg, "--patch-with-raw")) {
|
|
||||||
enable_patch_output(&options->output_format);
|
enable_patch_output(&options->output_format);
|
||||||
options->output_format |= DIFF_FORMAT_RAW;
|
options->output_format |= DIFF_FORMAT_RAW;
|
||||||
} else if (!strcmp(arg, "--numstat"))
|
} else if (!strcmp(arg, "--numstat"))
|
||||||
@ -5230,12 +5283,6 @@ int diff_opt_parse(struct diff_options *options,
|
|||||||
else if (opt_arg(arg, '\0', "inter-hunk-context",
|
else if (opt_arg(arg, '\0', "inter-hunk-context",
|
||||||
&options->interhunkcontext))
|
&options->interhunkcontext))
|
||||||
;
|
;
|
||||||
else if (!strcmp(arg, "-W"))
|
|
||||||
options->flags.funccontext = 1;
|
|
||||||
else if (!strcmp(arg, "--function-context"))
|
|
||||||
options->flags.funccontext = 1;
|
|
||||||
else if (!strcmp(arg, "--no-function-context"))
|
|
||||||
options->flags.funccontext = 0;
|
|
||||||
else if ((argcount = parse_long_opt("output", av, &optarg))) {
|
else if ((argcount = parse_long_opt("output", av, &optarg))) {
|
||||||
char *path = prefix_filename(prefix, optarg);
|
char *path = prefix_filename(prefix, optarg);
|
||||||
options->file = xfopen(path, "w");
|
options->file = xfopen(path, "w");
|
||||||
|
80
diff.h
80
diff.h
@ -9,16 +9,17 @@
|
|||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include "oidset.h"
|
#include "oidset.h"
|
||||||
|
|
||||||
struct rev_info;
|
struct combine_diff_path;
|
||||||
|
struct commit;
|
||||||
|
struct diff_filespec;
|
||||||
struct diff_options;
|
struct diff_options;
|
||||||
struct diff_queue_struct;
|
struct diff_queue_struct;
|
||||||
struct strbuf;
|
|
||||||
struct diff_filespec;
|
|
||||||
struct userdiff_driver;
|
|
||||||
struct oid_array;
|
struct oid_array;
|
||||||
struct commit;
|
struct option;
|
||||||
struct combine_diff_path;
|
|
||||||
struct repository;
|
struct repository;
|
||||||
|
struct rev_info;
|
||||||
|
struct strbuf;
|
||||||
|
struct userdiff_driver;
|
||||||
|
|
||||||
typedef int (*pathchange_fn_t)(struct diff_options *options,
|
typedef int (*pathchange_fn_t)(struct diff_options *options,
|
||||||
struct combine_diff_path *path);
|
struct combine_diff_path *path);
|
||||||
@ -64,39 +65,39 @@ typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data)
|
|||||||
|
|
||||||
#define DIFF_FLAGS_INIT { 0 }
|
#define DIFF_FLAGS_INIT { 0 }
|
||||||
struct diff_flags {
|
struct diff_flags {
|
||||||
unsigned recursive:1;
|
unsigned recursive;
|
||||||
unsigned tree_in_recursive:1;
|
unsigned tree_in_recursive;
|
||||||
unsigned binary:1;
|
unsigned binary;
|
||||||
unsigned text:1;
|
unsigned text;
|
||||||
unsigned full_index:1;
|
unsigned full_index;
|
||||||
unsigned silent_on_remove:1;
|
unsigned silent_on_remove;
|
||||||
unsigned find_copies_harder:1;
|
unsigned find_copies_harder;
|
||||||
unsigned follow_renames:1;
|
unsigned follow_renames;
|
||||||
unsigned rename_empty:1;
|
unsigned rename_empty;
|
||||||
unsigned has_changes:1;
|
unsigned has_changes;
|
||||||
unsigned quick:1;
|
unsigned quick;
|
||||||
unsigned no_index:1;
|
unsigned no_index;
|
||||||
unsigned allow_external:1;
|
unsigned allow_external;
|
||||||
unsigned exit_with_status:1;
|
unsigned exit_with_status;
|
||||||
unsigned reverse_diff:1;
|
unsigned reverse_diff;
|
||||||
unsigned check_failed:1;
|
unsigned check_failed;
|
||||||
unsigned relative_name:1;
|
unsigned relative_name;
|
||||||
unsigned ignore_submodules:1;
|
unsigned ignore_submodules;
|
||||||
unsigned dirstat_cumulative:1;
|
unsigned dirstat_cumulative;
|
||||||
unsigned dirstat_by_file:1;
|
unsigned dirstat_by_file;
|
||||||
unsigned allow_textconv:1;
|
unsigned allow_textconv;
|
||||||
unsigned textconv_set_via_cmdline:1;
|
unsigned textconv_set_via_cmdline;
|
||||||
unsigned diff_from_contents:1;
|
unsigned diff_from_contents;
|
||||||
unsigned dirty_submodules:1;
|
unsigned dirty_submodules;
|
||||||
unsigned ignore_untracked_in_submodules:1;
|
unsigned ignore_untracked_in_submodules;
|
||||||
unsigned ignore_dirty_submodules:1;
|
unsigned ignore_dirty_submodules;
|
||||||
unsigned override_submodule_config:1;
|
unsigned override_submodule_config;
|
||||||
unsigned dirstat_by_line:1;
|
unsigned dirstat_by_line;
|
||||||
unsigned funccontext:1;
|
unsigned funccontext;
|
||||||
unsigned default_follow_renames:1;
|
unsigned default_follow_renames;
|
||||||
unsigned stat_with_summary:1;
|
unsigned stat_with_summary;
|
||||||
unsigned suppress_diff_headers:1;
|
unsigned suppress_diff_headers;
|
||||||
unsigned dual_color_diffed_diffs:1;
|
unsigned dual_color_diffed_diffs;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void diff_flags_or(struct diff_flags *a,
|
static inline void diff_flags_or(struct diff_flags *a,
|
||||||
@ -229,6 +230,7 @@ struct diff_options {
|
|||||||
unsigned color_moved_ws_handling;
|
unsigned color_moved_ws_handling;
|
||||||
|
|
||||||
struct repository *repo;
|
struct repository *repo;
|
||||||
|
struct option *parseopts;
|
||||||
};
|
};
|
||||||
|
|
||||||
void diff_emit_submodule_del(struct diff_options *o, const char *line);
|
void diff_emit_submodule_del(struct diff_options *o, const char *line);
|
||||||
|
@ -170,9 +170,12 @@ int parse_opt_noop_cb(const struct option *opt, const char *arg, int unset)
|
|||||||
* "-h" output even if it's not being handled directly by
|
* "-h" output even if it's not being handled directly by
|
||||||
* parse_options().
|
* parse_options().
|
||||||
*/
|
*/
|
||||||
int parse_opt_unknown_cb(const struct option *opt, const char *arg, int unset)
|
enum parse_opt_result parse_opt_unknown_cb(struct parse_opt_ctx_t *ctx,
|
||||||
|
const struct option *opt,
|
||||||
|
const char *arg, int unset)
|
||||||
{
|
{
|
||||||
return -2;
|
BUG_ON_OPT_ARG(arg);
|
||||||
|
return PARSE_OPT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
136
parse-options.c
136
parse-options.c
@ -20,7 +20,8 @@ int optbug(const struct option *opt, const char *reason)
|
|||||||
return error("BUG: switch '%c' %s", opt->short_name, reason);
|
return error("BUG: switch '%c' %s", opt->short_name, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
|
static enum parse_opt_result get_arg(struct parse_opt_ctx_t *p,
|
||||||
|
const struct option *opt,
|
||||||
int flags, const char **arg)
|
int flags, const char **arg)
|
||||||
{
|
{
|
||||||
if (p->opt) {
|
if (p->opt) {
|
||||||
@ -44,7 +45,8 @@ static void fix_filename(const char *prefix, const char **file)
|
|||||||
*file = prefix_filename(prefix, *file);
|
*file = prefix_filename(prefix, *file);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int opt_command_mode_error(const struct option *opt,
|
static enum parse_opt_result opt_command_mode_error(
|
||||||
|
const struct option *opt,
|
||||||
const struct option *all_opts,
|
const struct option *all_opts,
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
@ -69,13 +71,13 @@ static int opt_command_mode_error(const struct option *opt,
|
|||||||
error(_("%s is incompatible with %s"),
|
error(_("%s is incompatible with %s"),
|
||||||
optname(opt, flags), that_name.buf);
|
optname(opt, flags), that_name.buf);
|
||||||
strbuf_release(&that_name);
|
strbuf_release(&that_name);
|
||||||
return -1;
|
return PARSE_OPT_ERROR;
|
||||||
}
|
}
|
||||||
return error(_("%s : incompatible with something else"),
|
return error(_("%s : incompatible with something else"),
|
||||||
optname(opt, flags));
|
optname(opt, flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_value(struct parse_opt_ctx_t *p,
|
static enum parse_opt_result get_value(struct parse_opt_ctx_t *p,
|
||||||
const struct option *opt,
|
const struct option *opt,
|
||||||
const struct option *all_opts,
|
const struct option *all_opts,
|
||||||
int flags)
|
int flags)
|
||||||
@ -93,7 +95,7 @@ static int get_value(struct parse_opt_ctx_t *p,
|
|||||||
|
|
||||||
switch (opt->type) {
|
switch (opt->type) {
|
||||||
case OPTION_LOWLEVEL_CALLBACK:
|
case OPTION_LOWLEVEL_CALLBACK:
|
||||||
return (*(parse_opt_ll_cb *)opt->callback)(p, opt, unset);
|
return opt->ll_callback(p, opt, NULL, unset);
|
||||||
|
|
||||||
case OPTION_BIT:
|
case OPTION_BIT:
|
||||||
if (unset)
|
if (unset)
|
||||||
@ -109,6 +111,13 @@ static int get_value(struct parse_opt_ctx_t *p,
|
|||||||
*(int *)opt->value &= ~opt->defval;
|
*(int *)opt->value &= ~opt->defval;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
case OPTION_BITOP:
|
||||||
|
if (unset)
|
||||||
|
BUG("BITOP can't have unset form");
|
||||||
|
*(int *)opt->value &= ~opt->extra;
|
||||||
|
*(int *)opt->value |= opt->defval;
|
||||||
|
return 0;
|
||||||
|
|
||||||
case OPTION_COUNTUP:
|
case OPTION_COUNTUP:
|
||||||
if (*(int *)opt->value < 0)
|
if (*(int *)opt->value < 0)
|
||||||
*(int *)opt->value = 0;
|
*(int *)opt->value = 0;
|
||||||
@ -152,16 +161,27 @@ static int get_value(struct parse_opt_ctx_t *p,
|
|||||||
return err;
|
return err;
|
||||||
|
|
||||||
case OPTION_CALLBACK:
|
case OPTION_CALLBACK:
|
||||||
if (unset)
|
{
|
||||||
return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
|
const char *p_arg = NULL;
|
||||||
if (opt->flags & PARSE_OPT_NOARG)
|
int p_unset;
|
||||||
return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
|
|
||||||
if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
|
|
||||||
return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
|
|
||||||
if (get_arg(p, opt, flags, &arg))
|
|
||||||
return -1;
|
|
||||||
return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
|
|
||||||
|
|
||||||
|
if (unset)
|
||||||
|
p_unset = 1;
|
||||||
|
else if (opt->flags & PARSE_OPT_NOARG)
|
||||||
|
p_unset = 0;
|
||||||
|
else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
|
||||||
|
p_unset = 0;
|
||||||
|
else if (get_arg(p, opt, flags, &arg))
|
||||||
|
return -1;
|
||||||
|
else {
|
||||||
|
p_unset = 0;
|
||||||
|
p_arg = arg;
|
||||||
|
}
|
||||||
|
if (opt->callback)
|
||||||
|
return (*opt->callback)(opt, p_arg, p_unset) ? (-1) : 0;
|
||||||
|
else
|
||||||
|
return (*opt->ll_callback)(p, opt, p_arg, p_unset);
|
||||||
|
}
|
||||||
case OPTION_INTEGER:
|
case OPTION_INTEGER:
|
||||||
if (unset) {
|
if (unset) {
|
||||||
*(int *)opt->value = 0;
|
*(int *)opt->value = 0;
|
||||||
@ -201,7 +221,8 @@ static int get_value(struct parse_opt_ctx_t *p,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
|
static enum parse_opt_result parse_short_opt(struct parse_opt_ctx_t *p,
|
||||||
|
const struct option *options)
|
||||||
{
|
{
|
||||||
const struct option *all_opts = options;
|
const struct option *all_opts = options;
|
||||||
const struct option *numopt = NULL;
|
const struct option *numopt = NULL;
|
||||||
@ -228,14 +249,18 @@ static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *optio
|
|||||||
len++;
|
len++;
|
||||||
arg = xmemdupz(p->opt, len);
|
arg = xmemdupz(p->opt, len);
|
||||||
p->opt = p->opt[len] ? p->opt + len : NULL;
|
p->opt = p->opt[len] ? p->opt + len : NULL;
|
||||||
|
if (numopt->callback)
|
||||||
rc = (*numopt->callback)(numopt, arg, 0) ? (-1) : 0;
|
rc = (*numopt->callback)(numopt, arg, 0) ? (-1) : 0;
|
||||||
|
else
|
||||||
|
rc = (*numopt->ll_callback)(p, numopt, arg, 0);
|
||||||
free(arg);
|
free(arg);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
return -2;
|
return PARSE_OPT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
|
static enum parse_opt_result parse_long_opt(
|
||||||
|
struct parse_opt_ctx_t *p, const char *arg,
|
||||||
const struct option *options)
|
const struct option *options)
|
||||||
{
|
{
|
||||||
const struct option *all_opts = options;
|
const struct option *all_opts = options;
|
||||||
@ -262,11 +287,12 @@ again:
|
|||||||
if (*rest)
|
if (*rest)
|
||||||
continue;
|
continue;
|
||||||
p->out[p->cpidx++] = arg - 2;
|
p->out[p->cpidx++] = arg - 2;
|
||||||
return 0;
|
return PARSE_OPT_DONE;
|
||||||
}
|
}
|
||||||
if (!rest) {
|
if (!rest) {
|
||||||
/* abbreviated? */
|
/* abbreviated? */
|
||||||
if (!strncmp(long_name, arg, arg_end - arg)) {
|
if (!(p->flags & PARSE_OPT_KEEP_UNKNOWN) &&
|
||||||
|
!strncmp(long_name, arg, arg_end - arg)) {
|
||||||
is_abbreviated:
|
is_abbreviated:
|
||||||
if (abbrev_option) {
|
if (abbrev_option) {
|
||||||
/*
|
/*
|
||||||
@ -326,11 +352,11 @@ is_abbreviated:
|
|||||||
ambiguous_option->long_name,
|
ambiguous_option->long_name,
|
||||||
(abbrev_flags & OPT_UNSET) ? "no-" : "",
|
(abbrev_flags & OPT_UNSET) ? "no-" : "",
|
||||||
abbrev_option->long_name);
|
abbrev_option->long_name);
|
||||||
return -3;
|
return PARSE_OPT_HELP;
|
||||||
}
|
}
|
||||||
if (abbrev_option)
|
if (abbrev_option)
|
||||||
return get_value(p, abbrev_option, all_opts, abbrev_flags);
|
return get_value(p, abbrev_option, all_opts, abbrev_flags);
|
||||||
return -2;
|
return PARSE_OPT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_nodash_opt(struct parse_opt_ctx_t *p, const char *arg,
|
static int parse_nodash_opt(struct parse_opt_ctx_t *p, const char *arg,
|
||||||
@ -400,6 +426,19 @@ static void parse_options_check(const struct option *opts)
|
|||||||
if ((opts->flags & PARSE_OPT_OPTARG) ||
|
if ((opts->flags & PARSE_OPT_OPTARG) ||
|
||||||
!(opts->flags & PARSE_OPT_NOARG))
|
!(opts->flags & PARSE_OPT_NOARG))
|
||||||
err |= optbug(opts, "should not accept an argument");
|
err |= optbug(opts, "should not accept an argument");
|
||||||
|
break;
|
||||||
|
case OPTION_CALLBACK:
|
||||||
|
if (!opts->callback && !opts->ll_callback)
|
||||||
|
BUG("OPTION_CALLBACK needs one callback");
|
||||||
|
if (opts->callback && opts->ll_callback)
|
||||||
|
BUG("OPTION_CALLBACK can't have two callbacks");
|
||||||
|
break;
|
||||||
|
case OPTION_LOWLEVEL_CALLBACK:
|
||||||
|
if (!opts->ll_callback)
|
||||||
|
BUG("OPTION_LOWLEVEL_CALLBACK needs a callback");
|
||||||
|
if (opts->callback)
|
||||||
|
BUG("OPTION_LOWLEVEL_CALLBACK needs no high level callback");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
; /* ok. (usually accepts an argument) */
|
; /* ok. (usually accepts an argument) */
|
||||||
}
|
}
|
||||||
@ -416,15 +455,24 @@ void parse_options_start(struct parse_opt_ctx_t *ctx,
|
|||||||
const struct option *options, int flags)
|
const struct option *options, int flags)
|
||||||
{
|
{
|
||||||
memset(ctx, 0, sizeof(*ctx));
|
memset(ctx, 0, sizeof(*ctx));
|
||||||
ctx->argc = ctx->total = argc - 1;
|
ctx->argc = argc;
|
||||||
ctx->argv = argv + 1;
|
ctx->argv = argv;
|
||||||
|
if (!(flags & PARSE_OPT_ONE_SHOT)) {
|
||||||
|
ctx->argc--;
|
||||||
|
ctx->argv++;
|
||||||
|
}
|
||||||
|
ctx->total = ctx->argc;
|
||||||
ctx->out = argv;
|
ctx->out = argv;
|
||||||
ctx->prefix = prefix;
|
ctx->prefix = prefix;
|
||||||
ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
|
ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
|
||||||
ctx->flags = flags;
|
ctx->flags = flags;
|
||||||
if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
|
if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
|
||||||
(flags & PARSE_OPT_STOP_AT_NON_OPTION))
|
(flags & PARSE_OPT_STOP_AT_NON_OPTION) &&
|
||||||
|
!(flags & PARSE_OPT_ONE_SHOT))
|
||||||
BUG("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
|
BUG("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
|
||||||
|
if ((flags & PARSE_OPT_ONE_SHOT) &&
|
||||||
|
(flags & PARSE_OPT_KEEP_ARGV0))
|
||||||
|
BUG("Can't keep argv0 if you don't have it");
|
||||||
parse_options_check(options);
|
parse_options_check(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -536,6 +584,10 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
|
|||||||
for (; ctx->argc; ctx->argc--, ctx->argv++) {
|
for (; ctx->argc; ctx->argc--, ctx->argv++) {
|
||||||
const char *arg = ctx->argv[0];
|
const char *arg = ctx->argv[0];
|
||||||
|
|
||||||
|
if (ctx->flags & PARSE_OPT_ONE_SHOT &&
|
||||||
|
ctx->argc != ctx->total)
|
||||||
|
break;
|
||||||
|
|
||||||
if (*arg != '-' || !arg[1]) {
|
if (*arg != '-' || !arg[1]) {
|
||||||
if (parse_nodash_opt(ctx, arg, options) == 0)
|
if (parse_nodash_opt(ctx, arg, options) == 0)
|
||||||
continue;
|
continue;
|
||||||
@ -556,22 +608,28 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
|
|||||||
if (arg[1] != '-') {
|
if (arg[1] != '-') {
|
||||||
ctx->opt = arg + 1;
|
ctx->opt = arg + 1;
|
||||||
switch (parse_short_opt(ctx, options)) {
|
switch (parse_short_opt(ctx, options)) {
|
||||||
case -1:
|
case PARSE_OPT_ERROR:
|
||||||
return PARSE_OPT_ERROR;
|
return PARSE_OPT_ERROR;
|
||||||
case -2:
|
case PARSE_OPT_UNKNOWN:
|
||||||
if (ctx->opt)
|
if (ctx->opt)
|
||||||
check_typos(arg + 1, options);
|
check_typos(arg + 1, options);
|
||||||
if (internal_help && *ctx->opt == 'h')
|
if (internal_help && *ctx->opt == 'h')
|
||||||
goto show_usage;
|
goto show_usage;
|
||||||
goto unknown;
|
goto unknown;
|
||||||
|
case PARSE_OPT_NON_OPTION:
|
||||||
|
case PARSE_OPT_HELP:
|
||||||
|
case PARSE_OPT_COMPLETE:
|
||||||
|
BUG("parse_short_opt() cannot return these");
|
||||||
|
case PARSE_OPT_DONE:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (ctx->opt)
|
if (ctx->opt)
|
||||||
check_typos(arg + 1, options);
|
check_typos(arg + 1, options);
|
||||||
while (ctx->opt) {
|
while (ctx->opt) {
|
||||||
switch (parse_short_opt(ctx, options)) {
|
switch (parse_short_opt(ctx, options)) {
|
||||||
case -1:
|
case PARSE_OPT_ERROR:
|
||||||
return PARSE_OPT_ERROR;
|
return PARSE_OPT_ERROR;
|
||||||
case -2:
|
case PARSE_OPT_UNKNOWN:
|
||||||
if (internal_help && *ctx->opt == 'h')
|
if (internal_help && *ctx->opt == 'h')
|
||||||
goto show_usage;
|
goto show_usage;
|
||||||
|
|
||||||
@ -583,6 +641,12 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
|
|||||||
ctx->argv[0] = xstrdup(ctx->opt - 1);
|
ctx->argv[0] = xstrdup(ctx->opt - 1);
|
||||||
*(char *)ctx->argv[0] = '-';
|
*(char *)ctx->argv[0] = '-';
|
||||||
goto unknown;
|
goto unknown;
|
||||||
|
case PARSE_OPT_NON_OPTION:
|
||||||
|
case PARSE_OPT_COMPLETE:
|
||||||
|
case PARSE_OPT_HELP:
|
||||||
|
BUG("parse_short_opt() cannot return these");
|
||||||
|
case PARSE_OPT_DONE:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@ -601,15 +665,22 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
|
|||||||
if (internal_help && !strcmp(arg + 2, "help"))
|
if (internal_help && !strcmp(arg + 2, "help"))
|
||||||
goto show_usage;
|
goto show_usage;
|
||||||
switch (parse_long_opt(ctx, arg + 2, options)) {
|
switch (parse_long_opt(ctx, arg + 2, options)) {
|
||||||
case -1:
|
case PARSE_OPT_ERROR:
|
||||||
return PARSE_OPT_ERROR;
|
return PARSE_OPT_ERROR;
|
||||||
case -2:
|
case PARSE_OPT_UNKNOWN:
|
||||||
goto unknown;
|
goto unknown;
|
||||||
case -3:
|
case PARSE_OPT_HELP:
|
||||||
goto show_usage;
|
goto show_usage;
|
||||||
|
case PARSE_OPT_NON_OPTION:
|
||||||
|
case PARSE_OPT_COMPLETE:
|
||||||
|
BUG("parse_long_opt() cannot return these");
|
||||||
|
case PARSE_OPT_DONE:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
unknown:
|
unknown:
|
||||||
|
if (ctx->flags & PARSE_OPT_ONE_SHOT)
|
||||||
|
break;
|
||||||
if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
|
if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
|
||||||
return PARSE_OPT_UNKNOWN;
|
return PARSE_OPT_UNKNOWN;
|
||||||
ctx->out[ctx->cpidx++] = ctx->argv[0];
|
ctx->out[ctx->cpidx++] = ctx->argv[0];
|
||||||
@ -623,6 +694,9 @@ unknown:
|
|||||||
|
|
||||||
int parse_options_end(struct parse_opt_ctx_t *ctx)
|
int parse_options_end(struct parse_opt_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
|
if (ctx->flags & PARSE_OPT_ONE_SHOT)
|
||||||
|
return ctx->total - ctx->argc;
|
||||||
|
|
||||||
MOVE_ARRAY(ctx->out + ctx->cpidx, ctx->argv, ctx->argc);
|
MOVE_ARRAY(ctx->out + ctx->cpidx, ctx->argv, ctx->argc);
|
||||||
ctx->out[ctx->cpidx + ctx->argc] = NULL;
|
ctx->out[ctx->cpidx + ctx->argc] = NULL;
|
||||||
return ctx->cpidx + ctx->argc;
|
return ctx->cpidx + ctx->argc;
|
||||||
|
@ -10,6 +10,7 @@ enum parse_opt_type {
|
|||||||
/* options with no arguments */
|
/* options with no arguments */
|
||||||
OPTION_BIT,
|
OPTION_BIT,
|
||||||
OPTION_NEGBIT,
|
OPTION_NEGBIT,
|
||||||
|
OPTION_BITOP,
|
||||||
OPTION_COUNTUP,
|
OPTION_COUNTUP,
|
||||||
OPTION_SET_INT,
|
OPTION_SET_INT,
|
||||||
OPTION_CMDMODE,
|
OPTION_CMDMODE,
|
||||||
@ -27,7 +28,8 @@ enum parse_opt_flags {
|
|||||||
PARSE_OPT_STOP_AT_NON_OPTION = 2,
|
PARSE_OPT_STOP_AT_NON_OPTION = 2,
|
||||||
PARSE_OPT_KEEP_ARGV0 = 4,
|
PARSE_OPT_KEEP_ARGV0 = 4,
|
||||||
PARSE_OPT_KEEP_UNKNOWN = 8,
|
PARSE_OPT_KEEP_UNKNOWN = 8,
|
||||||
PARSE_OPT_NO_INTERNAL_HELP = 16
|
PARSE_OPT_NO_INTERNAL_HELP = 16,
|
||||||
|
PARSE_OPT_ONE_SHOT = 32
|
||||||
};
|
};
|
||||||
|
|
||||||
enum parse_opt_option_flags {
|
enum parse_opt_option_flags {
|
||||||
@ -47,8 +49,9 @@ struct option;
|
|||||||
typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
|
typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
|
||||||
|
|
||||||
struct parse_opt_ctx_t;
|
struct parse_opt_ctx_t;
|
||||||
typedef int parse_opt_ll_cb(struct parse_opt_ctx_t *ctx,
|
typedef enum parse_opt_result parse_opt_ll_cb(struct parse_opt_ctx_t *ctx,
|
||||||
const struct option *opt, int unset);
|
const struct option *opt,
|
||||||
|
const char *arg, int unset);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* `type`::
|
* `type`::
|
||||||
@ -98,13 +101,16 @@ typedef int parse_opt_ll_cb(struct parse_opt_ctx_t *ctx,
|
|||||||
* the option takes optional argument.
|
* the option takes optional argument.
|
||||||
*
|
*
|
||||||
* `callback`::
|
* `callback`::
|
||||||
* pointer to the callback to use for OPTION_CALLBACK or
|
* pointer to the callback to use for OPTION_CALLBACK
|
||||||
* OPTION_LOWLEVEL_CALLBACK.
|
|
||||||
*
|
*
|
||||||
* `defval`::
|
* `defval`::
|
||||||
* default value to fill (*->value) with for PARSE_OPT_OPTARG.
|
* default value to fill (*->value) with for PARSE_OPT_OPTARG.
|
||||||
* OPTION_{BIT,SET_INT} store the {mask,integer} to put in the value when met.
|
* OPTION_{BIT,SET_INT} store the {mask,integer} to put in the value when met.
|
||||||
* CALLBACKS can use it like they want.
|
* CALLBACKS can use it like they want.
|
||||||
|
*
|
||||||
|
* `ll_callback`::
|
||||||
|
* pointer to the callback to use for OPTION_LOWLEVEL_CALLBACK
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
struct option {
|
struct option {
|
||||||
enum parse_opt_type type;
|
enum parse_opt_type type;
|
||||||
@ -117,6 +123,8 @@ struct option {
|
|||||||
int flags;
|
int flags;
|
||||||
parse_opt_cb *callback;
|
parse_opt_cb *callback;
|
||||||
intptr_t defval;
|
intptr_t defval;
|
||||||
|
parse_opt_ll_cb *ll_callback;
|
||||||
|
intptr_t extra;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define OPT_BIT_F(s, l, v, h, b, f) { OPTION_BIT, (s), (l), (v), NULL, (h), \
|
#define OPT_BIT_F(s, l, v, h, b, f) { OPTION_BIT, (s), (l), (v), NULL, (h), \
|
||||||
@ -126,12 +134,17 @@ struct option {
|
|||||||
#define OPT_SET_INT_F(s, l, v, h, i, f) { OPTION_SET_INT, (s), (l), (v), NULL, \
|
#define OPT_SET_INT_F(s, l, v, h, i, f) { OPTION_SET_INT, (s), (l), (v), NULL, \
|
||||||
(h), PARSE_OPT_NOARG | (f), NULL, (i) }
|
(h), PARSE_OPT_NOARG | (f), NULL, (i) }
|
||||||
#define OPT_BOOL_F(s, l, v, h, f) OPT_SET_INT_F(s, l, v, h, 1, f)
|
#define OPT_BOOL_F(s, l, v, h, f) OPT_SET_INT_F(s, l, v, h, 1, f)
|
||||||
|
#define OPT_CALLBACK_F(s, l, v, a, h, f, cb) \
|
||||||
|
{ OPTION_CALLBACK, (s), (l), (v), (a), (h), (f), (cb) }
|
||||||
|
|
||||||
#define OPT_END() { OPTION_END }
|
#define OPT_END() { OPTION_END }
|
||||||
#define OPT_ARGUMENT(l, h) { OPTION_ARGUMENT, 0, (l), NULL, NULL, \
|
#define OPT_ARGUMENT(l, h) { OPTION_ARGUMENT, 0, (l), NULL, NULL, \
|
||||||
(h), PARSE_OPT_NOARG}
|
(h), PARSE_OPT_NOARG}
|
||||||
#define OPT_GROUP(h) { OPTION_GROUP, 0, NULL, NULL, NULL, (h) }
|
#define OPT_GROUP(h) { OPTION_GROUP, 0, NULL, NULL, NULL, (h) }
|
||||||
#define OPT_BIT(s, l, v, h, b) OPT_BIT_F(s, l, v, h, b, 0)
|
#define OPT_BIT(s, l, v, h, b) OPT_BIT_F(s, l, v, h, b, 0)
|
||||||
|
#define OPT_BITOP(s, l, v, h, set, clear) { OPTION_BITOP, (s), (l), (v), NULL, (h), \
|
||||||
|
PARSE_OPT_NOARG|PARSE_OPT_NONEG, NULL, \
|
||||||
|
(set), NULL, (clear) }
|
||||||
#define OPT_NEGBIT(s, l, v, h, b) { OPTION_NEGBIT, (s), (l), (v), NULL, \
|
#define OPT_NEGBIT(s, l, v, h, b) { OPTION_NEGBIT, (s), (l), (v), NULL, \
|
||||||
(h), PARSE_OPT_NOARG, NULL, (b) }
|
(h), PARSE_OPT_NOARG, NULL, (b) }
|
||||||
#define OPT_COUNTUP(s, l, v, h) OPT_COUNTUP_F(s, l, v, h, 0)
|
#define OPT_COUNTUP(s, l, v, h) OPT_COUNTUP_F(s, l, v, h, 0)
|
||||||
@ -153,8 +166,7 @@ struct option {
|
|||||||
#define OPT_EXPIRY_DATE(s, l, v, h) \
|
#define OPT_EXPIRY_DATE(s, l, v, h) \
|
||||||
{ OPTION_CALLBACK, (s), (l), (v), N_("expiry-date"),(h), 0, \
|
{ OPTION_CALLBACK, (s), (l), (v), N_("expiry-date"),(h), 0, \
|
||||||
parse_opt_expiry_date_cb }
|
parse_opt_expiry_date_cb }
|
||||||
#define OPT_CALLBACK(s, l, v, a, h, f) \
|
#define OPT_CALLBACK(s, l, v, a, h, f) OPT_CALLBACK_F(s, l, v, a, h, 0, f)
|
||||||
{ OPTION_CALLBACK, (s), (l), (v), (a), (h), 0, (f) }
|
|
||||||
#define OPT_NUMBER_CALLBACK(v, h, f) \
|
#define OPT_NUMBER_CALLBACK(v, h, f) \
|
||||||
{ OPTION_NUMBER, 0, NULL, (v), NULL, (h), \
|
{ OPTION_NUMBER, 0, NULL, (v), NULL, (h), \
|
||||||
PARSE_OPT_NOARG | PARSE_OPT_NONEG, (f) }
|
PARSE_OPT_NOARG | PARSE_OPT_NONEG, (f) }
|
||||||
@ -169,23 +181,31 @@ struct option {
|
|||||||
N_("no-op (backward compatibility)"), \
|
N_("no-op (backward compatibility)"), \
|
||||||
PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, parse_opt_noop_cb }
|
PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, parse_opt_noop_cb }
|
||||||
|
|
||||||
/* parse_options() will filter out the processed options and leave the
|
/*
|
||||||
* non-option arguments in argv[]. usagestr strings should be marked
|
* parse_options() will filter out the processed options and leave the
|
||||||
* for translation with N_().
|
* non-option arguments in argv[]. argv0 is assumed program name and
|
||||||
|
* skipped.
|
||||||
|
*
|
||||||
|
* usagestr strings should be marked for translation with N_().
|
||||||
|
*
|
||||||
* Returns the number of arguments left in argv[].
|
* Returns the number of arguments left in argv[].
|
||||||
|
*
|
||||||
|
* In one-shot mode, argv0 is not a program name, argv[] is left
|
||||||
|
* untouched and parse_options() returns the number of options
|
||||||
|
* processed.
|
||||||
*/
|
*/
|
||||||
extern int parse_options(int argc, const char **argv, const char *prefix,
|
int parse_options(int argc, const char **argv, const char *prefix,
|
||||||
const struct option *options,
|
const struct option *options,
|
||||||
const char * const usagestr[], int flags);
|
const char * const usagestr[], int flags);
|
||||||
|
|
||||||
extern NORETURN void usage_with_options(const char * const *usagestr,
|
NORETURN void usage_with_options(const char * const *usagestr,
|
||||||
const struct option *options);
|
const struct option *options);
|
||||||
|
|
||||||
extern NORETURN void usage_msg_opt(const char *msg,
|
NORETURN void usage_msg_opt(const char *msg,
|
||||||
const char * const *usagestr,
|
const char * const *usagestr,
|
||||||
const struct option *options);
|
const struct option *options);
|
||||||
|
|
||||||
extern int optbug(const struct option *opt, const char *reason);
|
int optbug(const struct option *opt, const char *reason);
|
||||||
const char *optname(const struct option *opt, int flags);
|
const char *optname(const struct option *opt, int flags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -204,12 +224,12 @@ const char *optname(const struct option *opt, int flags);
|
|||||||
|
|
||||||
/*----- incremental advanced APIs -----*/
|
/*----- incremental advanced APIs -----*/
|
||||||
|
|
||||||
enum {
|
enum parse_opt_result {
|
||||||
PARSE_OPT_COMPLETE = -2,
|
PARSE_OPT_COMPLETE = -3,
|
||||||
PARSE_OPT_HELP = -1,
|
PARSE_OPT_HELP = -2,
|
||||||
PARSE_OPT_DONE,
|
PARSE_OPT_ERROR = -1, /* must be the same as error() */
|
||||||
|
PARSE_OPT_DONE = 0, /* fixed so that "return 0" works */
|
||||||
PARSE_OPT_NON_OPTION,
|
PARSE_OPT_NON_OPTION,
|
||||||
PARSE_OPT_ERROR,
|
|
||||||
PARSE_OPT_UNKNOWN
|
PARSE_OPT_UNKNOWN
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -227,31 +247,31 @@ struct parse_opt_ctx_t {
|
|||||||
const char *prefix;
|
const char *prefix;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void parse_options_start(struct parse_opt_ctx_t *ctx,
|
void parse_options_start(struct parse_opt_ctx_t *ctx,
|
||||||
int argc, const char **argv, const char *prefix,
|
int argc, const char **argv, const char *prefix,
|
||||||
const struct option *options, int flags);
|
const struct option *options, int flags);
|
||||||
|
|
||||||
extern int parse_options_step(struct parse_opt_ctx_t *ctx,
|
int parse_options_step(struct parse_opt_ctx_t *ctx,
|
||||||
const struct option *options,
|
const struct option *options,
|
||||||
const char * const usagestr[]);
|
const char * const usagestr[]);
|
||||||
|
|
||||||
extern int parse_options_end(struct parse_opt_ctx_t *ctx);
|
int parse_options_end(struct parse_opt_ctx_t *ctx);
|
||||||
|
|
||||||
extern struct option *parse_options_concat(struct option *a, struct option *b);
|
struct option *parse_options_concat(struct option *a, struct option *b);
|
||||||
|
|
||||||
/*----- some often used options -----*/
|
/*----- some often used options -----*/
|
||||||
extern int parse_opt_abbrev_cb(const struct option *, const char *, int);
|
int parse_opt_abbrev_cb(const struct option *, const char *, int);
|
||||||
extern int parse_opt_expiry_date_cb(const struct option *, const char *, int);
|
int parse_opt_expiry_date_cb(const struct option *, const char *, int);
|
||||||
extern int parse_opt_color_flag_cb(const struct option *, const char *, int);
|
int parse_opt_color_flag_cb(const struct option *, const char *, int);
|
||||||
extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
|
int parse_opt_verbosity_cb(const struct option *, const char *, int);
|
||||||
extern int parse_opt_object_name(const struct option *, const char *, int);
|
int parse_opt_object_name(const struct option *, const char *, int);
|
||||||
extern int parse_opt_commits(const struct option *, const char *, int);
|
int parse_opt_commits(const struct option *, const char *, int);
|
||||||
extern int parse_opt_tertiary(const struct option *, const char *, int);
|
int parse_opt_tertiary(const struct option *, const char *, int);
|
||||||
extern int parse_opt_string_list(const struct option *, const char *, int);
|
int parse_opt_string_list(const struct option *, const char *, int);
|
||||||
extern int parse_opt_noop_cb(const struct option *, const char *, int);
|
int parse_opt_noop_cb(const struct option *, const char *, int);
|
||||||
extern int parse_opt_unknown_cb(const struct option *, const char *, int);
|
int parse_opt_unknown_cb(struct parse_opt_ctx_t *ctx, const struct option *, const char *, int);
|
||||||
extern int parse_opt_passthru(const struct option *, const char *, int);
|
int parse_opt_passthru(const struct option *, const char *, int);
|
||||||
extern int parse_opt_passthru_argv(const struct option *, const char *, int);
|
int parse_opt_passthru_argv(const struct option *, const char *, int);
|
||||||
|
|
||||||
#define OPT__VERBOSE(var, h) OPT_COUNTUP('v', "verbose", (var), (h))
|
#define OPT__VERBOSE(var, h) OPT_COUNTUP('v', "verbose", (var), (h))
|
||||||
#define OPT__QUIET(var, h) OPT_COUNTUP('q', "quiet", (var), (h))
|
#define OPT__QUIET(var, h) OPT_COUNTUP('q', "quiet", (var), (h))
|
||||||
|
@ -546,7 +546,7 @@ do
|
|||||||
done >actual
|
done >actual
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
test_expect_success SYMLINKS 'difftool --dir-diff --symlink without unstaged changes' '
|
test_expect_success SYMLINKS 'difftool --dir-diff --symlinks without unstaged changes' '
|
||||||
cat >expect <<-EOF &&
|
cat >expect <<-EOF &&
|
||||||
file
|
file
|
||||||
$PWD/file
|
$PWD/file
|
||||||
@ -555,7 +555,7 @@ test_expect_success SYMLINKS 'difftool --dir-diff --symlink without unstaged cha
|
|||||||
sub/sub
|
sub/sub
|
||||||
$PWD/sub/sub
|
$PWD/sub/sub
|
||||||
EOF
|
EOF
|
||||||
git difftool --dir-diff --symlink \
|
git difftool --dir-diff --symlinks \
|
||||||
--extcmd "./.git/CHECK_SYMLINKS" branch HEAD &&
|
--extcmd "./.git/CHECK_SYMLINKS" branch HEAD &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
Reference in New Issue
Block a user