Skip to content

Commit 65ca324

Browse files
committed
Merge branch 'ab/parse-options-cleanup'
Random changes to parse-options implementation. * ab/parse-options-cleanup: parse-options: change OPT_{SHORT,UNSET} to an enum parse-options tests: test optname() output parse-options.[ch]: make opt{bug,name}() "static" commit-graph: stop using optname() parse-options.c: move optname() earlier in the file parse-options.h: make the "flags" in "struct option" an enum parse-options.c: use exhaustive "case" arms for "enum parse_opt_result" parse-options.[ch]: consistently use "enum parse_opt_result" parse-options.[ch]: consistently use "enum parse_opt_flags" parse-options.h: move PARSE_OPT_SHELL_EVAL between enums
2 parents f3f157f + d342834 commit 65ca324

File tree

6 files changed

+109
-56
lines changed

6 files changed

+109
-56
lines changed

builtin/blame.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -913,6 +913,9 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
913913
PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0);
914914
for (;;) {
915915
switch (parse_options_step(&ctx, options, blame_opt_usage)) {
916+
case PARSE_OPT_NON_OPTION:
917+
case PARSE_OPT_UNKNOWN:
918+
break;
916919
case PARSE_OPT_HELP:
917920
case PARSE_OPT_ERROR:
918921
exit(129);

builtin/commit-graph.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,8 @@ static int write_option_max_new_filters(const struct option *opt,
172172
const char *s;
173173
*to = strtol(arg, (char **)&s, 10);
174174
if (*s)
175-
return error(_("%s expects a numerical value"),
176-
optname(opt, opt->flags));
175+
return error(_("option `%s' expects a numerical value"),
176+
"max-new-filters");
177177
}
178178
return 0;
179179
}

builtin/shortlog.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,9 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
374374

375375
for (;;) {
376376
switch (parse_options_step(&ctx, options, shortlog_usage)) {
377+
case PARSE_OPT_NON_OPTION:
378+
case PARSE_OPT_UNKNOWN:
379+
break;
377380
case PARSE_OPT_HELP:
378381
case PARSE_OPT_ERROR:
379382
exit(129);

parse-options.c

Lines changed: 49 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@
88

99
static int disallow_abbreviated_options;
1010

11-
#define OPT_SHORT 1
12-
#define OPT_UNSET 2
11+
enum opt_parsed {
12+
OPT_LONG = 0,
13+
OPT_SHORT = 1<<0,
14+
OPT_UNSET = 1<<1,
15+
};
1316

14-
int optbug(const struct option *opt, const char *reason)
17+
static int optbug(const struct option *opt, const char *reason)
1518
{
1619
if (opt->long_name) {
1720
if (opt->short_name)
@@ -22,9 +25,26 @@ int optbug(const struct option *opt, const char *reason)
2225
return error("BUG: switch '%c' %s", opt->short_name, reason);
2326
}
2427

28+
static const char *optname(const struct option *opt, enum opt_parsed flags)
29+
{
30+
static struct strbuf sb = STRBUF_INIT;
31+
32+
strbuf_reset(&sb);
33+
if (flags & OPT_SHORT)
34+
strbuf_addf(&sb, "switch `%c'", opt->short_name);
35+
else if (flags & OPT_UNSET)
36+
strbuf_addf(&sb, "option `no-%s'", opt->long_name);
37+
else if (flags == OPT_LONG)
38+
strbuf_addf(&sb, "option `%s'", opt->long_name);
39+
else
40+
BUG("optname() got unknown flags %d", flags);
41+
42+
return sb.buf;
43+
}
44+
2545
static enum parse_opt_result get_arg(struct parse_opt_ctx_t *p,
2646
const struct option *opt,
27-
int flags, const char **arg)
47+
enum opt_parsed flags, const char **arg)
2848
{
2949
if (p->opt) {
3050
*arg = p->opt;
@@ -50,7 +70,7 @@ static void fix_filename(const char *prefix, const char **file)
5070
static enum parse_opt_result opt_command_mode_error(
5171
const struct option *opt,
5272
const struct option *all_opts,
53-
int flags)
73+
enum opt_parsed flags)
5474
{
5575
const struct option *that;
5676
struct strbuf that_name = STRBUF_INIT;
@@ -82,7 +102,7 @@ static enum parse_opt_result opt_command_mode_error(
82102
static enum parse_opt_result get_value(struct parse_opt_ctx_t *p,
83103
const struct option *opt,
84104
const struct option *all_opts,
85-
int flags)
105+
enum opt_parsed flags)
86106
{
87107
const char *s, *arg;
88108
const int unset = flags & OPT_UNSET;
@@ -298,11 +318,11 @@ static enum parse_opt_result parse_long_opt(
298318
const struct option *all_opts = options;
299319
const char *arg_end = strchrnul(arg, '=');
300320
const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
301-
int abbrev_flags = 0, ambiguous_flags = 0;
321+
enum opt_parsed abbrev_flags = OPT_LONG, ambiguous_flags = OPT_LONG;
302322

303323
for (; options->type != OPTION_END; options++) {
304324
const char *rest, *long_name = options->long_name;
305-
int flags = 0, opt_flags = 0;
325+
enum opt_parsed flags = OPT_LONG, opt_flags = OPT_LONG;
306326

307327
if (!long_name)
308328
continue;
@@ -481,7 +501,8 @@ static void parse_options_check(const struct option *opts)
481501

482502
static void parse_options_start_1(struct parse_opt_ctx_t *ctx,
483503
int argc, const char **argv, const char *prefix,
484-
const struct option *options, int flags)
504+
const struct option *options,
505+
enum parse_opt_flags flags)
485506
{
486507
ctx->argc = argc;
487508
ctx->argv = argv;
@@ -506,7 +527,8 @@ static void parse_options_start_1(struct parse_opt_ctx_t *ctx,
506527

507528
void parse_options_start(struct parse_opt_ctx_t *ctx,
508529
int argc, const char **argv, const char *prefix,
509-
const struct option *options, int flags)
530+
const struct option *options,
531+
enum parse_opt_flags flags)
510532
{
511533
memset(ctx, 0, sizeof(*ctx));
512534
parse_options_start_1(ctx, argc, argv, prefix, options, flags);
@@ -697,13 +719,14 @@ static void free_preprocessed_options(struct option *options)
697719
free(options);
698720
}
699721

700-
static int usage_with_options_internal(struct parse_opt_ctx_t *,
701-
const char * const *,
702-
const struct option *, int, int);
722+
static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t *,
723+
const char * const *,
724+
const struct option *,
725+
int, int);
703726

704-
int parse_options_step(struct parse_opt_ctx_t *ctx,
705-
const struct option *options,
706-
const char * const usagestr[])
727+
enum parse_opt_result parse_options_step(struct parse_opt_ctx_t *ctx,
728+
const struct option *options,
729+
const char * const usagestr[])
707730
{
708731
int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
709732

@@ -837,9 +860,11 @@ int parse_options_end(struct parse_opt_ctx_t *ctx)
837860
return ctx->cpidx + ctx->argc;
838861
}
839862

840-
int parse_options(int argc, const char **argv, const char *prefix,
841-
const struct option *options, const char * const usagestr[],
842-
int flags)
863+
enum parse_opt_result parse_options(int argc, const char **argv,
864+
const char *prefix,
865+
const struct option *options,
866+
const char * const usagestr[],
867+
enum parse_opt_flags flags)
843868
{
844869
struct parse_opt_ctx_t ctx;
845870
struct option *real_options;
@@ -861,7 +886,7 @@ int parse_options(int argc, const char **argv, const char *prefix,
861886
case PARSE_OPT_NON_OPTION:
862887
case PARSE_OPT_DONE:
863888
break;
864-
default: /* PARSE_OPT_UNKNOWN */
889+
case PARSE_OPT_UNKNOWN:
865890
if (ctx.argv[0][1] == '-') {
866891
error(_("unknown option `%s'"), ctx.argv[0] + 2);
867892
} else if (isascii(*ctx.opt)) {
@@ -897,9 +922,10 @@ static int usage_argh(const struct option *opts, FILE *outfile)
897922
#define USAGE_OPTS_WIDTH 24
898923
#define USAGE_GAP 2
899924

900-
static int usage_with_options_internal(struct parse_opt_ctx_t *ctx,
901-
const char * const *usagestr,
902-
const struct option *opts, int full, int err)
925+
static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t *ctx,
926+
const char * const *usagestr,
927+
const struct option *opts,
928+
int full, int err)
903929
{
904930
FILE *outfile = err ? stderr : stdout;
905931
int need_newline;
@@ -1052,18 +1078,3 @@ void NORETURN usage_msg_opt(const char *msg,
10521078
fprintf(stderr, "fatal: %s\n\n", msg);
10531079
usage_with_options(usagestr, options);
10541080
}
1055-
1056-
const char *optname(const struct option *opt, int flags)
1057-
{
1058-
static struct strbuf sb = STRBUF_INIT;
1059-
1060-
strbuf_reset(&sb);
1061-
if (flags & OPT_SHORT)
1062-
strbuf_addf(&sb, "switch `%c'", opt->short_name);
1063-
else if (flags & OPT_UNSET)
1064-
strbuf_addf(&sb, "option `no-%s'", opt->long_name);
1065-
else
1066-
strbuf_addf(&sb, "option `%s'", opt->long_name);
1067-
1068-
return sb.buf;
1069-
}

parse-options.h

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ enum parse_opt_flags {
3333
PARSE_OPT_KEEP_UNKNOWN = 1 << 3,
3434
PARSE_OPT_NO_INTERNAL_HELP = 1 << 4,
3535
PARSE_OPT_ONE_SHOT = 1 << 5,
36+
PARSE_OPT_SHELL_EVAL = 1 << 6,
3637
};
3738

3839
enum parse_opt_option_flags {
@@ -44,7 +45,6 @@ enum parse_opt_option_flags {
4445
PARSE_OPT_NODASH = 1 << 5,
4546
PARSE_OPT_LITERAL_ARGHELP = 1 << 6,
4647
PARSE_OPT_FROM_ALIAS = 1 << 7,
47-
PARSE_OPT_SHELL_EVAL = 1 << 8,
4848
PARSE_OPT_NOCOMPLETE = 1 << 9,
4949
PARSE_OPT_COMP_ARG = 1 << 10,
5050
PARSE_OPT_CMDMODE = 1 << 11,
@@ -134,7 +134,7 @@ struct option {
134134
const char *argh;
135135
const char *help;
136136

137-
int flags;
137+
enum parse_opt_option_flags flags;
138138
parse_opt_cb *callback;
139139
intptr_t defval;
140140
parse_opt_ll_cb *ll_callback;
@@ -213,9 +213,11 @@ struct option {
213213
* untouched and parse_options() returns the number of options
214214
* processed.
215215
*/
216-
int parse_options(int argc, const char **argv, const char *prefix,
217-
const struct option *options,
218-
const char * const usagestr[], int flags);
216+
enum parse_opt_result parse_options(int argc, const char **argv,
217+
const char *prefix,
218+
const struct option *options,
219+
const char * const usagestr[],
220+
enum parse_opt_flags flags);
219221

220222
NORETURN void usage_with_options(const char * const *usagestr,
221223
const struct option *options);
@@ -224,9 +226,6 @@ NORETURN void usage_msg_opt(const char *msg,
224226
const char * const *usagestr,
225227
const struct option *options);
226228

227-
int optbug(const struct option *opt, const char *reason);
228-
const char *optname(const struct option *opt, int flags);
229-
230229
/*
231230
* Use these assertions for callbacks that expect to be called with NONEG and
232231
* NOARG respectively, and do not otherwise handle the "unset" and "arg"
@@ -264,19 +263,20 @@ struct parse_opt_ctx_t {
264263
const char **out;
265264
int argc, cpidx, total;
266265
const char *opt;
267-
int flags;
266+
enum parse_opt_flags flags;
268267
const char *prefix;
269268
const char **alias_groups; /* must be in groups of 3 elements! */
270269
struct option *updated_options;
271270
};
272271

273272
void parse_options_start(struct parse_opt_ctx_t *ctx,
274273
int argc, const char **argv, const char *prefix,
275-
const struct option *options, int flags);
274+
const struct option *options,
275+
enum parse_opt_flags flags);
276276

277-
int parse_options_step(struct parse_opt_ctx_t *ctx,
278-
const struct option *options,
279-
const char * const usagestr[]);
277+
enum parse_opt_result parse_options_step(struct parse_opt_ctx_t *ctx,
278+
const struct option *options,
279+
const char * const usagestr[]);
280280

281281
int parse_options_end(struct parse_opt_ctx_t *ctx);
282282

t/t0040-parse-options.sh

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,45 @@ test_expect_success 'long options' '
168168
'
169169

170170
test_expect_success 'missing required value' '
171-
test_expect_code 129 test-tool parse-options -s &&
172-
test_expect_code 129 test-tool parse-options --string &&
173-
test_expect_code 129 test-tool parse-options --file
171+
cat >expect <<-\EOF &&
172+
error: switch `s'\'' requires a value
173+
EOF
174+
test_expect_code 129 test-tool parse-options -s 2>actual &&
175+
test_cmp expect actual &&
176+
177+
cat >expect <<-\EOF &&
178+
error: option `string'\'' requires a value
179+
EOF
180+
test_expect_code 129 test-tool parse-options --string 2>actual &&
181+
test_cmp expect actual &&
182+
183+
cat >expect <<-\EOF &&
184+
error: option `file'\'' requires a value
185+
EOF
186+
test_expect_code 129 test-tool parse-options --file 2>actual &&
187+
test_cmp expect actual
188+
'
189+
190+
test_expect_success 'superfluous value provided: boolean' '
191+
cat >expect <<-\EOF &&
192+
error: option `yes'\'' takes no value
193+
EOF
194+
test_expect_code 129 test-tool parse-options --yes=hi 2>actual &&
195+
test_cmp expect actual &&
196+
197+
cat >expect <<-\EOF &&
198+
error: option `no-yes'\'' takes no value
199+
EOF
200+
test_expect_code 129 test-tool parse-options --no-yes=hi 2>actual &&
201+
test_cmp expect actual
202+
'
203+
204+
test_expect_success 'superfluous value provided: cmdmode' '
205+
cat >expect <<-\EOF &&
206+
error: option `mode1'\'' takes no value
207+
EOF
208+
test_expect_code 129 test-tool parse-options --mode1=hi 2>actual &&
209+
test_cmp expect actual
174210
'
175211

176212
cat >expect <<\EOF

0 commit comments

Comments
 (0)