From 2f4b97f91071f5060bf2da482cf8b0d70486d808 Mon Sep 17 00:00:00 2001 From: René Scharfe Date: Thu, 7 May 2009 21:44:17 +0200 Subject: parseopt: add OPT_NEGBIT Add OPTION_NEGBIT and OPT_NEGBIT, mirroring OPTION_BIT and OPT_BIT. OPT_NEGBIT can be used together with OPT_BIT to define two options that cancel each other out. Note: this patch removes the reminder from the test script because it adds a test for --no-or4 and there already was one for --or4. Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano --- test-parse-options.c | 1 + 1 file changed, 1 insertion(+) (limited to 'test-parse-options.c') diff --git a/test-parse-options.c b/test-parse-options.c index 61d2c39814..eddc0267a2 100644 --- a/test-parse-options.c +++ b/test-parse-options.c @@ -29,6 +29,7 @@ int main(int argc, const char **argv) OPT_BOOLEAN('b', "boolean", &boolean, "get a boolean"), OPT_BIT('4', "or4", &boolean, "bitwise-or boolean with ...0100", 4), + OPT_NEGBIT(0, "neg-or4", &boolean, "same as --no-or4", 4), OPT_GROUP(""), OPT_INTEGER('i', "integer", &integer, "get a integer"), OPT_INTEGER('j', NULL, &integer, "get a integer, too"), -- cgit v1.3-5-g9baa From e0319ff5ed2b7927302389181449dcd029a26622 Mon Sep 17 00:00:00 2001 From: René Scharfe Date: Thu, 7 May 2009 21:45:08 +0200 Subject: 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 Signed-off-by: Junio C Hamano --- Documentation/technical/api-parse-options.txt | 8 ++++++++ parse-options.c | 26 +++++++++++++++++++++++++- parse-options.h | 4 ++++ t/t0040-parse-options.sh | 18 ++++++++++++++++++ test-parse-options.c | 8 ++++++++ 5 files changed, 63 insertions(+), 1 deletion(-) (limited to 'test-parse-options.c') diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt index 794194bad6..beca98d754 100644 --- a/Documentation/technical/api-parse-options.txt +++ b/Documentation/technical/api-parse-options.txt @@ -170,6 +170,14 @@ There are some macros to easily define options: `OPT_ARGUMENT(long, description)`:: Introduce a long-option argument that will be kept in `argv[]`. +`OPT_NUMBER_CALLBACK(&var, description, func_ptr)`:: + Recognize numerical options like -123 and feed the integer as + if it was an argument to the function given by `func_ptr`. + The result will be put into `var`. There can be only one such + option definition. It cannot be negated and it takes no + arguments. Short options that happen to be digits take + precedence over it. + The last element of the array must be `OPT_END()`. diff --git a/parse-options.c b/parse-options.c index a8c05e3dc2..aaa218d191 100644 --- a/parse-options.c +++ b/parse-options.c @@ -129,11 +129,33 @@ static int get_value(struct parse_opt_ctx_t *p, static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options) { + const struct option *numopt = NULL; + for (; options->type != OPTION_END; options++) { if (options->short_name == *p->opt) { p->opt = p->opt[1] ? p->opt + 1 : NULL; return get_value(p, options, OPT_SHORT); } + + /* + * Handle the numerical option later, explicit one-digit + * options take precedence over it. + */ + if (options->type == OPTION_NUMBER) + numopt = options; + } + if (numopt && isdigit(*p->opt)) { + size_t len = 1; + char *arg; + int rc; + + while (isdigit(p->opt[len])) + len++; + arg = xmemdupz(p->opt, len); + p->opt = p->opt[len] ? p->opt + len : NULL; + rc = (*numopt->callback)(numopt, arg, 0) ? (-1) : 0; + free(arg); + return rc; } return -2; } @@ -411,6 +433,8 @@ int usage_with_options_internal(const char * const *usagestr, pos += fprintf(stderr, ", "); if (opts->long_name) pos += fprintf(stderr, "--%s", opts->long_name); + if (opts->type == OPTION_NUMBER) + pos += fprintf(stderr, "-NUM"); switch (opts->type) { case OPTION_ARGUMENT: @@ -447,7 +471,7 @@ int usage_with_options_internal(const char * const *usagestr, pos += fprintf(stderr, " ..."); } break; - default: /* OPTION_{BIT,BOOLEAN,SET_INT,SET_PTR} */ + default: /* OPTION_{BIT,BOOLEAN,NUMBER,SET_INT,SET_PTR} */ break; } diff --git a/parse-options.h b/parse-options.h index f1e2452f69..77919a77fb 100644 --- a/parse-options.h +++ b/parse-options.h @@ -6,6 +6,7 @@ enum parse_opt_type { OPTION_END, OPTION_ARGUMENT, OPTION_GROUP, + OPTION_NUMBER, /* options with no arguments */ OPTION_BIT, OPTION_NEGBIT, @@ -105,6 +106,9 @@ struct option { parse_opt_approxidate_cb } #define OPT_CALLBACK(s, l, v, a, h, f) \ { OPTION_CALLBACK, (s), (l), (v), (a), (h), 0, (f) } +#define OPT_NUMBER_CALLBACK(v, h, f) \ + { OPTION_NUMBER, 0, NULL, (v), NULL, (h), \ + PARSE_OPT_NOARG | PARSE_OPT_NONEG, (f) } /* parse_options() will filter out the processed options and leave the * non-option arguments in argv[]. diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index 9054ed6030..8ca62ef453 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -30,6 +30,7 @@ String options Magic arguments --quux means --quux + -NUM set integer to NUM Standard options --abbrev[=] use digits to display SHA-1s @@ -275,4 +276,21 @@ test_expect_success 'OPT_NEGBIT() works' ' test_cmp expect output ' +cat > expect < output 2> output.err && + test ! -s output.err && + test_cmp expect output +' + test_done diff --git a/test-parse-options.c b/test-parse-options.c index eddc0267a2..d46eac21b1 100644 --- a/test-parse-options.c +++ b/test-parse-options.c @@ -19,6 +19,12 @@ int length_callback(const struct option *opt, const char *arg, int unset) return 0; } +int number_callback(const struct option *opt, const char *arg, int unset) +{ + *(int *)opt->value = strtol(arg, NULL, 10); + return 0; +} + int main(int argc, const char **argv) { const char *usage[] = { @@ -46,6 +52,8 @@ int main(int argc, const char **argv) "set string to default", (unsigned long)"default"), OPT_GROUP("Magic arguments"), OPT_ARGUMENT("quux", "means --quux"), + OPT_NUMBER_CALLBACK(&integer, "set integer to NUM", + number_callback), OPT_GROUP("Standard options"), OPT__ABBREV(&abbrev), OPT__VERBOSE(&verbose), -- cgit v1.3-5-g9baa From 51a9949eda7421a2dd9cb45b2110d6571ba09bbd Mon Sep 17 00:00:00 2001 From: René Scharfe Date: Thu, 7 May 2009 21:45:42 +0200 Subject: parseopt: add PARSE_OPT_NODASH Add support for options that don't start with a dash. Initially, they don't accept arguments and can only be short options, i.e. consist of a single character. Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano --- parse-options.c | 29 +++++++++++++++++++++++++++-- parse-options.h | 8 ++++++-- t/t0040-parse-options.sh | 7 +++++++ test-parse-options.c | 2 ++ 4 files changed, 42 insertions(+), 4 deletions(-) (limited to 'test-parse-options.c') diff --git a/parse-options.c b/parse-options.c index aaa218d191..c52b8ccf59 100644 --- a/parse-options.c +++ b/parse-options.c @@ -245,6 +245,25 @@ is_abbreviated: return -2; } +static int parse_nodash_opt(struct parse_opt_ctx_t *p, const char *arg, + const struct option *options) +{ + for (; options->type != OPTION_END; options++) { + if (!(options->flags & PARSE_OPT_NODASH)) + continue; + if ((options->flags & PARSE_OPT_OPTARG) || + !(options->flags & PARSE_OPT_NOARG)) + die("BUG: dashless options don't support arguments"); + if (!(options->flags & PARSE_OPT_NONEG)) + die("BUG: dashless options don't support negation"); + if (options->long_name) + die("BUG: dashless options can't be long"); + if (options->short_name == arg[0] && arg[1] == '\0') + return get_value(p, options, OPT_SHORT); + } + return -2; +} + static void check_typos(const char *arg, const struct option *options) { if (strlen(arg) < 3) @@ -295,6 +314,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, const char *arg = ctx->argv[0]; if (*arg != '-' || !arg[1]) { + if (parse_nodash_opt(ctx, arg, options) == 0) + continue; if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION) break; ctx->out[ctx->cpidx++] = ctx->argv[0]; @@ -427,8 +448,12 @@ int usage_with_options_internal(const char * const *usagestr, continue; pos = fprintf(stderr, " "); - if (opts->short_name) - pos += fprintf(stderr, "-%c", opts->short_name); + if (opts->short_name) { + if (opts->flags & PARSE_OPT_NODASH) + pos += fprintf(stderr, "%c", opts->short_name); + else + pos += fprintf(stderr, "-%c", opts->short_name); + } if (opts->long_name && opts->short_name) pos += fprintf(stderr, ", "); if (opts->long_name) diff --git a/parse-options.h b/parse-options.h index 77919a77fb..919b9b441f 100644 --- a/parse-options.h +++ b/parse-options.h @@ -33,6 +33,7 @@ enum parse_opt_option_flags { PARSE_OPT_NONEG = 4, PARSE_OPT_HIDDEN = 8, PARSE_OPT_LASTARG_DEFAULT = 16, + PARSE_OPT_NODASH = 32, }; struct option; @@ -66,8 +67,11 @@ typedef int parse_opt_cb(const struct option *, const char *arg, int unset); * PARSE_OPT_OPTARG: says that the argument is optional (not for BOOLEANs) * PARSE_OPT_NOARG: says that this option takes no argument, for CALLBACKs * PARSE_OPT_NONEG: says that this option cannot be negated - * PARSE_OPT_HIDDEN this option is skipped in the default usage, showed in - * the long one. + * PARSE_OPT_HIDDEN: this option is skipped in the default usage, and + * shown only in the full usage. + * PARSE_OPT_LASTARG_DEFAULT: if no argument is given, the default value + * is used. + * PARSE_OPT_NODASH: this option doesn't start with a dash. * * `callback`:: * pointer to the callback to use for OPTION_CALLBACK. diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index 8ca62ef453..a40c1236c0 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -31,6 +31,7 @@ String options Magic arguments --quux means --quux -NUM set integer to NUM + + same as -b Standard options --abbrev[=] use digits to display SHA-1s @@ -276,6 +277,12 @@ test_expect_success 'OPT_NEGBIT() works' ' test_cmp expect output ' +test_expect_success 'OPT_BOOLEAN() with PARSE_OPT_NODASH works' ' + test-parse-options + + + + + + > output 2> output.err && + test ! -s output.err && + test_cmp expect output +' + cat > expect <