Merge branch 'rs/no-no-no-parseopt' into next

* rs/no-no-no-parseopt:
  parse-options: remove PARSE_OPT_NEGHELP
  parse-options: allow positivation of options starting, with no-
  test-parse-options: convert to OPT_BOOL()

Conflicts:
	builtin/grep.c
This commit is contained in:
Junio C Hamano
2012-02-29 12:18:49 -08:00
7 changed files with 90 additions and 31 deletions

View File

@@ -39,7 +39,8 @@ The parse-options API allows:
* Short options may be bundled, e.g. `-a -b` can be specified as `-ab`.
* Boolean long options can be 'negated' (or 'unset') by prepending
`no-`, e.g. `\--no-abbrev` instead of `\--abbrev`.
`no-`, e.g. `\--no-abbrev` instead of `\--abbrev`. Conversely,
options that begin with `no-` can be 'negated' by removing it.
* Options and non-option arguments can clearly be separated using the `\--`
option, e.g. `-a -b \--option \-- \--this-is-a-file` indicates that

View File

@@ -647,9 +647,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
"Output full tree for each commit"),
OPT_BOOLEAN(0, "use-done-feature", &use_done_feature,
"Use the done feature to terminate the stream"),
{ OPTION_NEGBIT, 0, "data", &no_data, NULL,
"Skip output of blob data",
PARSE_OPT_NOARG | PARSE_OPT_NEGHELP, NULL, 1 },
OPT_BOOL(0, "no-data", &no_data, "Skip output of blob data"),
OPT_END()
};

View File

@@ -684,9 +684,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
struct option options[] = {
OPT_BOOLEAN(0, "cached", &cached,
"search in index instead of in the work tree"),
{ OPTION_BOOLEAN, 0, "index", &use_index, NULL,
"finds in contents not managed by git",
PARSE_OPT_NOARG | PARSE_OPT_NEGHELP },
OPT_NEGBIT(0, "no-index", &use_index,
"finds in contents not managed by git", 1),
OPT_BOOLEAN(0, "untracked", &untracked,
"search in both tracked and untracked files"),
OPT_SET_INT(0, "exclude-standard", &opt_exclude,

View File

@@ -193,13 +193,14 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
arg_end = arg + strlen(arg);
for (; options->type != OPTION_END; options++) {
const char *rest;
int flags = 0;
const char *rest, *long_name = options->long_name;
int flags = 0, opt_flags = 0;
if (!options->long_name)
if (!long_name)
continue;
rest = skip_prefix(arg, options->long_name);
again:
rest = skip_prefix(arg, long_name);
if (options->type == OPTION_ARGUMENT) {
if (!rest)
continue;
@@ -212,7 +213,7 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
}
if (!rest) {
/* abbreviated? */
if (!strncmp(options->long_name, arg, arg_end - arg)) {
if (!strncmp(long_name, arg, arg_end - arg)) {
is_abbreviated:
if (abbrev_option) {
/*
@@ -227,7 +228,7 @@ is_abbreviated:
if (!(flags & OPT_UNSET) && *arg_end)
p->opt = arg_end + 1;
abbrev_option = options;
abbrev_flags = flags;
abbrev_flags = flags ^ opt_flags;
continue;
}
/* negation allowed? */
@@ -239,12 +240,18 @@ is_abbreviated:
goto is_abbreviated;
}
/* negated? */
if (strncmp(arg, "no-", 3))
if (prefixcmp(arg, "no-")) {
if (!prefixcmp(long_name, "no-")) {
long_name += 3;
opt_flags |= OPT_UNSET;
goto again;
}
continue;
}
flags |= OPT_UNSET;
rest = skip_prefix(arg + 3, options->long_name);
rest = skip_prefix(arg + 3, long_name);
/* abbreviated and negated? */
if (!rest && !prefixcmp(options->long_name, arg + 3))
if (!rest && !prefixcmp(long_name, arg + 3))
goto is_abbreviated;
if (!rest)
continue;
@@ -254,7 +261,7 @@ is_abbreviated:
continue;
p->opt = rest + 1;
}
return get_value(p, options, flags);
return get_value(p, options, flags ^ opt_flags);
}
if (ambiguous_option)
@@ -526,7 +533,7 @@ static int usage_with_options_internal(struct parse_opt_ctx_t *ctx,
continue;
pos = fprintf(outfile, " ");
if (opts->short_name && !(opts->flags & PARSE_OPT_NEGHELP)) {
if (opts->short_name) {
if (opts->flags & PARSE_OPT_NODASH)
pos += fprintf(outfile, "%c", opts->short_name);
else
@@ -535,9 +542,7 @@ static int usage_with_options_internal(struct parse_opt_ctx_t *ctx,
if (opts->long_name && opts->short_name)
pos += fprintf(outfile, ", ");
if (opts->long_name)
pos += fprintf(outfile, "--%s%s",
(opts->flags & PARSE_OPT_NEGHELP) ? "no-" : "",
opts->long_name);
pos += fprintf(outfile, "--%s", opts->long_name);
if (opts->type == OPTION_NUMBER)
pos += fprintf(outfile, "-NUM");

View File

@@ -40,7 +40,6 @@ enum parse_opt_option_flags {
PARSE_OPT_LASTARG_DEFAULT = 16,
PARSE_OPT_NODASH = 32,
PARSE_OPT_LITERAL_ARGHELP = 64,
PARSE_OPT_NEGHELP = 128,
PARSE_OPT_SHELL_EVAL = 256
};
@@ -90,9 +89,6 @@ typedef int parse_opt_ll_cb(struct parse_opt_ctx_t *ctx,
* PARSE_OPT_LITERAL_ARGHELP: says that argh shouldn't be enclosed in brackets
* (i.e. '<argh>') in the help message.
* Useful for options with multiple parameters.
* PARSE_OPT_NEGHELP: says that the long option should always be shown with
* the --no prefix in the usage message. Sometimes
* useful for users of OPTION_NEGBIT.
*
* `callback`::
* pointer to the callback to use for OPTION_CALLBACK or

View File

@@ -10,7 +10,10 @@ test_description='our own option parser'
cat > expect << EOF
usage: test-parse-options <options>
-b, --boolean get a boolean
--yes get a boolean
-D, --no-doubt begins with 'no-'
-B, --no-fear be brave
-b, --boolean increment by one
-4, --or4 bitwise-or boolean with ...0100
--neg-or4 same as --no-or4
@@ -53,6 +56,59 @@ test_expect_success 'test help' '
mv expect expect.err
cat >expect.template <<EOF
boolean: 0
integer: 0
timestamp: 0
string: (not set)
abbrev: 7
verbose: 0
quiet: no
dry run: no
file: (not set)
EOF
check() {
what="$1" &&
shift &&
expect="$1" &&
shift &&
sed "s/^$what .*/$what $expect/" <expect.template >expect &&
test-parse-options $* >output 2>output.err &&
test ! -s output.err &&
test_cmp expect output
}
check_unknown() {
case "$1" in
--*)
echo error: unknown option \`${1#--}\' >expect ;;
-*)
echo error: unknown switch \`${1#-}\' >expect ;;
esac &&
cat expect.err >>expect &&
test_must_fail test-parse-options $* >output 2>output.err &&
test ! -s output &&
test_cmp expect output.err
}
test_expect_success 'OPT_BOOL() #1' 'check boolean: 1 --yes'
test_expect_success 'OPT_BOOL() #2' 'check boolean: 1 --no-doubt'
test_expect_success 'OPT_BOOL() #3' 'check boolean: 1 -D'
test_expect_success 'OPT_BOOL() #4' 'check boolean: 1 --no-fear'
test_expect_success 'OPT_BOOL() #5' 'check boolean: 1 -B'
test_expect_success 'OPT_BOOL() is idempotent #1' 'check boolean: 1 --yes --yes'
test_expect_success 'OPT_BOOL() is idempotent #2' 'check boolean: 1 -DB'
test_expect_success 'OPT_BOOL() negation #1' 'check boolean: 0 -D --no-yes'
test_expect_success 'OPT_BOOL() negation #2' 'check boolean: 0 -D --no-no-doubt'
test_expect_success 'OPT_BOOL() no negation #1' 'check_unknown --fear'
test_expect_success 'OPT_BOOL() no negation #2' 'check_unknown --no-no-fear'
test_expect_success 'OPT_BOOL() positivation' 'check boolean: 0 -D --doubt'
cat > expect << EOF
boolean: 2
integer: 1729
@@ -296,7 +352,7 @@ test_expect_success 'OPT_NEGBIT() works' '
test_cmp expect output
'
test_expect_success 'OPT_BOOLEAN() with PARSE_OPT_NODASH works' '
test_expect_success 'OPT_COUNTUP() with PARSE_OPT_NODASH works' '
test-parse-options + + + + + + > output 2> output.err &&
test ! -s output.err &&
test_cmp expect output

View File

@@ -37,7 +37,11 @@ int main(int argc, const char **argv)
NULL
};
struct option options[] = {
OPT_BOOLEAN('b', "boolean", &boolean, "get a boolean"),
OPT_BOOL(0, "yes", &boolean, "get a boolean"),
OPT_BOOL('D', "no-doubt", &boolean, "begins with 'no-'"),
{ OPTION_SET_INT, 'B', "no-fear", &boolean, NULL,
"be brave", PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
OPT_COUNTUP('b', "boolean", &boolean, "increment by one"),
OPT_BIT('4', "or4", &boolean,
"bitwise-or boolean with ...0100", 4),
OPT_NEGBIT(0, "neg-or4", &boolean, "same as --no-or4", 4),
@@ -62,11 +66,11 @@ int main(int argc, const char **argv)
OPT_ARGUMENT("quux", "means --quux"),
OPT_NUMBER_CALLBACK(&integer, "set integer to NUM",
number_callback),
{ OPTION_BOOLEAN, '+', NULL, &boolean, NULL, "same as -b",
{ OPTION_COUNTUP, '+', NULL, &boolean, NULL, "same as -b",
PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH },
{ OPTION_BOOLEAN, 0, "ambiguous", &ambiguous, NULL,
{ OPTION_COUNTUP, 0, "ambiguous", &ambiguous, NULL,
"positive ambiguity", PARSE_OPT_NOARG | PARSE_OPT_NONEG },
{ OPTION_BOOLEAN, 0, "no-ambiguous", &ambiguous, NULL,
{ OPTION_COUNTUP, 0, "no-ambiguous", &ambiguous, NULL,
"negative ambiguity", PARSE_OPT_NOARG | PARSE_OPT_NONEG },
OPT_GROUP("Standard options"),
OPT__ABBREV(&abbrev),