Skip to content

Commit ffe659f

Browse files
MadCodergitster
authored andcommitted
parse-options: make some arguments optional, add callbacks.
* add the possibility to use callbacks to parse some options, this can help implementing new options kinds with great flexibility. struct option gains a callback pointer and a `defval' where callbacks user can put either integers or pointers. callbacks also can use the `value' pointer for anything, preferably to the pointer to the final storage for the value though. * add a `flag' member to struct option to make explicit that this option may have an optional argument. The semantics depends on the option type. For INTEGERS, it means that if the switch is not used in its --long-form=<value> form, and that there is no token after it or that the token does not starts with a digit, then it's assumed that the switch has no argument. For STRING or CALLBACK it works the same, except that the condition is that the next atom starts with a dash. This is needed to implement backward compatible behaviour with existing ways to parse the command line. Its use for new options is discouraged. Signed-off-by: Pierre Habouzit <madcoder@debian.org> Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
1 parent f389c80 commit ffe659f

File tree

2 files changed

+53
-8
lines changed

2 files changed

+53
-8
lines changed

parse-options.c

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ static int opterror(const struct option *opt, const char *reason, int flags)
3939
static int get_value(struct optparse_t *p,
4040
const struct option *opt, int flags)
4141
{
42-
const char *s;
42+
const char *s, *arg;
43+
arg = p->opt ? p->opt : (p->argc > 1 ? p->argv[1] : NULL);
4344

4445
if (p->opt && (flags & OPT_UNSET))
4546
return opterror(opt, "takes no value", flags);
@@ -59,17 +60,34 @@ static int get_value(struct optparse_t *p,
5960
*(const char **)opt->value = (const char *)NULL;
6061
return 0;
6162
}
62-
if (!p->opt && p->argc <= 1)
63+
if (opt->flags & PARSE_OPT_OPTARG && (!arg || *arg == '-')) {
64+
*(const char **)opt->value = (const char *)opt->defval;
65+
return 0;
66+
}
67+
if (!arg)
6368
return opterror(opt, "requires a value", flags);
6469
*(const char **)opt->value = get_arg(p);
6570
return 0;
6671

72+
case OPTION_CALLBACK:
73+
if (flags & OPT_UNSET)
74+
return (*opt->callback)(opt, NULL, 1);
75+
if (opt->flags & PARSE_OPT_OPTARG && (!arg || *arg == '-'))
76+
return (*opt->callback)(opt, NULL, 0);
77+
if (!arg)
78+
return opterror(opt, "requires a value", flags);
79+
return (*opt->callback)(opt, get_arg(p), 0);
80+
6781
case OPTION_INTEGER:
6882
if (flags & OPT_UNSET) {
6983
*(int *)opt->value = 0;
7084
return 0;
7185
}
72-
if (!p->opt && p->argc <= 1)
86+
if (opt->flags & PARSE_OPT_OPTARG && (!arg || !isdigit(*arg))) {
87+
*(int *)opt->value = opt->defval;
88+
return 0;
89+
}
90+
if (!arg)
7391
return opterror(opt, "requires a value", flags);
7492
*(int *)opt->value = strtol(get_arg(p), (char **)&s, 10);
7593
if (*s)
@@ -201,13 +219,24 @@ void usage_with_options(const char * const *usagestr,
201219

202220
switch (opts->type) {
203221
case OPTION_INTEGER:
204-
pos += fprintf(stderr, " <n>");
222+
if (opts->flags & PARSE_OPT_OPTARG)
223+
pos += fprintf(stderr, " [<n>]");
224+
else
225+
pos += fprintf(stderr, " <n>");
205226
break;
206227
case OPTION_STRING:
207-
if (opts->argh)
208-
pos += fprintf(stderr, " <%s>", opts->argh);
209-
else
210-
pos += fprintf(stderr, " ...");
228+
case OPTION_CALLBACK:
229+
if (opts->argh) {
230+
if (opts->flags & PARSE_OPT_OPTARG)
231+
pos += fprintf(stderr, " [<%s>]", opts->argh);
232+
else
233+
pos += fprintf(stderr, " <%s>", opts->argh);
234+
} else {
235+
if (opts->flags & PARSE_OPT_OPTARG)
236+
pos += fprintf(stderr, " [...]");
237+
else
238+
pos += fprintf(stderr, " ...");
239+
}
211240
break;
212241
default:
213242
break;

parse-options.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,42 @@ enum parse_opt_type {
77
OPTION_BOOLEAN,
88
OPTION_STRING,
99
OPTION_INTEGER,
10+
OPTION_CALLBACK,
1011
};
1112

1213
enum parse_opt_flags {
1314
PARSE_OPT_KEEP_DASHDASH = 1,
1415
};
1516

17+
enum parse_opt_option_flags {
18+
PARSE_OPT_OPTARG = 1,
19+
};
20+
21+
struct option;
22+
typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
23+
1624
struct option {
1725
enum parse_opt_type type;
1826
int short_name;
1927
const char *long_name;
2028
void *value;
2129
const char *argh;
2230
const char *help;
31+
32+
int flags;
33+
parse_opt_cb *callback;
34+
/* holds default value for PARSE_OPT_OPTARG,
35+
though callbacks can use it like they want */
36+
intptr_t defval;
2337
};
2438

2539
#define OPT_END() { OPTION_END }
2640
#define OPT_GROUP(h) { OPTION_GROUP, 0, NULL, NULL, NULL, (h) }
2741
#define OPT_BOOLEAN(s, l, v, h) { OPTION_BOOLEAN, (s), (l), (v), NULL, (h) }
2842
#define OPT_INTEGER(s, l, v, h) { OPTION_INTEGER, (s), (l), (v), NULL, (h) }
2943
#define OPT_STRING(s, l, v, a, h) { OPTION_STRING, (s), (l), (v), (a), (h) }
44+
#define OPT_CALLBACK(s, l, v, a, h, f) \
45+
{ OPTION_CALLBACK, (s), (l), (v), (a), (h), 0, (f) }
3046

3147
/* parse_options() will filter out the processed options and leave the
3248
* non-option argments in argv[].

0 commit comments

Comments
 (0)