Skip to content

Commit 0f1930c

Browse files
René Scharfegitster
authored andcommitted
parse-options: allow positivation of options starting, with no-
Long options can be negated by adding no- right after the leading two dashes. This is useful e.g. to override options set by aliases. For options that are defined to start with no- already, this looks a bit funny. Allow such options to also be negated by removing the prefix. The following thirteen options are affected: apply --no-add bisect--helper --no-checkout checkout-index --no-create clone --no-checkout --no-hardlinks commit --no-verify --no-post-rewrite format-patch --no-binary hash-object --no-filters read-tree --no-sparse-checkout revert --no-commit show-branch --no-name update-ref --no-deref The following five are NOT affected because they are defined with PARSE_OPT_NONEG or the non-negated version is defined as well: branch --no-merged format-patch --no-stat --no-numbered update-index --no-assume-unchanged --no-skip-worktree Signed-off-by: Rene Scharfe <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent b9e63dd commit 0f1930c

File tree

3 files changed

+20
-12
lines changed

3 files changed

+20
-12
lines changed

Documentation/technical/api-parse-options.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ The parse-options API allows:
3939
* Short options may be bundled, e.g. `-a -b` can be specified as `-ab`.
4040

4141
* Boolean long options can be 'negated' (or 'unset') by prepending
42-
`no-`, e.g. `\--no-abbrev` instead of `\--abbrev`.
42+
`no-`, e.g. `\--no-abbrev` instead of `\--abbrev`. Conversely,
43+
options that begin with `no-` can be 'negated' by removing it.
4344

4445
* Options and non-option arguments can clearly be separated using the `\--`
4546
option, e.g. `-a -b \--option \-- \--this-is-a-file` indicates that

parse-options.c

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -193,13 +193,14 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
193193
arg_end = arg + strlen(arg);
194194

195195
for (; options->type != OPTION_END; options++) {
196-
const char *rest;
197-
int flags = 0;
196+
const char *rest, *long_name = options->long_name;
197+
int flags = 0, opt_flags = 0;
198198

199-
if (!options->long_name)
199+
if (!long_name)
200200
continue;
201201

202-
rest = skip_prefix(arg, options->long_name);
202+
again:
203+
rest = skip_prefix(arg, long_name);
203204
if (options->type == OPTION_ARGUMENT) {
204205
if (!rest)
205206
continue;
@@ -212,7 +213,7 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
212213
}
213214
if (!rest) {
214215
/* abbreviated? */
215-
if (!strncmp(options->long_name, arg, arg_end - arg)) {
216+
if (!strncmp(long_name, arg, arg_end - arg)) {
216217
is_abbreviated:
217218
if (abbrev_option) {
218219
/*
@@ -227,7 +228,7 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
227228
if (!(flags & OPT_UNSET) && *arg_end)
228229
p->opt = arg_end + 1;
229230
abbrev_option = options;
230-
abbrev_flags = flags;
231+
abbrev_flags = flags ^ opt_flags;
231232
continue;
232233
}
233234
/* negation allowed? */
@@ -239,12 +240,18 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
239240
goto is_abbreviated;
240241
}
241242
/* negated? */
242-
if (strncmp(arg, "no-", 3))
243+
if (prefixcmp(arg, "no-")) {
244+
if (!prefixcmp(long_name, "no-")) {
245+
long_name += 3;
246+
opt_flags |= OPT_UNSET;
247+
goto again;
248+
}
243249
continue;
250+
}
244251
flags |= OPT_UNSET;
245-
rest = skip_prefix(arg + 3, options->long_name);
252+
rest = skip_prefix(arg + 3, long_name);
246253
/* abbreviated and negated? */
247-
if (!rest && !prefixcmp(options->long_name, arg + 3))
254+
if (!rest && !prefixcmp(long_name, arg + 3))
248255
goto is_abbreviated;
249256
if (!rest)
250257
continue;
@@ -254,7 +261,7 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
254261
continue;
255262
p->opt = rest + 1;
256263
}
257-
return get_value(p, options, flags);
264+
return get_value(p, options, flags ^ opt_flags);
258265
}
259266

260267
if (ambiguous_option)

t/t0040-parse-options.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ test_expect_success 'OPT_BOOL() negation #2' 'check boolean: 0 -D --no-no-doubt'
107107
test_expect_success 'OPT_BOOL() no negation #1' 'check_unknown --fear'
108108
test_expect_success 'OPT_BOOL() no negation #2' 'check_unknown --no-no-fear'
109109

110-
test_expect_failure 'OPT_BOOL() positivation' 'check boolean: 0 -D --doubt'
110+
test_expect_success 'OPT_BOOL() positivation' 'check boolean: 0 -D --doubt'
111111

112112
cat > expect << EOF
113113
boolean: 2

0 commit comments

Comments
 (0)