parseopt: add OPT_NUMBER_CALLBACK

Add a way to recognize numerical options.  The number is passed to
a callback function as a string.

Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
René Scharfe 2009-05-07 21:45:08 +02:00 committed by Junio C Hamano
parent 2f4b97f910
commit e0319ff5ed
5 changed files with 63 additions and 1 deletions

View File

@ -170,6 +170,14 @@ There are some macros to easily define options:
`OPT_ARGUMENT(long, description)`::
Introduce a long-option argument that will be kept in `argv[]`.
`OPT_NUMBER_CALLBACK(&var, description, func_ptr)`::
Recognize numerical options like -123 and feed the integer as
if it was an argument to the function given by `func_ptr`.
The result will be put into `var`. There can be only one such
option definition. It cannot be negated and it takes no
arguments. Short options that happen to be digits take
precedence over it.
The last element of the array must be `OPT_END()`.

View File

@ -129,11 +129,33 @@ static int get_value(struct parse_opt_ctx_t *p,
static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
{
const struct option *numopt = NULL;
for (; options->type != OPTION_END; options++) {
if (options->short_name == *p->opt) {
p->opt = p->opt[1] ? p->opt + 1 : NULL;
return get_value(p, options, OPT_SHORT);
}
/*
* Handle the numerical option later, explicit one-digit
* options take precedence over it.
*/
if (options->type == OPTION_NUMBER)
numopt = options;
}
if (numopt && isdigit(*p->opt)) {
size_t len = 1;
char *arg;
int rc;
while (isdigit(p->opt[len]))
len++;
arg = xmemdupz(p->opt, len);
p->opt = p->opt[len] ? p->opt + len : NULL;
rc = (*numopt->callback)(numopt, arg, 0) ? (-1) : 0;
free(arg);
return rc;
}
return -2;
}
@ -411,6 +433,8 @@ int usage_with_options_internal(const char * const *usagestr,
pos += fprintf(stderr, ", ");
if (opts->long_name)
pos += fprintf(stderr, "--%s", opts->long_name);
if (opts->type == OPTION_NUMBER)
pos += fprintf(stderr, "-NUM");
switch (opts->type) {
case OPTION_ARGUMENT:
@ -447,7 +471,7 @@ int usage_with_options_internal(const char * const *usagestr,
pos += fprintf(stderr, " ...");
}
break;
default: /* OPTION_{BIT,BOOLEAN,SET_INT,SET_PTR} */
default: /* OPTION_{BIT,BOOLEAN,NUMBER,SET_INT,SET_PTR} */
break;
}

View File

@ -6,6 +6,7 @@ enum parse_opt_type {
OPTION_END,
OPTION_ARGUMENT,
OPTION_GROUP,
OPTION_NUMBER,
/* options with no arguments */
OPTION_BIT,
OPTION_NEGBIT,
@ -105,6 +106,9 @@ struct option {
parse_opt_approxidate_cb }
#define OPT_CALLBACK(s, l, v, a, h, f) \
{ OPTION_CALLBACK, (s), (l), (v), (a), (h), 0, (f) }
#define OPT_NUMBER_CALLBACK(v, h, f) \
{ OPTION_NUMBER, 0, NULL, (v), NULL, (h), \
PARSE_OPT_NOARG | PARSE_OPT_NONEG, (f) }
/* parse_options() will filter out the processed options and leave the
* non-option arguments in argv[].

View File

@ -30,6 +30,7 @@ String options
Magic arguments
--quux means --quux
-NUM set integer to NUM
Standard options
--abbrev[=<n>] use <n> digits to display SHA-1s
@ -275,4 +276,21 @@ test_expect_success 'OPT_NEGBIT() works' '
test_cmp expect output
'
cat > expect <<EOF
boolean: 0
integer: 12345
timestamp: 0
string: (not set)
abbrev: 7
verbose: 0
quiet: no
dry run: no
EOF
test_expect_success 'OPT_NUMBER_CALLBACK() works' '
test-parse-options -12345 > output 2> output.err &&
test ! -s output.err &&
test_cmp expect output
'
test_done

View File

@ -19,6 +19,12 @@ int length_callback(const struct option *opt, const char *arg, int unset)
return 0;
}
int number_callback(const struct option *opt, const char *arg, int unset)
{
*(int *)opt->value = strtol(arg, NULL, 10);
return 0;
}
int main(int argc, const char **argv)
{
const char *usage[] = {
@ -46,6 +52,8 @@ int main(int argc, const char **argv)
"set string to default", (unsigned long)"default"),
OPT_GROUP("Magic arguments"),
OPT_ARGUMENT("quux", "means --quux"),
OPT_NUMBER_CALLBACK(&integer, "set integer to NUM",
number_callback),
OPT_GROUP("Standard options"),
OPT__ABBREV(&abbrev),
OPT__VERBOSE(&verbose),