diff options
Diffstat (limited to 'diff.c')
-rw-r--r-- | diff.c | 1275 |
1 files changed, 779 insertions, 496 deletions
@@ -23,7 +23,9 @@ #include "argv-array.h" #include "graph.h" #include "packfile.h" +#include "parse-options.h" #include "help.h" +#include "fetch-object.h" #ifdef NO_FAST_WORKING_DIRECTORY #define FAST_WORKING_DIRECTORY 0 @@ -103,11 +105,6 @@ static const char *color_diff_slots[] = { [DIFF_FILE_NEW_BOLD] = "newBold", }; -static NORETURN void die_want_option(const char *option_name) -{ - die(_("option '%s' requires a value"), option_name); -} - define_list_config_array_extra(color_diff_slots, {"plain"}); static int parse_diff_color_slot(const char *var) @@ -178,6 +175,10 @@ static int parse_submodule_params(struct diff_options *options, const char *valu options->submodule_format = DIFF_SUBMODULE_SHORT; else if (!strcmp(value, "diff")) options->submodule_format = DIFF_SUBMODULE_INLINE_DIFF; + /* + * Please update $__git_diff_submodule_formats in + * git-completion.bash when you add new formats. + */ else return -1; return 0; @@ -204,6 +205,10 @@ long parse_algorithm_value(const char *value) return XDF_PATIENCE_DIFF; else if (!strcasecmp(value, "histogram")) return XDF_HISTOGRAM_DIFF; + /* + * Please update $__git_diff_algorithms in git-completion.bash + * when you add new algorithms. + */ return -1; } @@ -1613,8 +1618,7 @@ static int new_blank_line_at_eof(struct emit_callback *ecbdata, const char *line return ws_blank_line(line, len, ecbdata->ws_rule); } -static void emit_add_line(const char *reset, - struct emit_callback *ecbdata, +static void emit_add_line(struct emit_callback *ecbdata, const char *line, int len) { unsigned flags = WSEH_NEW | ecbdata->ws_rule; @@ -1624,16 +1628,14 @@ static void emit_add_line(const char *reset, emit_diff_symbol(ecbdata->opt, DIFF_SYMBOL_PLUS, line, len, flags); } -static void emit_del_line(const char *reset, - struct emit_callback *ecbdata, +static void emit_del_line(struct emit_callback *ecbdata, const char *line, int len) { unsigned flags = WSEH_OLD | ecbdata->ws_rule; emit_diff_symbol(ecbdata->opt, DIFF_SYMBOL_MINUS, line, len, flags); } -static void emit_context_line(const char *reset, - struct emit_callback *ecbdata, +static void emit_context_line(struct emit_callback *ecbdata, const char *line, int len) { unsigned flags = WSEH_CONTEXT | ecbdata->ws_rule; @@ -1742,7 +1744,6 @@ static void emit_rewrite_lines(struct emit_callback *ecb, int prefix, const char *data, int size) { const char *endp = NULL; - const char *reset = diff_get_color(ecb->color_diff, DIFF_RESET); while (0 < size) { int len; @@ -1751,10 +1752,10 @@ static void emit_rewrite_lines(struct emit_callback *ecb, len = endp ? (endp - data + 1) : size; if (prefix != '+') { ecb->lno_in_preimage++; - emit_del_line(reset, ecb, data, len); + emit_del_line(ecb, data, len); } else { ecb->lno_in_postimage++; - emit_add_line(reset, ecb, data, len); + emit_add_line(ecb, data, len); } size -= len; data += len; @@ -2291,7 +2292,7 @@ const char *diff_line_prefix(struct diff_options *opt) return msgbuf->buf; } -static unsigned long sane_truncate_line(struct emit_callback *ecb, char *line, unsigned long len) +static unsigned long sane_truncate_line(char *line, unsigned long len) { const char *cp; unsigned long allot; @@ -2325,7 +2326,6 @@ static void find_lno(const char *line, struct emit_callback *ecbdata) static void fn_out_consume(void *priv, char *line, unsigned long len) { struct emit_callback *ecbdata = priv; - const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET); struct diff_options *o = ecbdata->opt; o->found_changes = 1; @@ -2356,7 +2356,7 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) if (line[0] == '@') { if (ecbdata->diff_words) diff_words_flush(ecbdata); - len = sane_truncate_line(ecbdata, line, len); + len = sane_truncate_line(line, len); find_lno(line, ecbdata); emit_hunk_header(ecbdata, line, len); return; @@ -2392,16 +2392,16 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) switch (line[0]) { case '+': ecbdata->lno_in_postimage++; - emit_add_line(reset, ecbdata, line + 1, len - 1); + emit_add_line(ecbdata, line + 1, len - 1); break; case '-': ecbdata->lno_in_preimage++; - emit_del_line(reset, ecbdata, line + 1, len - 1); + emit_del_line(ecbdata, line + 1, len - 1); break; case ' ': ecbdata->lno_in_postimage++; ecbdata->lno_in_preimage++; - emit_context_line(reset, ecbdata, line + 1, len - 1); + emit_context_line(ecbdata, line + 1, len - 1); break; default: /* incomplete line at the end */ @@ -4183,7 +4183,6 @@ static void run_external_diff(const char *pgm, struct diff_filespec *one, struct diff_filespec *two, const char *xfrm_msg, - int complete_rewrite, struct diff_options *o) { struct argv_array argv = ARGV_ARRAY_INIT; @@ -4343,8 +4342,7 @@ static void run_diff_cmd(const char *pgm, } if (pgm) { - run_external_diff(pgm, name, other, one, two, xfrm_msg, - complete_rewrite, o); + run_external_diff(pgm, name, other, one, two, xfrm_msg, o); return; } if (one && two) @@ -4493,6 +4491,8 @@ static void run_checkdiff(struct diff_filepair *p, struct diff_options *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) { memcpy(options, &default_diff_options, sizeof(*options)); @@ -4534,6 +4534,8 @@ void repo_diff_setup(struct repository *r, struct diff_options *options) options->color_moved = diff_color_moved_default; options->color_moved_ws_handling = diff_color_moved_ws_default; + + prep_parse_options(options); } void diff_setup_done(struct diff_options *options) @@ -4637,68 +4639,8 @@ void diff_setup_done(struct diff_options *options) if (!options->use_color || external_diff()) options->color_moved = 0; -} - -static int opt_arg(const char *arg, int arg_short, const char *arg_long, int *val) -{ - char c, *eq; - int len; - - if (*arg != '-') - return 0; - c = *++arg; - if (!c) - return 0; - if (c == arg_short) { - c = *++arg; - if (!c) - return 1; - if (val && isdigit(c)) { - char *end; - int n = strtoul(arg, &end, 10); - if (*end) - return 0; - *val = n; - return 1; - } - return 0; - } - if (c != '-') - return 0; - arg++; - eq = strchrnul(arg, '='); - len = eq - arg; - if (!len || strncmp(arg, arg_long, len)) - return 0; - if (*eq) { - int n; - char *end; - if (!isdigit(*++eq)) - return 0; - n = strtoul(eq, &end, 10); - if (*end) - return 0; - *val = n; - } - return 1; -} - -static int diff_scoreopt_parse(const char *opt); -static inline int short_opt(char opt, const char **argv, - const char **optarg) -{ - const char *arg = argv[0]; - if (arg[0] != '-' || arg[1] != opt) - return 0; - if (arg[2] != '\0') { - *optarg = arg + 2; - return 1; - } - if (!argv[1]) - die("Option '%c' requires a value", opt); - *optarg = argv[1]; - return 2; + FREE_AND_NULL(options->parseopts); } int parse_long_opt(const char *opt, const char **argv, @@ -4722,77 +4664,56 @@ int parse_long_opt(const char *opt, const char **argv, return 2; } -static int stat_opt(struct diff_options *options, const char **av) +static int diff_opt_stat(const struct option *opt, const char *value, int unset) { - const char *arg = av[0]; - char *end; + struct diff_options *options = opt->value; int width = options->stat_width; int name_width = options->stat_name_width; int graph_width = options->stat_graph_width; int count = options->stat_count; - int argcount = 1; + char *end; - if (!skip_prefix(arg, "--stat", &arg)) - BUG("stat option does not begin with --stat: %s", arg); - end = (char *)arg; + BUG_ON_OPT_NEG(unset); - switch (*arg) { - case '-': - if (skip_prefix(arg, "-width", &arg)) { - if (*arg == '=') - width = strtoul(arg + 1, &end, 10); - else if (!*arg && !av[1]) - die_want_option("--stat-width"); - else if (!*arg) { - width = strtoul(av[1], &end, 10); - argcount = 2; - } - } else if (skip_prefix(arg, "-name-width", &arg)) { - if (*arg == '=') - name_width = strtoul(arg + 1, &end, 10); - else if (!*arg && !av[1]) - die_want_option("--stat-name-width"); - else if (!*arg) { - name_width = strtoul(av[1], &end, 10); - argcount = 2; - } - } else if (skip_prefix(arg, "-graph-width", &arg)) { - if (*arg == '=') - graph_width = strtoul(arg + 1, &end, 10); - else if (!*arg && !av[1]) - die_want_option("--stat-graph-width"); - else if (!*arg) { - graph_width = strtoul(av[1], &end, 10); - argcount = 2; - } - } else if (skip_prefix(arg, "-count", &arg)) { - if (*arg == '=') - count = strtoul(arg + 1, &end, 10); - else if (!*arg && !av[1]) - die_want_option("--stat-count"); - else if (!*arg) { - count = strtoul(av[1], &end, 10); - argcount = 2; - } + if (!strcmp(opt->long_name, "stat")) { + if (value) { + width = strtoul(value, &end, 10); + if (*end == ',') + name_width = strtoul(end+1, &end, 10); + if (*end == ',') + count = strtoul(end+1, &end, 10); + if (*end) + return error(_("invalid --stat value: %s"), value); } - break; - case '=': - width = strtoul(arg+1, &end, 10); - if (*end == ',') - name_width = strtoul(end+1, &end, 10); - if (*end == ',') - count = strtoul(end+1, &end, 10); - } + } else if (!strcmp(opt->long_name, "stat-width")) { + width = strtoul(value, &end, 10); + if (*end) + return error(_("%s expects a numerical value"), + opt->long_name); + } else if (!strcmp(opt->long_name, "stat-name-width")) { + name_width = strtoul(value, &end, 10); + if (*end) + return error(_("%s expects a numerical value"), + opt->long_name); + } else if (!strcmp(opt->long_name, "stat-graph-width")) { + graph_width = strtoul(value, &end, 10); + if (*end) + return error(_("%s expects a numerical value"), + opt->long_name); + } else if (!strcmp(opt->long_name, "stat-count")) { + count = strtoul(value, &end, 10); + if (*end) + return error(_("%s expects a numerical value"), + opt->long_name); + } else + BUG("%s should not get here", opt->long_name); - /* Important! This checks all the error cases! */ - if (*end) - return 0; options->output_format |= DIFF_FORMAT_DIFFSTAT; options->stat_name_width = name_width; options->stat_graph_width = graph_width; options->stat_width = width; options->stat_count = count; - return argcount; + return 0; } static int parse_dirstat_opt(struct diff_options *options, const char *params) @@ -4810,14 +4731,6 @@ static int parse_dirstat_opt(struct diff_options *options, const char *params) return 1; } -static int parse_submodule_opt(struct diff_options *options, const char *value) -{ - if (parse_submodule_params(options, value)) - die(_("Failed to parse --submodule option parameter: '%s'"), - value); - return 1; -} - static const char diff_status_letters[] = { DIFF_STATUS_ADDED, DIFF_STATUS_COPIED, @@ -4849,10 +4762,19 @@ static unsigned filter_bit_tst(char status, const struct diff_options *opt) return opt->filter & filter_bit[(int) status]; } -static int parse_diff_filter_opt(const char *optarg, struct diff_options *opt) +unsigned diff_filter_bit(char status) +{ + prepare_filter_bits(); + return filter_bit[(int) status]; +} + +static int diff_opt_diff_filter(const struct option *option, + const char *optarg, int unset) { + struct diff_options *opt = option->value; int i, optch; + BUG_ON_OPT_NEG(unset); prepare_filter_bits(); /* @@ -4883,7 +4805,8 @@ static int parse_diff_filter_opt(const char *optarg, struct diff_options *opt) bit = (0 <= optch && optch <= 'Z') ? filter_bit[optch] : 0; if (!bit) - return optarg[i]; + return error(_("unknown change class '%c' in --diff-filter=%s"), + optarg[i], optarg); if (negate) opt->filter &= ~bit; else @@ -4898,25 +4821,29 @@ static void enable_patch_output(int *fmt) *fmt |= DIFF_FORMAT_PATCH; } -static int parse_ws_error_highlight_opt(struct diff_options *opt, const char *arg) +static int diff_opt_ws_error_highlight(const struct option *option, + const char *arg, int unset) { + struct diff_options *opt = option->value; int val = parse_ws_error_highlight(arg); - if (val < 0) { - error("unknown value after ws-error-highlight=%.*s", - -1 - val, arg); - return 0; - } + BUG_ON_OPT_NEG(unset); + if (val < 0) + return error(_("unknown value after ws-error-highlight=%.*s"), + -1 - val, arg); opt->ws_error_highlight = val; - return 1; + return 0; } -static int parse_objfind_opt(struct diff_options *opt, const char *arg) +static int diff_opt_find_object(const struct option *option, + const char *arg, int unset) { + struct diff_options *opt = option->value; struct object_id oid; + BUG_ON_OPT_NEG(unset); if (get_oid(arg, &oid)) - return error("unable to resolve '%s'", arg); + return error(_("unable to resolve '%s'"), arg); if (!opt->objfind) opt->objfind = xcalloc(1, sizeof(*opt->objfind)); @@ -4925,207 +4852,384 @@ static int parse_objfind_opt(struct diff_options *opt, const char *arg) opt->flags.recursive = 1; opt->flags.tree_in_recursive = 1; oidset_insert(opt->objfind, &oid); - return 1; + return 0; } -int diff_opt_parse(struct diff_options *options, - const char **av, int ac, const char *prefix) +static int diff_opt_anchored(const struct option *opt, + const char *arg, int unset) { - const char *arg = av[0]; - const char *optarg; - int argcount; + struct diff_options *options = opt->value; - if (!prefix) - prefix = ""; + BUG_ON_OPT_NEG(unset); + options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF); + ALLOC_GROW(options->anchors, options->anchors_nr + 1, + options->anchors_alloc); + options->anchors[options->anchors_nr++] = xstrdup(arg); + return 0; +} - /* Output format options */ - if (!strcmp(arg, "-p") || !strcmp(arg, "-u") || !strcmp(arg, "--patch") - || 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); - options->output_format |= DIFF_FORMAT_RAW; - } else if (!strcmp(arg, "--numstat")) - options->output_format |= DIFF_FORMAT_NUMSTAT; - else if (!strcmp(arg, "--shortstat")) - options->output_format |= DIFF_FORMAT_SHORTSTAT; - else if (skip_prefix(arg, "-X", &arg) || - skip_to_optional_arg(arg, "--dirstat", &arg)) - return parse_dirstat_opt(options, arg); - else if (!strcmp(arg, "--cumulative")) - return parse_dirstat_opt(options, "cumulative"); - else if (skip_to_optional_arg(arg, "--dirstat-by-file", &arg)) { - parse_dirstat_opt(options, "files"); - return parse_dirstat_opt(options, arg); - } - else if (!strcmp(arg, "--check")) - options->output_format |= DIFF_FORMAT_CHECKDIFF; - else if (!strcmp(arg, "--summary")) - options->output_format |= DIFF_FORMAT_SUMMARY; - else if (!strcmp(arg, "--patch-with-stat")) { - enable_patch_output(&options->output_format); - options->output_format |= DIFF_FORMAT_DIFFSTAT; - } else if (!strcmp(arg, "--name-only")) - options->output_format |= DIFF_FORMAT_NAME; - else if (!strcmp(arg, "--name-status")) - options->output_format |= DIFF_FORMAT_NAME_STATUS; - else if (!strcmp(arg, "-s") || !strcmp(arg, "--no-patch")) - options->output_format |= DIFF_FORMAT_NO_OUTPUT; - else if (starts_with(arg, "--stat")) - /* --stat, --stat-width, --stat-name-width, or --stat-count */ - return stat_opt(options, av); - else if (!strcmp(arg, "--compact-summary")) { - options->flags.stat_with_summary = 1; - options->output_format |= DIFF_FORMAT_DIFFSTAT; - } else if (!strcmp(arg, "--no-compact-summary")) - options->flags.stat_with_summary = 0; - else if (skip_prefix(arg, "--output-indicator-new=", &arg)) - options->output_indicators[OUTPUT_INDICATOR_NEW] = arg[0]; - else if (skip_prefix(arg, "--output-indicator-old=", &arg)) - options->output_indicators[OUTPUT_INDICATOR_OLD] = arg[0]; - else if (skip_prefix(arg, "--output-indicator-context=", &arg)) - options->output_indicators[OUTPUT_INDICATOR_CONTEXT] = arg[0]; - - /* renames options */ - else if (starts_with(arg, "-B") || - skip_to_optional_arg(arg, "--break-rewrites", NULL)) { - if ((options->break_opt = diff_scoreopt_parse(arg)) == -1) - return error("invalid argument to -B: %s", arg+2); - } - else if (starts_with(arg, "-M") || - skip_to_optional_arg(arg, "--find-renames", NULL)) { - if ((options->rename_score = diff_scoreopt_parse(arg)) == -1) - return error("invalid argument to -M: %s", arg+2); - options->detect_rename = DIFF_DETECT_RENAME; - } - else if (!strcmp(arg, "-D") || !strcmp(arg, "--irreversible-delete")) { - options->irreversible_delete = 1; - } - else if (starts_with(arg, "-C") || - skip_to_optional_arg(arg, "--find-copies", NULL)) { - if (options->detect_rename == DIFF_DETECT_COPY) - options->flags.find_copies_harder = 1; - if ((options->rename_score = diff_scoreopt_parse(arg)) == -1) - return error("invalid argument to -C: %s", arg+2); - options->detect_rename = DIFF_DETECT_COPY; +static int diff_opt_binary(const struct option *opt, + const char *arg, int unset) +{ + struct diff_options *options = opt->value; + + BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); + enable_patch_output(&options->output_format); + options->flags.binary = 1; + return 0; +} + +static int diff_opt_break_rewrites(const struct option *opt, + const char *arg, int unset) +{ + int *break_opt = opt->value; + int opt1, opt2; + + BUG_ON_OPT_NEG(unset); + if (!arg) + arg = ""; + opt1 = parse_rename_score(&arg); + if (*arg == 0) + opt2 = 0; + else if (*arg != '/') + return error(_("%s expects <n>/<m> form"), opt->long_name); + else { + arg++; + opt2 = parse_rename_score(&arg); } - else if (!strcmp(arg, "--no-renames")) - options->detect_rename = 0; - else if (!strcmp(arg, "--rename-empty")) - options->flags.rename_empty = 1; - else if (!strcmp(arg, "--no-rename-empty")) - options->flags.rename_empty = 0; - else if (skip_to_optional_arg_default(arg, "--relative", &arg, NULL)) { - options->flags.relative_name = 1; - if (arg) - options->prefix = arg; - } - - /* xdiff options */ - else if (!strcmp(arg, "--minimal")) - DIFF_XDL_SET(options, NEED_MINIMAL); - else if (!strcmp(arg, "--no-minimal")) - DIFF_XDL_CLR(options, NEED_MINIMAL); - else if (!strcmp(arg, "-w") || !strcmp(arg, "--ignore-all-space")) - DIFF_XDL_SET(options, IGNORE_WHITESPACE); - else if (!strcmp(arg, "-b") || !strcmp(arg, "--ignore-space-change")) - DIFF_XDL_SET(options, IGNORE_WHITESPACE_CHANGE); - else if (!strcmp(arg, "--ignore-space-at-eol")) - DIFF_XDL_SET(options, IGNORE_WHITESPACE_AT_EOL); - else if (!strcmp(arg, "--ignore-cr-at-eol")) - DIFF_XDL_SET(options, IGNORE_CR_AT_EOL); - else if (!strcmp(arg, "--ignore-blank-lines")) - DIFF_XDL_SET(options, IGNORE_BLANK_LINES); - else if (!strcmp(arg, "--indent-heuristic")) - DIFF_XDL_SET(options, INDENT_HEURISTIC); - else if (!strcmp(arg, "--no-indent-heuristic")) - DIFF_XDL_CLR(options, INDENT_HEURISTIC); - else if (!strcmp(arg, "--patience")) { - int i; - options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF); - /* - * Both --patience and --anchored use PATIENCE_DIFF - * internally, so remove any anchors previously - * specified. - */ - for (i = 0; i < options->anchors_nr; i++) - free(options->anchors[i]); - options->anchors_nr = 0; - } else if (!strcmp(arg, "--histogram")) - options->xdl_opts = DIFF_WITH_ALG(options, HISTOGRAM_DIFF); - else if ((argcount = parse_long_opt("diff-algorithm", av, &optarg))) { - long value = parse_algorithm_value(optarg); - if (value < 0) - return error("option diff-algorithm accepts \"myers\", " - "\"minimal\", \"patience\" and \"histogram\""); - /* clear out previous settings */ - DIFF_XDL_CLR(options, NEED_MINIMAL); - options->xdl_opts &= ~XDF_DIFF_ALGORITHM_MASK; - options->xdl_opts |= value; - return argcount; - } else if (skip_prefix(arg, "--anchored=", &arg)) { - options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF); - ALLOC_GROW(options->anchors, options->anchors_nr + 1, - options->anchors_alloc); - options->anchors[options->anchors_nr++] = xstrdup(arg); - } - - /* flags options */ - else if (!strcmp(arg, "--binary")) { - enable_patch_output(&options->output_format); - options->flags.binary = 1; - } - else if (!strcmp(arg, "--full-index")) - options->flags.full_index = 1; - else if (!strcmp(arg, "-a") || !strcmp(arg, "--text")) - options->flags.text = 1; - else if (!strcmp(arg, "-R")) - options->flags.reverse_diff = 1; - else if (!strcmp(arg, "--find-copies-harder")) - options->flags.find_copies_harder = 1; - else if (!strcmp(arg, "--follow")) - options->flags.follow_renames = 1; - else if (!strcmp(arg, "--no-follow")) { - options->flags.follow_renames = 0; - options->flags.default_follow_renames = 0; - } else if (skip_to_optional_arg_default(arg, "--color", &arg, "always")) { - int value = git_config_colorbool(NULL, arg); - if (value < 0) - return error("option `color' expects \"always\", \"auto\", or \"never\""); - options->use_color = value; - } - else if (!strcmp(arg, "--no-color")) - options->use_color = 0; - else if (!strcmp(arg, "--color-moved")) { + if (*arg != 0) + return error(_("%s expects <n>/<m> form"), opt->long_name); + *break_opt = opt1 | (opt2 << 16); + return 0; +} + +static int diff_opt_char(const struct option *opt, + const char *arg, int unset) +{ + char *value = opt->value; + + BUG_ON_OPT_NEG(unset); + if (arg[1]) + return error(_("%s expects a character, got '%s'"), + opt->long_name, arg); + *value = arg[0]; + return 0; +} + +static int diff_opt_color_moved(const struct option *opt, + const char *arg, int unset) +{ + struct diff_options *options = opt->value; + + if (unset) { + options->color_moved = COLOR_MOVED_NO; + } else if (!arg) { if (diff_color_moved_default) options->color_moved = diff_color_moved_default; if (options->color_moved == COLOR_MOVED_NO) options->color_moved = COLOR_MOVED_DEFAULT; - } else if (!strcmp(arg, "--no-color-moved")) - options->color_moved = COLOR_MOVED_NO; - else if (skip_prefix(arg, "--color-moved=", &arg)) { + } else { int cm = parse_color_moved(arg); if (cm < 0) - return error("bad --color-moved argument: %s", arg); + return error(_("bad --color-moved argument: %s"), arg); options->color_moved = cm; - } else if (!strcmp(arg, "--no-color-moved-ws")) { + } + return 0; +} + +static int diff_opt_color_moved_ws(const struct option *opt, + const char *arg, int unset) +{ + struct diff_options *options = opt->value; + unsigned cm; + + if (unset) { options->color_moved_ws_handling = 0; - } else if (skip_prefix(arg, "--color-moved-ws=", &arg)) { - unsigned cm = parse_color_moved_ws(arg); - if (cm & COLOR_MOVED_WS_ERROR) - return -1; - options->color_moved_ws_handling = cm; - } else if (skip_to_optional_arg_default(arg, "--color-words", &options->word_regex, NULL)) { - options->use_color = 1; - options->word_diff = DIFF_WORDS_COLOR; + return 0; } - else if (!strcmp(arg, "--word-diff")) { - if (options->word_diff == DIFF_WORDS_NONE) - options->word_diff = DIFF_WORDS_PLAIN; + + cm = parse_color_moved_ws(arg); + if (cm & COLOR_MOVED_WS_ERROR) + return error(_("invalid mode '%s' in --color-moved-ws"), arg); + options->color_moved_ws_handling = cm; + return 0; +} + +static int diff_opt_color_words(const struct option *opt, + const char *arg, int unset) +{ + struct diff_options *options = opt->value; + + BUG_ON_OPT_NEG(unset); + options->use_color = 1; + options->word_diff = DIFF_WORDS_COLOR; + options->word_regex = arg; + return 0; +} + +static int diff_opt_compact_summary(const struct option *opt, + const char *arg, int unset) +{ + struct diff_options *options = opt->value; + + BUG_ON_OPT_ARG(arg); + if (unset) { + options->flags.stat_with_summary = 0; + } else { + options->flags.stat_with_summary = 1; + options->output_format |= DIFF_FORMAT_DIFFSTAT; } - else if (skip_prefix(arg, "--word-diff=", &arg)) { + return 0; +} + +static int diff_opt_diff_algorithm(const struct option *opt, + const char *arg, int unset) +{ + struct diff_options *options = opt->value; + long value = parse_algorithm_value(arg); + + BUG_ON_OPT_NEG(unset); + if (value < 0) + return error(_("option diff-algorithm accepts \"myers\", " + "\"minimal\", \"patience\" and \"histogram\"")); + + /* clear out previous settings */ + DIFF_XDL_CLR(options, NEED_MINIMAL); + options->xdl_opts &= ~XDF_DIFF_ALGORITHM_MASK; + options->xdl_opts |= value; + return 0; +} + +static int diff_opt_dirstat(const struct option *opt, + const char *arg, int unset) +{ + struct diff_options *options = opt->value; + + BUG_ON_OPT_NEG(unset); + if (!strcmp(opt->long_name, "cumulative")) { + if (arg) + BUG("how come --cumulative take a value?"); + arg = "cumulative"; + } else if (!strcmp(opt->long_name, "dirstat-by-file")) + parse_dirstat_opt(options, "files"); + parse_dirstat_opt(options, arg ? arg : ""); + return 0; +} + +static int diff_opt_find_copies(const struct option *opt, + const char *arg, int unset) +{ + struct diff_options *options = opt->value; + + BUG_ON_OPT_NEG(unset); + if (!arg) + arg = ""; + options->rename_score = parse_rename_score(&arg); + if (*arg != 0) + return error(_("invalid argument to %s"), opt->long_name); + + if (options->detect_rename == DIFF_DETECT_COPY) + options->flags.find_copies_harder = 1; + else + options->detect_rename = DIFF_DETECT_COPY; + + return 0; +} + +static int diff_opt_find_renames(const struct option *opt, + const char *arg, int unset) +{ + struct diff_options *options = opt->value; + + BUG_ON_OPT_NEG(unset); + if (!arg) + arg = ""; + options->rename_score = parse_rename_score(&arg); + if (*arg != 0) + return error(_("invalid argument to %s"), opt->long_name); + + options->detect_rename = DIFF_DETECT_RENAME; + return 0; +} + +static int diff_opt_follow(const struct option *opt, + const char *arg, int unset) +{ + struct diff_options *options = opt->value; + + BUG_ON_OPT_ARG(arg); + if (unset) { + options->flags.follow_renames = 0; + options->flags.default_follow_renames = 0; + } else { + options->flags.follow_renames = 1; + } + return 0; +} + +static int diff_opt_ignore_submodules(const struct option *opt, + const char *arg, int unset) +{ + struct diff_options *options = opt->value; + + BUG_ON_OPT_NEG(unset); + if (!arg) + arg = "all"; + options->flags.override_submodule_config = 1; + handle_ignore_submodules_arg(options, arg); + return 0; +} + +static int diff_opt_line_prefix(const struct option *opt, + const char *optarg, int unset) +{ + struct diff_options *options = opt->value; + + BUG_ON_OPT_NEG(unset); + options->line_prefix = optarg; + options->line_prefix_length = strlen(options->line_prefix); + graph_setup_line_prefix(options); + return 0; +} + +static int diff_opt_no_prefix(const struct option *opt, + const char *optarg, int unset) +{ + struct diff_options *options = opt->value; + + BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(optarg); + options->a_prefix = ""; + options->b_prefix = ""; + return 0; +} + +static enum parse_opt_result diff_opt_output(struct parse_opt_ctx_t *ctx, + const struct option *opt, + const char *arg, int unset) +{ + struct diff_options *options = opt->value; + char *path; + + BUG_ON_OPT_NEG(unset); + path = prefix_filename(ctx->prefix, arg); + options->file = xfopen(path, "w"); + options->close_file = 1; + if (options->use_color != GIT_COLOR_ALWAYS) + options->use_color = GIT_COLOR_NEVER; + free(path); + return 0; +} + +static int diff_opt_patience(const struct option *opt, + const char *arg, int unset) +{ + struct diff_options *options = opt->value; + int i; + + BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); + options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF); + /* + * Both --patience and --anchored use PATIENCE_DIFF + * internally, so remove any anchors previously + * specified. + */ + for (i = 0; i < options->anchors_nr; i++) + free(options->anchors[i]); + options->anchors_nr = 0; + return 0; +} + +static int diff_opt_pickaxe_regex(const struct option *opt, + const char *arg, int unset) +{ + struct diff_options *options = opt->value; + + BUG_ON_OPT_NEG(unset); + options->pickaxe = arg; + options->pickaxe_opts |= DIFF_PICKAXE_KIND_G; + return 0; +} + +static int diff_opt_pickaxe_string(const struct option *opt, + const char *arg, int unset) +{ + struct diff_options *options = opt->value; + + BUG_ON_OPT_NEG(unset); + options->pickaxe = arg; + options->pickaxe_opts |= DIFF_PICKAXE_KIND_S; + return 0; +} + +static int diff_opt_relative(const struct option *opt, + const char *arg, int unset) +{ + struct diff_options *options = opt->value; + + BUG_ON_OPT_NEG(unset); + options->flags.relative_name = 1; + if (arg) + options->prefix = arg; + return 0; +} + +static int diff_opt_submodule(const struct option *opt, + const char *arg, int unset) +{ + struct diff_options *options = opt->value; + + BUG_ON_OPT_NEG(unset); + if (!arg) + arg = "log"; + if (parse_submodule_params(options, arg)) + return error(_("failed to parse --submodule option parameter: '%s'"), + arg); + return 0; +} + +static int diff_opt_textconv(const struct option *opt, + const char *arg, int unset) +{ + struct diff_options *options = opt->value; + + BUG_ON_OPT_ARG(arg); + if (unset) { + options->flags.allow_textconv = 0; + } else { + options->flags.allow_textconv = 1; + options->flags.textconv_set_via_cmdline = 1; + } + return 0; +} + +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); + + if (arg) { + 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 int diff_opt_word_diff(const struct option *opt, + const char *arg, int unset) +{ + struct diff_options *options = opt->value; + + BUG_ON_OPT_NEG(unset); + if (arg) { if (!strcmp(arg, "plain")) options->word_diff = DIFF_WORDS_PLAIN; else if (!strcmp(arg, "color")) { @@ -5137,118 +5241,305 @@ int diff_opt_parse(struct diff_options *options, else if (!strcmp(arg, "none")) options->word_diff = DIFF_WORDS_NONE; else - die("bad --word-diff argument: %s", arg); - } - else if ((argcount = parse_long_opt("word-diff-regex", av, &optarg))) { + return error(_("bad --word-diff argument: %s"), arg); + } else { if (options->word_diff == DIFF_WORDS_NONE) options->word_diff = DIFF_WORDS_PLAIN; - options->word_regex = optarg; - return argcount; } - else if (!strcmp(arg, "--exit-code")) - options->flags.exit_with_status = 1; - else if (!strcmp(arg, "--quiet")) - options->flags.quick = 1; - else if (!strcmp(arg, "--ext-diff")) - options->flags.allow_external = 1; - else if (!strcmp(arg, "--no-ext-diff")) - options->flags.allow_external = 0; - else if (!strcmp(arg, "--textconv")) { - options->flags.allow_textconv = 1; - options->flags.textconv_set_via_cmdline = 1; - } else if (!strcmp(arg, "--no-textconv")) - options->flags.allow_textconv = 0; - else if (skip_to_optional_arg_default(arg, "--ignore-submodules", &arg, "all")) { - options->flags.override_submodule_config = 1; - handle_ignore_submodules_arg(options, arg); - } else if (skip_to_optional_arg_default(arg, "--submodule", &arg, "log")) - return parse_submodule_opt(options, arg); - else if (skip_prefix(arg, "--ws-error-highlight=", &arg)) - return parse_ws_error_highlight_opt(options, arg); - else if (!strcmp(arg, "--ita-invisible-in-index")) - options->ita_invisible_in_index = 1; - else if (!strcmp(arg, "--ita-visible-in-index")) - options->ita_invisible_in_index = 0; - - /* misc options */ - else if (!strcmp(arg, "-z")) - options->line_termination = 0; - else if ((argcount = short_opt('l', av, &optarg))) { - options->rename_limit = strtoul(optarg, NULL, 10); - return argcount; - } - else if ((argcount = short_opt('S', av, &optarg))) { - options->pickaxe = optarg; - options->pickaxe_opts |= DIFF_PICKAXE_KIND_S; - return argcount; - } else if ((argcount = short_opt('G', av, &optarg))) { - options->pickaxe = optarg; - options->pickaxe_opts |= DIFF_PICKAXE_KIND_G; - return argcount; - } - else if (!strcmp(arg, "--pickaxe-all")) - options->pickaxe_opts |= DIFF_PICKAXE_ALL; - else if (!strcmp(arg, "--pickaxe-regex")) - options->pickaxe_opts |= DIFF_PICKAXE_REGEX; - else if ((argcount = short_opt('O', av, &optarg))) { - options->orderfile = prefix_filename(prefix, optarg); - return argcount; - } else if (skip_prefix(arg, "--find-object=", &arg)) - return parse_objfind_opt(options, arg); - else if ((argcount = parse_long_opt("diff-filter", av, &optarg))) { - int offending = parse_diff_filter_opt(optarg, options); - if (offending) - die("unknown change class '%c' in --diff-filter=%s", - offending, optarg); - return argcount; - } - else if (!strcmp(arg, "--no-abbrev")) - options->abbrev = 0; - else if (!strcmp(arg, "--abbrev")) - options->abbrev = DEFAULT_ABBREV; - else if (skip_prefix(arg, "--abbrev=", &arg)) { - options->abbrev = strtoul(arg, NULL, 10); - if (options->abbrev < MINIMUM_ABBREV) - options->abbrev = MINIMUM_ABBREV; - else if (the_hash_algo->hexsz < options->abbrev) - options->abbrev = the_hash_algo->hexsz; - } - else if ((argcount = parse_long_opt("src-prefix", av, &optarg))) { - options->a_prefix = optarg; - return argcount; - } - else if ((argcount = parse_long_opt("line-prefix", av, &optarg))) { - options->line_prefix = optarg; - options->line_prefix_length = strlen(options->line_prefix); - graph_setup_line_prefix(options); - return argcount; - } - else if ((argcount = parse_long_opt("dst-prefix", av, &optarg))) { |