Fix processing of abbreviated negated boolean options
It was noted that "mhn -nohead" did not suppress the output of headers as "mhn -noheaders" did. It turned out that the negation marker was overwritten while scanning options for possible matching alternatives. This patch fixes it. * libmailutils/opt/opt.c (find_long_option): Don't overwrite the negation attribute of the last found option. * libmailutils/tests/parseopt.c: New option --headers, to test the fix. * libmailutils/tests/parseopt28.at: New testcase. * libmailutils/tests/Makefile.am: Add new testcase. * libmailutils/tests/testsuite.at: Include new testcase. * libmailutils/tests/parseopt*.at: Trivial changes
Showing
39 changed files
with
103 additions
and
12 deletions
... | @@ -279,7 +279,7 @@ find_long_option (struct mu_parseopt *po, char const *optstr, | ... | @@ -279,7 +279,7 @@ find_long_option (struct mu_parseopt *po, char const *optstr, |
279 | size_t i; | 279 | size_t i; |
280 | size_t optlen; /* Length of the option in optstr */ | 280 | size_t optlen; /* Length of the option in optstr */ |
281 | int found = 0; /* 1 if the match was found, 2 if option is ambiguous */ | 281 | int found = 0; /* 1 if the match was found, 2 if option is ambiguous */ |
282 | enum neg_match neg; /* 1 if a boolean option is negated */ | 282 | int negated; /* 1 if a boolean option is negated */ |
283 | struct mu_option *ret_opt = NULL; | 283 | struct mu_option *ret_opt = NULL; |
284 | struct mu_option *used_opt; | 284 | struct mu_option *used_opt; |
285 | 285 | ||
... | @@ -290,7 +290,7 @@ find_long_option (struct mu_parseopt *po, char const *optstr, | ... | @@ -290,7 +290,7 @@ find_long_option (struct mu_parseopt *po, char const *optstr, |
290 | size_t j = po->po_longidx[i]; | 290 | size_t j = po->po_longidx[i]; |
291 | size_t len = strlen (po->po_optv[j]->opt_long); | 291 | size_t len = strlen (po->po_optv[j]->opt_long); |
292 | struct mu_option *opt = option_unalias (po, j); | 292 | struct mu_option *opt = option_unalias (po, j); |
293 | neg = neg_nomatch; | 293 | enum neg_match neg = neg_nomatch; |
294 | if ((optlen <= len | 294 | if ((optlen <= len |
295 | && memcmp (po->po_optv[j]->opt_long, optstr, optlen) == 0) | 295 | && memcmp (po->po_optv[j]->opt_long, optstr, optlen) == 0) |
296 | || (neg = negmatch (po, j, optstr, optlen))) | 296 | || (neg = negmatch (po, j, optstr, optlen))) |
... | @@ -301,6 +301,7 @@ find_long_option (struct mu_parseopt *po, char const *optstr, | ... | @@ -301,6 +301,7 @@ find_long_option (struct mu_parseopt *po, char const *optstr, |
301 | used_opt = po->po_optv[j]; | 301 | used_opt = po->po_optv[j]; |
302 | ret_opt = opt; | 302 | ret_opt = opt; |
303 | found++; | 303 | found++; |
304 | negated = neg != neg_nomatch; | ||
304 | if (optlen == len || neg == neg_match_exact) | 305 | if (optlen == len || neg == neg_match_exact) |
305 | i = po->po_longcnt - 1; /* exact match: break the loop */ | 306 | i = po->po_longcnt - 1; /* exact match: break the loop */ |
306 | break; | 307 | break; |
... | @@ -353,12 +354,7 @@ find_long_option (struct mu_parseopt *po, char const *optstr, | ... | @@ -353,12 +354,7 @@ find_long_option (struct mu_parseopt *po, char const *optstr, |
353 | ++optlen; | 354 | ++optlen; |
354 | *used_value = (char *)(optstr + optlen); | 355 | *used_value = (char *)(optstr + optlen); |
355 | if (ret_opt->opt_type == mu_c_bool) | 356 | if (ret_opt->opt_type == mu_c_bool) |
356 | { | 357 | *value = negated ? "0" : "1"; |
357 | if (neg) | ||
358 | *value = "0"; | ||
359 | else | ||
360 | *value = "1"; | ||
361 | } | ||
362 | else | 358 | else |
363 | *value = NULL; | 359 | *value = NULL; |
364 | return ret_opt; | 360 | return ret_opt; | ... | ... |
... | @@ -141,6 +141,7 @@ TESTSUITE_AT = \ | ... | @@ -141,6 +141,7 @@ TESTSUITE_AT = \ |
141 | parseopt25.at\ | 141 | parseopt25.at\ |
142 | parseopt26.at\ | 142 | parseopt26.at\ |
143 | parseopt27.at\ | 143 | parseopt27.at\ |
144 | parseopt28.at\ | ||
144 | parseopt_help00.at\ | 145 | parseopt_help00.at\ |
145 | parseopt_help01.at\ | 146 | parseopt_help01.at\ |
146 | parseopt_help02.at\ | 147 | parseopt_help02.at\ | ... | ... |
... | @@ -26,6 +26,7 @@ char *find_value; | ... | @@ -26,6 +26,7 @@ char *find_value; |
26 | int jobs = 0; | 26 | int jobs = 0; |
27 | int x_option; | 27 | int x_option; |
28 | int a_option; | 28 | int a_option; |
29 | int headers_option = 1; | ||
29 | int d_option; | 30 | int d_option; |
30 | int debug_level_value; | 31 | int debug_level_value; |
31 | char *debug_info_value; | 32 | char *debug_info_value; |
... | @@ -46,6 +47,9 @@ struct mu_option group_a[] = { | ... | @@ -46,6 +47,9 @@ struct mu_option group_a[] = { |
46 | "no arguments to this one", | 47 | "no arguments to this one", |
47 | mu_c_bool, &a_option }, | 48 | mu_c_bool, &a_option }, |
48 | { "debug-all", 0, NULL, MU_OPTION_ALIAS }, | 49 | { "debug-all", 0, NULL, MU_OPTION_ALIAS }, |
50 | { "headers", 0, NULL, MU_OPTION_DEFAULT, | ||
51 | "show headers", | ||
52 | mu_c_bool, &headers_option }, | ||
49 | MU_OPTION_END | 53 | MU_OPTION_END |
50 | }; | 54 | }; |
51 | 55 | ||
... | @@ -218,6 +222,7 @@ main (int argc, char *argv[]) | ... | @@ -218,6 +222,7 @@ main (int argc, char *argv[]) |
218 | printf ("opt_value=%s\n", S(opt_value)); | 222 | printf ("opt_value=%s\n", S(opt_value)); |
219 | printf ("x_option=%d\n", x_option); | 223 | printf ("x_option=%d\n", x_option); |
220 | printf ("a_option=%d\n", a_option); | 224 | printf ("a_option=%d\n", a_option); |
225 | printf ("headers_option=%d\n", headers_option); | ||
221 | printf ("find_value=%s\n", S(find_value)); | 226 | printf ("find_value=%s\n", S(find_value)); |
222 | printf ("d_option=%d\n", d_option); | 227 | printf ("d_option=%d\n", d_option); |
223 | printf ("jobs=%d\n", jobs); | 228 | printf ("jobs=%d\n", jobs); | ... | ... |
... | @@ -26,6 +26,7 @@ file_name=file | ... | @@ -26,6 +26,7 @@ file_name=file |
26 | opt_value=(null) | 26 | opt_value=(null) |
27 | x_option=1 | 27 | x_option=1 |
28 | a_option=0 | 28 | a_option=0 |
29 | headers_option=1 | ||
29 | find_value=(null) | 30 | find_value=(null) |
30 | d_option=0 | 31 | d_option=0 |
31 | jobs=0 | 32 | jobs=0 |
... | @@ -48,6 +49,7 @@ file_name=file | ... | @@ -48,6 +49,7 @@ file_name=file |
48 | opt_value=(null) | 49 | opt_value=(null) |
49 | x_option=1 | 50 | x_option=1 |
50 | a_option=0 | 51 | a_option=0 |
52 | headers_option=1 | ||
51 | find_value=(null) | 53 | find_value=(null) |
52 | d_option=0 | 54 | d_option=0 |
53 | jobs=0 | 55 | jobs=0 | ... | ... |
libmailutils/tests/parseopt28.at
0 → 100644
1 | # This file is part of GNU Mailutils. -*- Autotest -*- | ||
2 | # Copyright (C) 2017 Free Software Foundation, Inc. | ||
3 | # | ||
4 | # GNU Mailutils is free software; you can redistribute it and/or | ||
5 | # modify it under the terms of the GNU General Public License as | ||
6 | # published by the Free Software Foundation; either version 3, or (at | ||
7 | # your option) any later version. | ||
8 | # | ||
9 | # GNU Mailutils is distributed in the hope that it will be useful, but | ||
10 | # WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | # General Public License for more details. | ||
13 | # | ||
14 | # You should have received a copy of the GNU General Public License | ||
15 | # along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. | ||
16 | |||
17 | AT_SETUP([boolean negation]) | ||
18 | AT_KEYWORDS([parseopt parseopt_bool parseopt28]) | ||
19 | AT_CHECK([ | ||
20 | PARSEOPT_DEFAULT | ||
21 | MU_PARSEOPT_NEGATION=no- | ||
22 | export MU_PARSEOPT_NEGATION | ||
23 | echo "# full option" | ||
24 | parseopt --no-headers | ||
25 | echo "# abbreviated option" | ||
26 | parseopt --no-header | ||
27 | ], | ||
28 | [0], | ||
29 | [# full option | ||
30 | rc=0 | ||
31 | file_name=(null) | ||
32 | opt_value=initial | ||
33 | x_option=0 | ||
34 | a_option=0 | ||
35 | headers_option=0 | ||
36 | find_value=(null) | ||
37 | d_option=0 | ||
38 | jobs=0 | ||
39 | debug_level_value=0 | ||
40 | debug_info_value=(null) | ||
41 | argv: | ||
42 | # abbreviated option | ||
43 | rc=0 | ||
44 | file_name=(null) | ||
45 | opt_value=initial | ||
46 | x_option=0 | ||
47 | a_option=0 | ||
48 | headers_option=0 | ||
49 | find_value=(null) | ||
50 | d_option=0 | ||
51 | jobs=0 | ||
52 | debug_level_value=0 | ||
53 | debug_info_value=(null) | ||
54 | argv: | ||
55 | ]) | ||
56 | AT_CLEANUP |
... | @@ -26,6 +26,7 @@ parseopt --help | ... | @@ -26,6 +26,7 @@ parseopt --help |
26 | Group A | 26 | Group A |
27 | -a, --all, --debug-all no arguments to this one | 27 | -a, --all, --debug-all no arguments to this one |
28 | -f, --file=FILE set file name | 28 | -f, --file=FILE set file name |
29 | --headers show headers | ||
29 | -o, --optional[=FILE] optional argument | 30 | -o, --optional[=FILE] optional argument |
30 | -x short-only option | 31 | -x short-only option |
31 | 32 | ... | ... |
... | @@ -23,7 +23,7 @@ parseopt --usage | ... | @@ -23,7 +23,7 @@ parseopt --usage |
23 | [0], | 23 | [0], |
24 | [[Usage: parseopt [-advx?] [-f FILE] [-F VALUE] [-j N] [-o[FILE]] [--all] | 24 | [[Usage: parseopt [-advx?] [-f FILE] [-F VALUE] [-j N] [-o[FILE]] [--all] |
25 | [--debug] [--debug-all] [--debug-info=S] [--debug-level=NUM] | 25 | [--debug] [--debug-all] [--debug-info=S] [--debug-level=NUM] |
26 | [--file=FILE] [--find=VALUE] [--help] [--jobs=N] | 26 | [--file=FILE] [--find=VALUE] [--headers] [--help] [--jobs=N] |
27 | [--optional[=FILE]] [--usage] [--verbose] | 27 | [--optional[=FILE]] [--usage] [--verbose] |
28 | ]]) | 28 | ]]) |
29 | AT_CLEANUP | 29 | AT_CLEANUP | ... | ... |
... | @@ -26,6 +26,7 @@ MU_PARSEOPT_PROG_NAME=newname parseopt --help | ... | @@ -26,6 +26,7 @@ MU_PARSEOPT_PROG_NAME=newname parseopt --help |
26 | Group A | 26 | Group A |
27 | -a, --all, --debug-all no arguments to this one | 27 | -a, --all, --debug-all no arguments to this one |
28 | -f, --file=FILE set file name | 28 | -f, --file=FILE set file name |
29 | --headers show headers | ||
29 | -o, --optional[=FILE] optional argument | 30 | -o, --optional[=FILE] optional argument |
30 | -x short-only option | 31 | -x short-only option |
31 | 32 | ... | ... |
... | @@ -27,6 +27,7 @@ Tests option parsing | ... | @@ -27,6 +27,7 @@ Tests option parsing |
27 | Group A | 27 | Group A |
28 | -a, --all, --debug-all no arguments to this one | 28 | -a, --all, --debug-all no arguments to this one |
29 | -f, --file=FILE set file name | 29 | -f, --file=FILE set file name |
30 | --headers show headers | ||
30 | -o, --optional[=FILE] optional argument | 31 | -o, --optional[=FILE] optional argument |
31 | -x short-only option | 32 | -x short-only option |
32 | 33 | ... | ... |
... | @@ -26,6 +26,7 @@ MU_PARSEOPT_PROG_ARGS="SOME MORE ARGS" parseopt --help | ... | @@ -26,6 +26,7 @@ MU_PARSEOPT_PROG_ARGS="SOME MORE ARGS" parseopt --help |
26 | Group A | 26 | Group A |
27 | -a, --all, --debug-all no arguments to this one | 27 | -a, --all, --debug-all no arguments to this one |
28 | -f, --file=FILE set file name | 28 | -f, --file=FILE set file name |
29 | --headers show headers | ||
29 | -o, --optional[[=FILE]] optional argument | 30 | -o, --optional[[=FILE]] optional argument |
30 | -x short-only option | 31 | -x short-only option |
31 | 32 | ... | ... |
... | @@ -26,6 +26,7 @@ MU_PARSEOPT_BUG_ADDRESS='gray@gnu.org' parseopt --help | ... | @@ -26,6 +26,7 @@ MU_PARSEOPT_BUG_ADDRESS='gray@gnu.org' parseopt --help |
26 | Group A | 26 | Group A |
27 | -a, --all, --debug-all no arguments to this one | 27 | -a, --all, --debug-all no arguments to this one |
28 | -f, --file=FILE set file name | 28 | -f, --file=FILE set file name |
29 | --headers show headers | ||
29 | -o, --optional[[=FILE]] optional argument | 30 | -o, --optional[[=FILE]] optional argument |
30 | -x short-only option | 31 | -x short-only option |
31 | 32 | ... | ... |
... | @@ -26,6 +26,7 @@ MU_PARSEOPT_PACKAGE_NAME='GNU Mailutils' MU_PARSEOPT_PACKAGE_URL='http://mailuti | ... | @@ -26,6 +26,7 @@ MU_PARSEOPT_PACKAGE_NAME='GNU Mailutils' MU_PARSEOPT_PACKAGE_URL='http://mailuti |
26 | Group A | 26 | Group A |
27 | -a, --all, --debug-all no arguments to this one | 27 | -a, --all, --debug-all no arguments to this one |
28 | -f, --file=FILE set file name | 28 | -f, --file=FILE set file name |
29 | --headers show headers | ||
29 | -o, --optional[=FILE] optional argument | 30 | -o, --optional[=FILE] optional argument |
30 | -x short-only option | 31 | -x short-only option |
31 | 32 | ... | ... |
... | @@ -33,6 +33,7 @@ Tests option parsing | ... | @@ -33,6 +33,7 @@ Tests option parsing |
33 | Group A | 33 | Group A |
34 | -a, --all, --debug-all no arguments to this one | 34 | -a, --all, --debug-all no arguments to this one |
35 | -f, --file=FILE set file name | 35 | -f, --file=FILE set file name |
36 | --headers show headers | ||
36 | -o, --optional[=FILE] optional argument | 37 | -o, --optional[=FILE] optional argument |
37 | -x short-only option | 38 | -x short-only option |
38 | 39 | ... | ... |
... | @@ -27,6 +27,7 @@ ARGP_HELP_FMT=dup-args,no-dup-args-note,short-opt-col=1,opt-doc-col=32,header-co | ... | @@ -27,6 +27,7 @@ ARGP_HELP_FMT=dup-args,no-dup-args-note,short-opt-col=1,opt-doc-col=32,header-co |
27 | Group A | 27 | Group A |
28 | -a, --all, --debug-all no arguments to this one | 28 | -a, --all, --debug-all no arguments to this one |
29 | -f FILE, --file=FILE set file name | 29 | -f FILE, --file=FILE set file name |
30 | --headers show headers | ||
30 | -o[FILE], --optional[=FILE] optional argument | 31 | -o[FILE], --optional[=FILE] optional argument |
31 | -x short-only option | 32 | -x short-only option |
32 | 33 | ... | ... |
... | @@ -24,7 +24,7 @@ ARGP_HELP_FMT=rmargin=62,usage-indent=1\ | ... | @@ -24,7 +24,7 @@ ARGP_HELP_FMT=rmargin=62,usage-indent=1\ |
24 | [0], | 24 | [0], |
25 | [[Usage: parseopt [-advx?] [-f FILE] [-F VALUE] [-j N] | 25 | [[Usage: parseopt [-advx?] [-f FILE] [-F VALUE] [-j N] |
26 | [-o[FILE]] [--all] [--debug] [--debug-all] [--debug-info=S] | 26 | [-o[FILE]] [--all] [--debug] [--debug-all] [--debug-info=S] |
27 | [--debug-level=NUM] [--file=FILE] [--find=VALUE] [--help] | 27 | [--debug-level=NUM] [--file=FILE] [--find=VALUE] [--headers] |
28 | [--jobs=N] [--optional[=FILE]] [--usage] [--verbose] | 28 | [--help] [--jobs=N] [--optional[=FILE]] [--usage] [--verbose] |
29 | ]]) | 29 | ]]) |
30 | AT_CLEANUP | 30 | AT_CLEANUP | ... | ... |
... | @@ -23,7 +23,7 @@ MU_PARSEOPT_VERSION_HOOK=1 parseopt --usage | ... | @@ -23,7 +23,7 @@ MU_PARSEOPT_VERSION_HOOK=1 parseopt --usage |
23 | [0], | 23 | [0], |
24 | [[Usage: parseopt [-advVx?] [-f FILE] [-F VALUE] [-j N] [-o[FILE]] [--all] | 24 | [[Usage: parseopt [-advVx?] [-f FILE] [-F VALUE] [-j N] [-o[FILE]] [--all] |
25 | [--debug] [--debug-all] [--debug-info=S] [--debug-level=NUM] | 25 | [--debug] [--debug-all] [--debug-info=S] [--debug-level=NUM] |
26 | [--file=FILE] [--find=VALUE] [--help] [--jobs=N] | 26 | [--file=FILE] [--find=VALUE] [--headers] [--help] [--jobs=N] |
27 | [--optional[=FILE]] [--usage] [--verbose] [--version] | 27 | [--optional[=FILE]] [--usage] [--verbose] [--version] |
28 | ]]) | 28 | ]]) |
29 | AT_CLEANUP | 29 | AT_CLEANUP | ... | ... |
... | @@ -26,6 +26,7 @@ MU_PARSEOPT_VERSION_HOOK=1 parseopt --help | ... | @@ -26,6 +26,7 @@ MU_PARSEOPT_VERSION_HOOK=1 parseopt --help |
26 | Group A | 26 | Group A |
27 | -a, --all, --debug-all no arguments to this one | 27 | -a, --all, --debug-all no arguments to this one |
28 | -f, --file=FILE set file name | 28 | -f, --file=FILE set file name |
29 | --headers show headers | ||
29 | -o, --optional[=FILE] optional argument | 30 | -o, --optional[=FILE] optional argument |
30 | -x short-only option | 31 | -x short-only option |
31 | 32 | ... | ... |
... | @@ -28,6 +28,7 @@ MU_PARSEOPT_PROG_ARGS="SOME MORE ARGS|ALTERNATIVE ARGS|ANOTHER ARGS" parseopt -- | ... | @@ -28,6 +28,7 @@ MU_PARSEOPT_PROG_ARGS="SOME MORE ARGS|ALTERNATIVE ARGS|ANOTHER ARGS" parseopt -- |
28 | Group A | 28 | Group A |
29 | -a, --all, --debug-all no arguments to this one | 29 | -a, --all, --debug-all no arguments to this one |
30 | -f, --file=FILE set file name | 30 | -f, --file=FILE set file name |
31 | --headers show headers | ||
31 | -o, --optional[[=FILE]] optional argument | 32 | -o, --optional[[=FILE]] optional argument |
32 | -x short-only option | 33 | -x short-only option |
33 | 34 | ... | ... |
... | @@ -131,6 +131,7 @@ m4_include([parseopt24.at]) | ... | @@ -131,6 +131,7 @@ m4_include([parseopt24.at]) |
131 | m4_include([parseopt25.at]) | 131 | m4_include([parseopt25.at]) |
132 | m4_include([parseopt26.at]) | 132 | m4_include([parseopt26.at]) |
133 | m4_include([parseopt27.at]) | 133 | m4_include([parseopt27.at]) |
134 | m4_include([parseopt28.at]) | ||
134 | 135 | ||
135 | AT_BANNER([Command line help output]) | 136 | AT_BANNER([Command line help output]) |
136 | m4_include([parseopt_help00.at]) | 137 | m4_include([parseopt_help00.at]) | ... | ... |
-
Please register or sign in to post a comment