diff --git a/argparse.c b/argparse.c index ec86bba7..02df0393 100644 --- a/argparse.c +++ b/argparse.c @@ -47,10 +47,11 @@ argparse_error(struct argparse *self, const struct argparse_option *opt, } static int -argparse_getvalue(struct argparse *self, const struct argparse_option *opt, +argparse_getvalue(struct argparse *self, struct argparse_option *opt, int flags) { const char *s = NULL; + opt->parsed = 1; if (!opt->value) goto skipped; switch (opt->type) { @@ -147,7 +148,7 @@ argparse_options_check(const struct argparse_option *options) } static int -argparse_short_opt(struct argparse *self, const struct argparse_option *options) +argparse_short_opt(struct argparse *self, struct argparse_option *options) { for (; options->type != ARGPARSE_OPT_END; options++) { if (options->short_name == *self->optvalue) { @@ -159,7 +160,7 @@ argparse_short_opt(struct argparse *self, const struct argparse_option *options) } static int -argparse_long_opt(struct argparse *self, const struct argparse_option *options) +argparse_long_opt(struct argparse *self, struct argparse_option *options) { for (; options->type != ARGPARSE_OPT_END; options++) { const char *rest; @@ -218,9 +219,22 @@ argparse_describe(struct argparse *self, const char *description, self->epilog = epilog; } +void argparse_check_for_required(struct argparse *self, struct argparse_option *options) { + for(; options->type != ARGPARSE_OPT_END; options++) { + // printf("checking %s %d %d\n", options->long_name, options->parsed, options->flags); + if((options->flags & OPT_REQUIRED) == OPT_REQUIRED && !options->parsed) { + // error => required option not parsed + fprintf(stderr, "error: option `%s` required\n", options->long_name); + argparse_usage(self); + exit(1); + } + } +} + int argparse_parse(struct argparse *self, int argc, const char **argv) { + self->argc = argc - 1; self->argv = argv + 1; self->out = argv; @@ -278,6 +292,9 @@ argparse_parse(struct argparse *self, int argc, const char **argv) } end: + // check required options and exit if not all flags are satisfied + argparse_check_for_required(self, self->options); + memmove(self->out + self->cpidx, self->argv, self->argc * sizeof(*self->out)); self->out[self->cpidx + self->argc] = NULL; @@ -302,7 +319,7 @@ argparse_usage(struct argparse *self) fputc('\n', stdout); - const struct argparse_option *options; + struct argparse_option *options; // figure out best width size_t usage_opts_width = 0; diff --git a/argparse.h b/argparse.h index 44ce835a..0a9c9e77 100644 --- a/argparse.h +++ b/argparse.h @@ -40,6 +40,7 @@ enum argparse_option_type { enum argparse_option_flags { OPT_NONEG = 1, /* disable negation */ + OPT_REQUIRED }; /** @@ -70,6 +71,9 @@ enum argparse_option_flags { * * `flags`: * option flags. + * + * * `parsed`: + * boolean to see if the option showed up in the argument list. */ struct argparse_option { enum argparse_option_type type; @@ -80,6 +84,7 @@ struct argparse_option { argparse_callback *callback; intptr_t data; int flags; + int parsed; }; /** @@ -87,7 +92,7 @@ struct argparse_option { */ struct argparse { // user supplied - const struct argparse_option *options; + struct argparse_option *options; const char *const *usages; int flags; const char *description; // a description after usage @@ -105,13 +110,14 @@ int argparse_help_cb(struct argparse *self, const struct argparse_option *option); // built-in option macros -#define OPT_END() { ARGPARSE_OPT_END, 0, NULL, NULL, 0, NULL, 0, 0 } -#define OPT_BOOLEAN(...) { ARGPARSE_OPT_BOOLEAN, __VA_ARGS__ } -#define OPT_BIT(...) { ARGPARSE_OPT_BIT, __VA_ARGS__ } -#define OPT_INTEGER(...) { ARGPARSE_OPT_INTEGER, __VA_ARGS__ } -#define OPT_FLOAT(...) { ARGPARSE_OPT_FLOAT, __VA_ARGS__ } -#define OPT_STRING(...) { ARGPARSE_OPT_STRING, __VA_ARGS__ } -#define OPT_GROUP(h) { ARGPARSE_OPT_GROUP, 0, NULL, NULL, h, NULL, 0, 0 } +// initially all parsed values for options are 0 +#define OPT_END() { ARGPARSE_OPT_END, 0, NULL, NULL, 0, NULL, 0, 0, 0 } +#define OPT_BOOLEAN(...) { ARGPARSE_OPT_BOOLEAN, __VA_ARGS__, 0 } +#define OPT_BIT(...) { ARGPARSE_OPT_BIT, __VA_ARGS__, 0 } +#define OPT_INTEGER(...) { ARGPARSE_OPT_INTEGER, __VA_ARGS__, 0 } +#define OPT_FLOAT(...) { ARGPARSE_OPT_FLOAT, __VA_ARGS__, 0 } +#define OPT_STRING(...) { ARGPARSE_OPT_STRING, __VA_ARGS__, 0 } +#define OPT_GROUP(h) { ARGPARSE_OPT_GROUP, 0, NULL, NULL, h, NULL, 0, 0, 0 } #define OPT_HELP() OPT_BOOLEAN('h', "help", NULL, \ "show this help message and exit", \ argparse_help_cb, 0, OPT_NONEG)