diff-parseopt: convert --diff-filter
[gitweb.git] / diff.c
diff --git a/diff.c b/diff.c
index bd152693463e575c0d94cd31091466bbf9aaa8a6..47146c33f5ad2f234896aa53ed5487f2a122085c 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -4617,22 +4617,6 @@ static int opt_arg(const char *arg, int arg_short, const char *arg_long, int *va
        return 1;
 }
 
-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;
-}
-
 int parse_long_opt(const char *opt, const char **argv,
                   const char **optarg)
 {
@@ -4721,14 +4705,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,
@@ -4760,10 +4736,13 @@ 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)
+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();
 
        /*
@@ -4794,7 +4773,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
@@ -4809,25 +4789,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));
@@ -4836,7 +4820,7 @@ 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;
 }
 
 static int diff_opt_anchored(const struct option *opt,
@@ -5013,6 +4997,19 @@ static int diff_opt_follow(const struct option *opt,
        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 enum parse_opt_result diff_opt_output(struct parse_opt_ctx_t *ctx,
                                             const struct option *opt,
                                             const char *arg, int unset)
@@ -5050,6 +5047,28 @@ static int diff_opt_patience(const struct option *opt,
        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)
 {
@@ -5062,6 +5081,35 @@ static int diff_opt_relative(const struct option *opt,
        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)
 {
@@ -5200,6 +5248,12 @@ static void prep_parse_options(struct diff_options *options)
                         N_("show full pre- and post-image object names on the \"index\" lines")),
                OPT_COLOR_FLAG(0, "color", &options->use_color,
                               N_("show colored diff")),
+               OPT_CALLBACK_F(0, "ws-error-highlight", options, N_("<kind>"),
+                              N_("highlight whitespace errors in the 'context', 'old' or 'new' lines in the diff"),
+                              PARSE_OPT_NONEG, diff_opt_ws_error_highlight),
+               OPT_SET_INT('z', NULL, &options->line_termination,
+                           N_("do not munge pathnames and use NULs as output field terminators in --raw or --numstat"),
+                           0),
                OPT_CALLBACK_F(0, "output-indicator-new",
                               &options->output_indicators[OUTPUT_INDICATOR_NEW],
                               N_("<char>"),
@@ -5242,6 +5296,8 @@ static void prep_parse_options(struct diff_options *options)
                OPT_CALLBACK_F(0, "follow", options, NULL,
                               N_("continue listing the history of a file beyond renames"),
                               PARSE_OPT_NOARG, diff_opt_follow),
+               OPT_INTEGER('l', NULL, &options->rename_limit,
+                           N_("prevent rename/copy detection if the number of rename/copy targets exceeds given limit")),
 
                OPT_GROUP(N_("Diff algorithm options")),
                OPT_BIT(0, "minimal", &options->xdl_opts,
@@ -5301,6 +5357,45 @@ static void prep_parse_options(struct diff_options *options)
                         N_("exit with 1 if there were differences, 0 otherwise")),
                OPT_BOOL(0, "quiet", &options->flags.quick,
                         N_("disable all output of the program")),
+               OPT_BOOL(0, "ext-diff", &options->flags.allow_external,
+                        N_("allow an external diff helper to be executed")),
+               OPT_CALLBACK_F(0, "textconv", options, NULL,
+                              N_("run external text conversion filters when comparing binary files"),
+                              PARSE_OPT_NOARG, diff_opt_textconv),
+               OPT_CALLBACK_F(0, "ignore-submodules", options, N_("<when>"),
+                              N_("ignore changes to submodules in the diff generation"),
+                              PARSE_OPT_NONEG | PARSE_OPT_OPTARG,
+                              diff_opt_ignore_submodules),
+               OPT_CALLBACK_F(0, "submodule", options, N_("<format>"),
+                              N_("specify how differences in submodules are shown"),
+                              PARSE_OPT_NONEG | PARSE_OPT_OPTARG,
+                              diff_opt_submodule),
+               OPT_SET_INT_F(0, "ita-invisible-in-index", &options->ita_invisible_in_index,
+                             N_("hide 'git add -N' entries from the index"),
+                             1, PARSE_OPT_NONEG),
+               OPT_SET_INT_F(0, "ita-visible-in-index", &options->ita_invisible_in_index,
+                             N_("treat 'git add -N' entries as real in the index"),
+                             0, PARSE_OPT_NONEG),
+               OPT_CALLBACK_F('S', NULL, options, N_("<string>"),
+                              N_("look for differences that change the number of occurrences of the specified string"),
+                              0, diff_opt_pickaxe_string),
+               OPT_CALLBACK_F('G', NULL, options, N_("<regex>"),
+                              N_("look for differences that change the number of occurrences of the specified regex"),
+                              0, diff_opt_pickaxe_regex),
+               OPT_BIT_F(0, "pickaxe-all", &options->pickaxe_opts,
+                         N_("show all changes in the changeset with -S or -G"),
+                         DIFF_PICKAXE_ALL, PARSE_OPT_NONEG),
+               OPT_BIT_F(0, "pickaxe-regex", &options->pickaxe_opts,
+                         N_("treat <string> in -S as extended POSIX regular expression"),
+                         DIFF_PICKAXE_REGEX, PARSE_OPT_NONEG),
+               OPT_FILENAME('O', NULL, &options->orderfile,
+                            N_("control the order in which files appear in the output")),
+               OPT_CALLBACK_F(0, "find-object", options, N_("<object-id>"),
+                              N_("look for differences that change the number of occurrences of the specified object"),
+                              PARSE_OPT_NONEG, diff_opt_find_object),
+               OPT_CALLBACK_F(0, "diff-filter", options, N_("[(A|C|D|M|R|T|U|X|B)...[*]]"),
+                              N_("select files by diff type"),
+                              PARSE_OPT_NONEG, diff_opt_diff_filter),
                { OPTION_CALLBACK, 0, "output", options, N_("<file>"),
                  N_("Output to a specific file"),
                  PARSE_OPT_NONEG, NULL, 0, diff_opt_output },
@@ -5350,59 +5445,9 @@ int diff_opt_parse(struct diff_options *options,
                if (cm & COLOR_MOVED_WS_ERROR)
                        return -1;
                options->color_moved_ws_handling = cm;
-       } 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"))