From 760ae9e3a01c7dee03bb57d5dbdbeaa3b0670735 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Mon, 17 Feb 2014 18:41:33 +0100 Subject: [PATCH] Opt: Improved parsing of negative boolean options Boolean options with the OPT_NEGATIVE flag, which are named "no-X", are also recognized as bare "X" with positive meaning. Include tests for processing of both positive and negative bools. --- ucw/opt-test.c | 3 +++ ucw/opt.c | 24 ++++++++++++++++++++---- ucw/opt.t | 28 ++++++++++++++++++++++------ 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/ucw/opt-test.c b/ucw/opt-test.c index a030eefe..ffaf0f9e 100644 --- a/ucw/opt-test.c +++ b/ucw/opt-test.c @@ -50,6 +50,7 @@ static int with_gas = 0; static int *black_magic; static int pray = 0; static int water_amount = 0; +static int clean_pot = 1; static char * first_tea = NULL; #define MAX_TEA_COUNT 30 @@ -144,6 +145,7 @@ static struct opt_section options = { OPT_INC('q', "quiet", verbose, OPT_NEGATIVE, "\tQuiet (the more -q, the more quiet)"), OPT_INT_MULTIPLE('b', NULL, black_magic, 0, "\tUse black magic to make the tea extraordinarily delicious.\n\t\tMay be specified more than once to describe the amounts of black magic to be invoked in each step of tea boiling."), OPT_BOOL('p', "pray", pray, OPT_SINGLE, "\tPray before boiling"), + OPT_BOOL(0, "no-clean", clean_pot, OPT_NEGATIVE, "\tDo not clean the teapot before boiling"), OPT_STRING(OPT_POSITIONAL(1), NULL, first_tea, OPT_REQUIRED, ""), OPT_CALL(OPT_POSITIONAL_TAIL, NULL, add_tea, &tea_list, 0, ""), OPT_HELP(""), @@ -182,6 +184,7 @@ int main(int argc UNUSED, char ** argv) for (uns i=0; iname, str, len)) { if (strlen(opt->name) == len) return opt; - } else if (opt->item->cls == OPT_CL_BOOL && !strncmp("no-", str, 3) && !strncmp(opt->name, str+3, len-3)) { - if (strlen(opt->name) == len-3) - return opt; + } else if (opt->item->cls == OPT_CL_BOOL) { + if (opt->flags & OPT_NEGATIVE) { + // If the option is called no-X, match X as well + if (!strncmp("no-", opt->name, 3) && !strncmp(opt->name+3, str, len)) { + if (strlen(opt->name) == len+3) + return opt; + } else + continue; + } else { + // Match no-X as well + if (!strncmp("no-", str, 3) && !strncmp(opt->name, str+3, len-3)) { + if (strlen(opt->name) == len-3) + return opt; + } else + continue; + } } else continue; @@ -228,7 +241,10 @@ static int opt_longopt(struct opt_context * oc, char ** argv, int index) { opt->flags |= OPT_SEEN_AS_LONG; - if (opt->item->cls == OPT_CL_BOOL && !strncmp(name_in, "no-", 3) && !strncmp(name_in+3, opt->item->name, pos-3)) { + if (opt->item->cls == OPT_CL_BOOL && + ((opt->flags & OPT_NEGATIVE) + ? (!strncmp(opt->item->name, "no-", 3) && !strncmp(name_in, opt->item->name + 3, pos-3)) + : (!strncmp(name_in, "no-", 3) && !strncmp(name_in+3, opt->item->name, pos-3)))) { if (name_in[pos]) opt_failure("Option --%s must not have any value.", name_in); value = "n"; diff --git a/ucw/opt.t b/ucw/opt.t index 26c9ab37..8ac04438 100644 --- a/ucw/opt.t +++ b/ucw/opt.t @@ -8,15 +8,15 @@ Out: Required option -t/--temperature not found. Name: Opt-2 Run: ../obj/ucw/opt-test -t95C -w640 -gG darjeeling -Out: English style: no|Chosen teapot: glass|Temperature: 95C|Verbosity: 1|Prayer: no|Water amount: 640|Gas: yes|First tea: darjeeling|Everything OK. Bye. +Out: English style: no|Chosen teapot: glass|Temperature: 95C|Verbosity: 1|Prayer: no|Clean: yes|Water amount: 640|Gas: yes|First tea: darjeeling|Everything OK. Bye. Name: Opt-3 Run: ../obj/ucw/opt-test -vvqvqvhpe -t120F -w4 darjeeling -Out: English style: yes|Chosen teapot: hands|Temperature: 120F|Verbosity: 3|Prayer: yes|Water amount: 4|Gas: no|First tea: darjeeling|Everything OK. Bye. +Out: English style: yes|Chosen teapot: hands|Temperature: 120F|Verbosity: 3|Prayer: yes|Clean: yes|Water amount: 4|Gas: no|First tea: darjeeling|Everything OK. Bye. Name: Opt-4 Run: ../obj/ucw/opt-test -t120F -w4 puerh darjeeling earl-grey -Out: English style: no|Temperature: 120F|Verbosity: 1|Prayer: no|Water amount: 4|Gas: no|First tea: puerh|Boiling a tea: darjeeling|Boiling a tea: earl-grey|Everything OK. Bye. +Out: English style: no|Temperature: 120F|Verbosity: 1|Prayer: no|Clean: yes|Water amount: 4|Gas: no|First tea: puerh|Boiling a tea: darjeeling|Boiling a tea: earl-grey|Everything OK. Bye. Name: Opt-5 Run: ../obj/ucw/opt-test -ghx 2>&1 1>/dev/null @@ -26,11 +26,27 @@ Out: Multiple switches: -h Name: Opt-6 Run: ../obj/ucw/opt-test -t120F -w4 -b15 -he -- --puerh darjeeling earl-grey -Out: English style: yes|Chosen teapot: hands|Temperature: 120F|Verbosity: 1|Black magic: 15|Prayer: no|Water amount: 4|Gas: no|First tea: --puerh|Boiling a tea: darjeeling|Boiling a tea: earl-grey|Everything OK. Bye. +Out: English style: yes|Chosen teapot: hands|Temperature: 120F|Verbosity: 1|Black magic: 15|Prayer: no|Clean: yes|Water amount: 4|Gas: no|First tea: --puerh|Boiling a tea: darjeeling|Boiling a tea: earl-grey|Everything OK. Bye. Name: Opt-7 Run: ../obj/ucw/opt-test -t120F -w4 -b15 -b54 -he -- --puerh darjeeling earl-grey -Out: English style: yes|Chosen teapot: hands|Temperature: 120F|Verbosity: 1|Black magic: 15|Black magic: 54|Prayer: no|Water amount: 4|Gas: no|First tea: --puerh|Boiling a tea: darjeeling|Boiling a tea: earl-grey|Everything OK. Bye. +Out: English style: yes|Chosen teapot: hands|Temperature: 120F|Verbosity: 1|Black magic: 15|Black magic: 54|Prayer: no|Clean: yes|Water amount: 4|Gas: no|First tea: --puerh|Boiling a tea: darjeeling|Boiling a tea: earl-grey|Everything OK. Bye. + +Name: Opt-bool-1 +Run: ../obj/ucw/opt-test -t95C -w640 -gG darjeeling --english-style +Out: English style: yes|Chosen teapot: glass|Temperature: 95C|Verbosity: 1|Prayer: no|Clean: yes|Water amount: 640|Gas: yes|First tea: darjeeling|Everything OK. Bye. + +Name: Opt-bool-2 +Run: ../obj/ucw/opt-test -t95C -w640 -gG darjeeling --english-style --no-english-style +Out: English style: no|Chosen teapot: glass|Temperature: 95C|Verbosity: 1|Prayer: no|Clean: yes|Water amount: 640|Gas: yes|First tea: darjeeling|Everything OK. Bye. + +Name: Opt-bool-negative-1 +Run: ../obj/ucw/opt-test -t95C -w640 -gG darjeeling --clean +Out: English style: no|Chosen teapot: glass|Temperature: 95C|Verbosity: 1|Prayer: no|Clean: yes|Water amount: 640|Gas: yes|First tea: darjeeling|Everything OK. Bye. + +Name: Opt-bool-negative-2 +Run: ../obj/ucw/opt-test -t95C -w640 -gG darjeeling --no-clean +Out: English style: no|Chosen teapot: glass|Temperature: 95C|Verbosity: 1|Prayer: no|Clean: no|Water amount: 640|Gas: yes|First tea: darjeeling|Everything OK. Bye. Name: Opt-Conf-1 Run: ../obj/ucw/opt-test -h -SX.Y=Z 2>&1 1>/dev/null @@ -40,4 +56,4 @@ Out: Config options must stand before other options. Name: Opt-Hook-1 Run: ../obj/ucw/opt-test -Ht 95C -w640 -gG darjeeling -Out: [HOOK-postval:H/show-hooks=(null)] [HOOK-preval:t/temperature=95C] [HOOK-postval:t/temperature=95C] [HOOK-prearg] [HOOK-preval:w/water=640] [HOOK-postval:w/water=640] [HOOK-prearg] [HOOK-preval:g/glass-set=(null)] [HOOK-postval:g/glass-set=(null)] [HOOK-preval:G/with-gas=(null)] [HOOK-postval:G/with-gas=(null)] [HOOK-prearg] [HOOK-preval:/(null)=darjeeling] [HOOK-postval:/(null)=darjeeling] English style: no|Chosen teapot: glass|Temperature: 95C|Verbosity: 1|Prayer: no|Water amount: 640|Gas: yes|First tea: darjeeling|Everything OK. Bye. +Out: [HOOK-postval:H/show-hooks=(null)] [HOOK-preval:t/temperature=95C] [HOOK-postval:t/temperature=95C] [HOOK-prearg] [HOOK-preval:w/water=640] [HOOK-postval:w/water=640] [HOOK-prearg] [HOOK-preval:g/glass-set=(null)] [HOOK-postval:g/glass-set=(null)] [HOOK-preval:G/with-gas=(null)] [HOOK-postval:G/with-gas=(null)] [HOOK-prearg] [HOOK-preval:/(null)=darjeeling] [HOOK-postval:/(null)=darjeeling] English style: no|Chosen teapot: glass|Temperature: 95C|Verbosity: 1|Prayer: no|Clean: yes|Water amount: 640|Gas: yes|First tea: darjeeling|Everything OK. Bye. -- 2.39.2