@matheusbsbs / matheus-bagliano / commits / dea007fb4c
Fork 0

diff: parse separate options like -S foo

Change the option parsing logic in revision.c to accept separate forms like `-S foo' in addition to `-Sfoo'. The rest of git already accepted this form, but revision.c still used its own option parsing. Short options affected are -S<string>, -l<num> and -O<orderfile>, for which an empty string wouldn't make sense, hence -<option> <arg> isn't ambiguous. This patch does not handle --stat-name-width and --stat-width, which are special-cases where diff_long_opt do not apply. They are handled in a separate patch to ease review. Original patch by Matthieu Moy, plus refactoring by Jonathan Nieder. Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Matthieu Moy committed Aug 5, 2010 at 10:22 UTC dea007fb4c8170ea007b577698c7b44df6c318b9
5 files changed +95 -23
diff.c
+71 -16
@@ -2990,9 +2990,50 @@ static int opt_arg(const char *arg, int arg_short, const char *arg_long, int *va
2990
2991 static int diff_scoreopt_parse(const char *opt);
2992
2993 +static inline int short_opt(char opt, const char **argv,
2994 + const char **optarg)
2995 +{
2996 + const char *arg = argv[0];
2997 + if (arg[0] != '-' || arg[1] != opt)
2998 + return 0;
2999 + if (arg[2] != '\0') {
3000 + *optarg = arg + 2;
3001 + return 1;
3002 + }
3003 + if (!argv[1])
3004 + die("Option '%c' requires a value", opt);
3005 + *optarg = argv[1];
3006 + return 2;
3007 +}
3008 +
3009 +int parse_long_opt(const char *opt, const char **argv,
3010 + const char **optarg)
3011 +{
3012 + const char *arg = argv[0];
3013 + if (arg[0] != '-' || arg[1] != '-')
3014 + return 0;
3015 + arg += strlen("--");
3016 + if (prefixcmp(arg, opt))
3017 + return 0;
3018 + arg += strlen(opt);
3019 + if (*arg == '=') { /* sticked form: --option=value */
3020 + *optarg = arg + 1;
3021 + return 1;
3022 + }
3023 + if (*arg != '\0')
3024 + return 0;
3025 + /* separate form: --option value */
3026 + if (!argv[1])
3027 + die("Option '--%s' requires a value", opt);
3028 + *optarg = argv[1];
3029 + return 2;
3030 +}
3031 +
3032 int diff_opt_parse(struct diff_options *options, const char **av, int ac)
3033 {
3034 const char *arg = av[0];
3035 + const char *optarg;
3036 + int argcount;
3037
3038 /* Output format options */
3039 if (!strcmp(arg, "-p") || !strcmp(arg, "-u") || !strcmp(arg, "--patch"))
@@ -3149,10 +3190,11 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
3190 else
3191 die("bad --word-diff argument: %s", type);
3192 }
3152 - else if (!prefixcmp(arg, "--word-diff-regex=")) {
3193 + else if ((argcount = parse_long_opt("word-diff-regex", av, &optarg))) {
3194 if (options->word_diff == DIFF_WORDS_NONE)
3195 options->word_diff = DIFF_WORDS_PLAIN;
3155 - options->word_regex = arg + 18;
3196 + options->word_regex = optarg;
3197 + return argcount;
3198 }
3199 else if (!strcmp(arg, "--exit-code"))
3200 DIFF_OPT_SET(options, EXIT_WITH_STATUS);
@@ -3180,18 +3222,26 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
3222 /* misc options */
3223 else if (!strcmp(arg, "-z"))
3224 options->line_termination = 0;
3183 - else if (!prefixcmp(arg, "-l"))
3184 - options->rename_limit = strtoul(arg+2, NULL, 10);
3185 - else if (!prefixcmp(arg, "-S"))
3186 - options->pickaxe = arg + 2;
3225 + else if ((argcount = short_opt('l', av, &optarg))) {
3226 + options->rename_limit = strtoul(optarg, NULL, 10);
3227 + return argcount;
3228 + }
3229 + else if ((argcount = short_opt('S', av, &optarg))) {
3230 + options->pickaxe = optarg;
3231 + return argcount;
3232 + }
3233 else if (!strcmp(arg, "--pickaxe-all"))
3234 options->pickaxe_opts = DIFF_PICKAXE_ALL;
3235 else if (!strcmp(arg, "--pickaxe-regex"))
3236 options->pickaxe_opts = DIFF_PICKAXE_REGEX;
3191 - else if (!prefixcmp(arg, "-O"))
3192 - options->orderfile = arg + 2;
3193 - else if (!prefixcmp(arg, "--diff-filter="))
3194 - options->filter = arg + 14;
3237 + else if ((argcount = short_opt('O', av, &optarg))) {
3238 + options->orderfile = optarg;
3239 + return argcount;
3240 + }
3241 + else if ((argcount = parse_long_opt("diff-filter", av, &optarg))) {
3242 + options->filter = optarg;
3243 + return argcount;
3244 + }
3245 else if (!strcmp(arg, "--abbrev"))
3246 options->abbrev = DEFAULT_ABBREV;
3247 else if (!prefixcmp(arg, "--abbrev=")) {
@@ -3201,20 +3251,25 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
3251 else if (40 < options->abbrev)
3252 options->abbrev = 40;
3253 }
3204 - else if (!prefixcmp(arg, "--src-prefix="))
3205 - options->a_prefix = arg + 13;
3206 - else if (!prefixcmp(arg, "--dst-prefix="))
3207 - options->b_prefix = arg + 13;
3254 + else if ((argcount = parse_long_opt("src-prefix", av, &optarg))) {
3255 + options->a_prefix = optarg;
3256 + return argcount;
3257 + }
3258 + else if ((argcount = parse_long_opt("dst-prefix", av, &optarg))) {
3259 + options->b_prefix = optarg;
3260 + return argcount;
3261 + }
3262 else if (!strcmp(arg, "--no-prefix"))
3263 options->a_prefix = options->b_prefix = "";
3264 else if (opt_arg(arg, '\0', "inter-hunk-context",
3265 &options->interhunkcontext))
3266 ;
3213 - else if (!prefixcmp(arg, "--output=")) {
3214 - options->file = fopen(arg + strlen("--output="), "w");
3267 + else if ((argcount = parse_long_opt("output", av, &optarg))) {
3268 + options->file = fopen(optarg, "w");
3269 if (!options->file)
3270 die_errno("Could not open '%s'", arg + strlen("--output="));
3271 options->close_file = 1;
3272 + return argcount;
3273 } else
3274 return 0;
3275 return 1;
diff.h
+7
@@ -214,6 +214,13 @@ extern void diff_unmerge(struct diff_options *,
214 #define DIFF_SETUP_USE_CACHE 2
215 #define DIFF_SETUP_USE_SIZE_CACHE 4
216
217 +/*
218 + * Poor man's alternative to parse-option, to allow both sticked form
219 + * (--option=value) and separate form (--option value).
220 + */
221 +extern int parse_long_opt(const char *opt, const char **argv,
222 + const char **optarg);
223 +
224 extern int git_diff_basic_config(const char *var, const char *value, void *cb);
225 extern int git_diff_ui_config(const char *var, const char *value, void *cb);
226 extern int diff_use_color_default;
t/t4013-diff-various.sh
+5
@@ -208,6 +208,7 @@ log -p --first-parent master
208 log -m -p --first-parent master
209 log -m -p master
210 log -SF master
211 +log -S F master
212 log -SF -p master
213 log --decorate --all
214 log --decorate=full --all
@@ -282,4 +283,8 @@ diff master master^ side
283 diff --dirstat master~1 master~2
284 EOF
285
286 +test_expect_success 'log -S requires an argument' '
287 + test_must_fail git log -S
288 +'
289 +
290 test_done
t/t4013/diff.log_-S_F_master new
+7
@@ -0,0 +1,7 @@
1 +$ git log -S F master
2 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
3 +Author: A U Thor <author@example.com>
4 +Date: Mon Jun 26 00:02:00 2006 +0000
5 +
6 + Third
7 +$
t/t4202-log.sh
+5 -7
@@ -100,13 +100,11 @@ test_expect_success 'oneline' '
100
101 test_expect_success 'diff-filter=A' '
102
103 - actual=$(git log --pretty="format:%s" --diff-filter=A HEAD) &&
104 - expect=$(echo fifth ; echo fourth ; echo third ; echo initial) &&
105 - test "$actual" = "$expect" || {
106 - echo Oops
107 - echo "Actual: $actual"
108 - false
109 - }
103 + git log --pretty="format:%s" --diff-filter=A HEAD > actual &&
104 + git log --pretty="format:%s" --diff-filter A HEAD > actual-separate &&
105 + printf "fifth\nfourth\nthird\ninitial" > expect &&
106 + test_cmp expect actual &&
107 + test_cmp expect actual-separate
108
109 '
110