Ævar Arnfjörð Bjarmason <[email protected]> writes:
> + [--range-diff<common diff option>]]
Let's make sure a random string thrown at this mechanism will
properly get noticed and diagnosed.
> @@ -257,6 +258,13 @@ feeding the result to `git send-email`.
> creation/deletion cost fudge factor. See linkgit:git-range-diff[1])
> for details.
>
> +--range-diff<common diff option>::
> + Other options prefixed with `--range-diff` are stripped of
> + that prefix and passed as-is to the diff machinery used to
> + generate the range-diff, e.g. `--range-diff-U0` and
> + `--range-diff--no-color`. This allows for adjusting the format
> + of the range-diff independently from the patch itself.
Taking anything is of course the most general, but I am afraid if
this backfires if there are some options that do not make sense to
be different between the invocations of range-diff and format-patch.
> @@ -1689,8 +1688,32 @@ int cmd_format_patch(int argc, const char **argv,
> const char *prefix)
> rev.preserve_subject = keep_subject;
>
> argc = setup_revisions(argc, argv, &rev, &s_r_opt);
> - if (argc > 1)
> - die(_("unrecognized argument: %s"), argv[1]);
> + if (argc > 1) {
> + struct argv_array args = ARGV_ARRAY_INIT;
> + const char *prefix = "--range-diff";
Please call that anything but "prefix" that hides the parameter to
the function.
const char *range_diff_opt = "--range-diff";
might work OK, or it might not. Let's read on.
> + int have_prefix = 0;
> +
> + for (i = 0; i < argc; i++) {
> + struct strbuf sb = STRBUF_INIT;
> + char *str;
> +
> + strbuf_addstr(&sb, argv[i]);
> + if (starts_with(argv[i], prefix)) {
> + have_prefix = 1;
> + strbuf_remove(&sb, 0, strlen(prefix));
> + }
> + str = strbuf_detach(&sb, NULL);
> + strbuf_release(&sb);
> +
> + argv_array_push(&args, str);
> + }
> +
Is the body of the loop essentially this?
char *passopt = argv[i];
if (!skip_prefix(passopt, range_diff_opt, &passopt))
saw_range_diff_opt = 1;
argv_array_push(&args, xstrdup(passopt));
We only use that "prefix" thing once, so we may not even need the
variable.
> + if (!have_prefix)
> + die(_("unrecognized argument: %s"), argv[1]);
So we take normal options and check the leftover args; if there is
no --range-diff<whatever> among the leftover bits, we pretend that
we stumbled while reading the first such leftover arg.
> + argc = setup_revisions(args.argc, args.argv, &rd_rev, NULL);
> + if (argc > 1)
> + die(_("unrecognized argument: %s"), argv[1]);
> + }
Otherwise, we pass all the leftover bits, which is a random mixture
but guaranteed to have at least one meant for range-diff, to another
setup_revisions(). If it leaves a leftover arg, then that is
diagnosed here, so we'd be OK (iow, this is not a new "attack
vector" to inject random string to command line parser).
One minor glitch I can see is "format-patch --range-diffSilly" would
report "unrecognised arg: Silly". As we are pretending to be and
reporting errors as format-patch, it would be better if we report
that --range-diffSilly was what we did not understand.
> Junio: I know it's late, but unless Eric has objections to this UI
> change I'd really like to have this in 2.20 since this is a change to
> a new command-line UI that's newly added in 2.20.
Quite honestly, I'd rather document "driving range-diff from
format-patch is experimental and does silly things when given
non-standard options in this release" and not touch the code at this
late stage in the game. Would it be less intrusive a change to
*not* support the --range-diff<whatever> option, still use rd_rev
that is separate from the main rev, and use a reasonable hardcoded
default settings when preparing rd_rev?