Skip to content

Commit e0319ff

Browse files
René Scharfegitster
authored andcommitted
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>
1 parent 2f4b97f commit e0319ff

File tree

5 files changed

+63
-1
lines changed

5 files changed

+63
-1
lines changed

Documentation/technical/api-parse-options.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,14 @@ There are some macros to easily define options:
170170
`OPT_ARGUMENT(long, description)`::
171171
Introduce a long-option argument that will be kept in `argv[]`.
172172

173+
`OPT_NUMBER_CALLBACK(&var, description, func_ptr)`::
174+
Recognize numerical options like -123 and feed the integer as
175+
if it was an argument to the function given by `func_ptr`.
176+
The result will be put into `var`. There can be only one such
177+
option definition. It cannot be negated and it takes no
178+
arguments. Short options that happen to be digits take
179+
precedence over it.
180+
173181

174182
The last element of the array must be `OPT_END()`.
175183

parse-options.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,33 @@ static int get_value(struct parse_opt_ctx_t *p,
129129

130130
static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
131131
{
132+
const struct option *numopt = NULL;
133+
132134
for (; options->type != OPTION_END; options++) {
133135
if (options->short_name == *p->opt) {
134136
p->opt = p->opt[1] ? p->opt + 1 : NULL;
135137
return get_value(p, options, OPT_SHORT);
136138
}
139+
140+
/*
141+
* Handle the numerical option later, explicit one-digit
142+
* options take precedence over it.
143+
*/
144+
if (options->type == OPTION_NUMBER)
145+
numopt = options;
146+
}
147+
if (numopt && isdigit(*p->opt)) {
148+
size_t len = 1;
149+
char *arg;
150+
int rc;
151+
152+
while (isdigit(p->opt[len]))
153+
len++;
154+
arg = xmemdupz(p->opt, len);
155+
p->opt = p->opt[len] ? p->opt + len : NULL;
156+
rc = (*numopt->callback)(numopt, arg, 0) ? (-1) : 0;
157+
free(arg);
158+
return rc;
137159
}
138160
return -2;
139161
}
@@ -411,6 +433,8 @@ int usage_with_options_internal(const char * const *usagestr,
411433
pos += fprintf(stderr, ", ");
412434
if (opts->long_name)
413435
pos += fprintf(stderr, "--%s", opts->long_name);
436+
if (opts->type == OPTION_NUMBER)
437+
pos += fprintf(stderr, "-NUM");
414438

415439
switch (opts->type) {
416440
case OPTION_ARGUMENT:
@@ -447,7 +471,7 @@ int usage_with_options_internal(const char * const *usagestr,
447471
pos += fprintf(stderr, " ...");
448472
}
449473
break;
450-
default: /* OPTION_{BIT,BOOLEAN,SET_INT,SET_PTR} */
474+
default: /* OPTION_{BIT,BOOLEAN,NUMBER,SET_INT,SET_PTR} */
451475
break;
452476
}
453477

parse-options.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ enum parse_opt_type {
66
OPTION_END,
77
OPTION_ARGUMENT,
88
OPTION_GROUP,
9+
OPTION_NUMBER,
910
/* options with no arguments */
1011
OPTION_BIT,
1112
OPTION_NEGBIT,
@@ -105,6 +106,9 @@ struct option {
105106
parse_opt_approxidate_cb }
106107
#define OPT_CALLBACK(s, l, v, a, h, f) \
107108
{ OPTION_CALLBACK, (s), (l), (v), (a), (h), 0, (f) }
109+
#define OPT_NUMBER_CALLBACK(v, h, f) \
110+
{ OPTION_NUMBER, 0, NULL, (v), NULL, (h), \
111+
PARSE_OPT_NOARG | PARSE_OPT_NONEG, (f) }
108112

109113
/* parse_options() will filter out the processed options and leave the
110114
* non-option arguments in argv[].

t/t0040-parse-options.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ String options
3030
3131
Magic arguments
3232
--quux means --quux
33+
-NUM set integer to NUM
3334
3435
Standard options
3536
--abbrev[=<n>] use <n> digits to display SHA-1s
@@ -275,4 +276,21 @@ test_expect_success 'OPT_NEGBIT() works' '
275276
test_cmp expect output
276277
'
277278

279+
cat > expect <<EOF
280+
boolean: 0
281+
integer: 12345
282+
timestamp: 0
283+
string: (not set)
284+
abbrev: 7
285+
verbose: 0
286+
quiet: no
287+
dry run: no
288+
EOF
289+
290+
test_expect_success 'OPT_NUMBER_CALLBACK() works' '
291+
test-parse-options -12345 > output 2> output.err &&
292+
test ! -s output.err &&
293+
test_cmp expect output
294+
'
295+
278296
test_done

test-parse-options.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ int length_callback(const struct option *opt, const char *arg, int unset)
1919
return 0;
2020
}
2121

22+
int number_callback(const struct option *opt, const char *arg, int unset)
23+
{
24+
*(int *)opt->value = strtol(arg, NULL, 10);
25+
return 0;
26+
}
27+
2228
int main(int argc, const char **argv)
2329
{
2430
const char *usage[] = {
@@ -46,6 +52,8 @@ int main(int argc, const char **argv)
4652
"set string to default", (unsigned long)"default"),
4753
OPT_GROUP("Magic arguments"),
4854
OPT_ARGUMENT("quux", "means --quux"),
55+
OPT_NUMBER_CALLBACK(&integer, "set integer to NUM",
56+
number_callback),
4957
OPT_GROUP("Standard options"),
5058
OPT__ABBREV(&abbrev),
5159
OPT__VERBOSE(&verbose),

0 commit comments

Comments
 (0)