summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--parse-options.c45
-rw-r--r--parse-options.h16
2 files changed, 53 insertions, 8 deletions
diff --git a/parse-options.c b/parse-options.c
index 89c5f52be5..c751ebf601 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -39,7 +39,8 @@ static int opterror(const struct option *opt, const char *reason, int flags)
static int get_value(struct optparse_t *p,
const struct option *opt, int flags)
{
- const char *s;
+ const char *s, *arg;
+ arg = p->opt ? p->opt : (p->argc > 1 ? p->argv[1] : NULL);
if (p->opt && (flags & OPT_UNSET))
return opterror(opt, "takes no value", flags);
@@ -59,17 +60,34 @@ static int get_value(struct optparse_t *p,
*(const char **)opt->value = (const char *)NULL;
return 0;
}
- if (!p->opt && p->argc <= 1)
+ if (opt->flags & PARSE_OPT_OPTARG && (!arg || *arg == '-')) {
+ *(const char **)opt->value = (const char *)opt->defval;
+ return 0;
+ }
+ if (!arg)
return opterror(opt, "requires a value", flags);
*(const char **)opt->value = get_arg(p);
return 0;
+ case OPTION_CALLBACK:
+ if (flags & OPT_UNSET)
+ return (*opt->callback)(opt, NULL, 1);
+ if (opt->flags & PARSE_OPT_OPTARG && (!arg || *arg == '-'))
+ return (*opt->callback)(opt, NULL, 0);
+ if (!arg)
+ return opterror(opt, "requires a value", flags);
+ return (*opt->callback)(opt, get_arg(p), 0);
+
case OPTION_INTEGER:
if (flags & OPT_UNSET) {
*(int *)opt->value = 0;
return 0;
}
- if (!p->opt && p->argc <= 1)
+ if (opt->flags & PARSE_OPT_OPTARG && (!arg || !isdigit(*arg))) {
+ *(int *)opt->value = opt->defval;
+ return 0;
+ }
+ if (!arg)
return opterror(opt, "requires a value", flags);
*(int *)opt->value = strtol(get_arg(p), (char **)&s, 10);
if (*s)
@@ -201,13 +219,24 @@ void usage_with_options(const char * const *usagestr,
switch (opts->type) {
case OPTION_INTEGER:
- pos += fprintf(stderr, " <n>");
+ if (opts->flags & PARSE_OPT_OPTARG)
+ pos += fprintf(stderr, " [<n>]");
+ else
+ pos += fprintf(stderr, " <n>");
break;
case OPTION_STRING:
- if (opts->argh)
- pos += fprintf(stderr, " <%s>", opts->argh);
- else
- pos += fprintf(stderr, " ...");
+ case OPTION_CALLBACK:
+ if (opts->argh) {
+ if (opts->flags & PARSE_OPT_OPTARG)
+ pos += fprintf(stderr, " [<%s>]", opts->argh);
+ else
+ pos += fprintf(stderr, " <%s>", opts->argh);
+ } else {
+ if (opts->flags & PARSE_OPT_OPTARG)
+ pos += fprintf(stderr, " [...]");
+ else
+ pos += fprintf(stderr, " ...");
+ }
break;
default:
break;
diff --git a/parse-options.h b/parse-options.h
index 3006a769cd..2b8e7624d6 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -7,12 +7,20 @@ enum parse_opt_type {
OPTION_BOOLEAN,
OPTION_STRING,
OPTION_INTEGER,
+ OPTION_CALLBACK,
};
enum parse_opt_flags {
PARSE_OPT_KEEP_DASHDASH = 1,
};
+enum parse_opt_option_flags {
+ PARSE_OPT_OPTARG = 1,
+};
+
+struct option;
+typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
+
struct option {
enum parse_opt_type type;
int short_name;
@@ -20,6 +28,12 @@ struct option {
void *value;
const char *argh;
const char *help;
+
+ int flags;
+ parse_opt_cb *callback;
+ /* holds default value for PARSE_OPT_OPTARG,
+ though callbacks can use it like they want */
+ intptr_t defval;
};
#define OPT_END() { OPTION_END }
@@ -27,6 +41,8 @@ struct option {
#define OPT_BOOLEAN(s, l, v, h) { OPTION_BOOLEAN, (s), (l), (v), NULL, (h) }
#define OPT_INTEGER(s, l, v, h) { OPTION_INTEGER, (s), (l), (v), NULL, (h) }
#define OPT_STRING(s, l, v, a, h) { OPTION_STRING, (s), (l), (v), (a), (h) }
+#define OPT_CALLBACK(s, l, v, a, h, f) \
+ { OPTION_CALLBACK, (s), (l), (v), (a), (h), 0, (f) }
/* parse_options() will filter out the processed options and leave the
* non-option argments in argv[].