Support for single-dash long options (as in MH) and negation for boolean options.
* include/mailutils/opt.h (MU_PARSEOPT_SINGLE_DASH) (MU_PARSEOPT_NEGATION): New flags. (mu_parseopt) <po_negation, po_long_opt_start>: New fields. (mu_option_describe_options): Change signature. * libmailutils/opt/help.c (init_usage_vars): Initialize long_opt_col depending on the value of MU_PARSEOPT_SINGLE_DASH bit. (print_option): Handle single-dash long options and boolean options with negations. (option_summary): Likewise. (mu_option_describe_options): Take struct mu_parseopt * as its second parameter. * libmailutils/opt/opt.c (find_long_option): Handle boolean options with negations. Return also a pointer to the mu_option describing the originally used option (as opposed to the canonical one returned by the function). (parse): Handle single-dash long options. (parseopt_init): Initialize po_negation and po_long_opt_start. * libmailutils/tests/parseopt.c (parseopt_param): Handle MU_PARSEOPT_SINGLE_DASH and MU_PARSEOPT_NEGATION.
Showing
4 changed files
with
226 additions
and
120 deletions
... | @@ -103,13 +103,17 @@ struct mu_option_cache | ... | @@ -103,13 +103,17 @@ struct mu_option_cache |
103 | #define MU_PARSEOPT_DATA 0x00400000 | 103 | #define MU_PARSEOPT_DATA 0x00400000 |
104 | #define MU_PARSEOPT_VERSION_HOOK 0x00800000 | 104 | #define MU_PARSEOPT_VERSION_HOOK 0x00800000 |
105 | #define MU_PARSEOPT_PROG_DOC_HOOK 0x01000000 | 105 | #define MU_PARSEOPT_PROG_DOC_HOOK 0x01000000 |
106 | /* Long options start with single dash. Disables recognition of traditional | ||
107 | short options */ | ||
108 | #define MU_PARSEOPT_SINGLE_DASH 0x02000000 | ||
109 | /* Negation prefix is set */ | ||
110 | #define MU_PARSEOPT_NEGATION 0x04000000 | ||
106 | 111 | ||
107 | /* Reuse mu_parseopt struct initialized previously */ | 112 | /* Reuse mu_parseopt struct initialized previously */ |
108 | #define MU_PARSEOPT_REUSE 0x80000000 | 113 | #define MU_PARSEOPT_REUSE 0x80000000 |
109 | /* Mask for immutable flag bits */ | 114 | /* Mask for immutable flag bits */ |
110 | #define MU_PARSEOPT_IMMUTABLE_MASK 0xFFFFF000 | 115 | #define MU_PARSEOPT_IMMUTABLE_MASK 0xFFFFF000 |
111 | 116 | ||
112 | |||
113 | struct mu_parseopt | 117 | struct mu_parseopt |
114 | { | 118 | { |
115 | /* Input data: */ | 119 | /* Input data: */ |
... | @@ -119,6 +123,7 @@ struct mu_parseopt | ... | @@ -119,6 +123,7 @@ struct mu_parseopt |
119 | struct mu_option **po_optv; /* Array of ptrs to option structures */ | 123 | struct mu_option **po_optv; /* Array of ptrs to option structures */ |
120 | int po_flags; | 124 | int po_flags; |
121 | 125 | ||
126 | char *po_negation; /* Negation prefix for boolean options */ | ||
122 | void *po_data; /* Call-specific data */ | 127 | void *po_data; /* Call-specific data */ |
123 | 128 | ||
124 | int po_exit_error; /* Exit on error with this code */ | 129 | int po_exit_error; /* Exit on error with this code */ |
... | @@ -145,6 +150,9 @@ struct mu_parseopt | ... | @@ -145,6 +150,9 @@ struct mu_parseopt |
145 | /* Auxiliary data */ | 150 | /* Auxiliary data */ |
146 | char *po_cur; /* Points to the next character */ | 151 | char *po_cur; /* Points to the next character */ |
147 | int po_chr; /* Single-char option */ | 152 | int po_chr; /* Single-char option */ |
153 | |||
154 | char *po_long_opt_start; /* Character sequence that starts | ||
155 | long option */ | ||
148 | 156 | ||
149 | /* The following two keep the position of the first non-optional argument | 157 | /* The following two keep the position of the first non-optional argument |
150 | and the number of contiguous non-optional arguments after it. | 158 | and the number of contiguous non-optional arguments after it. |
... | @@ -161,6 +169,7 @@ struct mu_parseopt | ... | @@ -161,6 +169,7 @@ struct mu_parseopt |
161 | unsigned po_permuted:1; /* Whether the arguments were permuted */ | 169 | unsigned po_permuted:1; /* Whether the arguments were permuted */ |
162 | }; | 170 | }; |
163 | 171 | ||
172 | |||
164 | int mu_parseopt (struct mu_parseopt *p, | 173 | int mu_parseopt (struct mu_parseopt *p, |
165 | int argc, char **argv, struct mu_option **optv, | 174 | int argc, char **argv, struct mu_option **optv, |
166 | int flags); | 175 | int flags); |
... | @@ -171,8 +180,7 @@ void mu_parseopt_free (struct mu_parseopt *p); | ... | @@ -171,8 +180,7 @@ void mu_parseopt_free (struct mu_parseopt *p); |
171 | 180 | ||
172 | unsigned mu_parseopt_getcolumn (const char *name); | 181 | unsigned mu_parseopt_getcolumn (const char *name); |
173 | 182 | ||
174 | void mu_option_describe_options (mu_stream_t str, | 183 | void mu_option_describe_options (mu_stream_t str, struct mu_parseopt *p); |
175 | struct mu_option **optbuf, size_t optcnt); | ||
176 | void mu_program_help (struct mu_parseopt *p, mu_stream_t str); | 184 | void mu_program_help (struct mu_parseopt *p, mu_stream_t str); |
177 | void mu_program_usage (struct mu_parseopt *p, int optsummary, mu_stream_t str); | 185 | void mu_program_usage (struct mu_parseopt *p, int optsummary, mu_stream_t str); |
178 | void mu_program_version (struct mu_parseopt *po, mu_stream_t str); | 186 | void mu_program_version (struct mu_parseopt *po, mu_stream_t str); |
... | @@ -180,4 +188,6 @@ void mu_program_version (struct mu_parseopt *po, mu_stream_t str); | ... | @@ -180,4 +188,6 @@ void mu_program_version (struct mu_parseopt *po, mu_stream_t str); |
180 | void mu_option_set_value (struct mu_parseopt *po, struct mu_option *opt, | 188 | void mu_option_set_value (struct mu_parseopt *po, struct mu_option *opt, |
181 | char const *arg); | 189 | char const *arg); |
182 | 190 | ||
191 | int mu_option_possible_negation (struct mu_parseopt *po, struct mu_option *opt); | ||
192 | |||
183 | #endif | 193 | #endif | ... | ... |
... | @@ -30,7 +30,7 @@ | ... | @@ -30,7 +30,7 @@ |
30 | #include <mailutils/stream.h> | 30 | #include <mailutils/stream.h> |
31 | 31 | ||
32 | unsigned short_opt_col = 2; | 32 | unsigned short_opt_col = 2; |
33 | unsigned long_opt_col = 6; | 33 | unsigned long_opt_col; /* Initialized in init_usage_vars */ |
34 | /*FIXME: doc_opt_col? */ | 34 | /*FIXME: doc_opt_col? */ |
35 | unsigned header_col = 1; | 35 | unsigned header_col = 1; |
36 | unsigned opt_doc_col = 29; | 36 | unsigned opt_doc_col = 29; |
... | @@ -170,6 +170,11 @@ init_usage_vars (struct mu_parseopt *po) | ... | @@ -170,6 +170,11 @@ init_usage_vars (struct mu_parseopt *po) |
170 | struct mu_wordsplit ws; | 170 | struct mu_wordsplit ws; |
171 | size_t i; | 171 | size_t i; |
172 | 172 | ||
173 | if (po->po_flags & MU_PARSEOPT_SINGLE_DASH) | ||
174 | long_opt_col = 2; | ||
175 | else | ||
176 | long_opt_col = 6; | ||
177 | |||
173 | fmt = getenv ("ARGP_HELP_FMT"); | 178 | fmt = getenv ("ARGP_HELP_FMT"); |
174 | if (!fmt) | 179 | if (!fmt) |
175 | return; | 180 | return; |
... | @@ -223,11 +228,10 @@ print_opt_arg (mu_stream_t str, struct mu_option *opt, int delim) | ... | @@ -223,11 +228,10 @@ print_opt_arg (mu_stream_t str, struct mu_option *opt, int delim) |
223 | } | 228 | } |
224 | 229 | ||
225 | static size_t | 230 | static size_t |
226 | print_option (mu_stream_t str, | 231 | print_option (mu_stream_t str, struct mu_parseopt *po, size_t num, |
227 | struct mu_option **optbuf, size_t optcnt, size_t num, | ||
228 | int *argsused) | 232 | int *argsused) |
229 | { | 233 | { |
230 | struct mu_option *opt = optbuf[num]; | 234 | struct mu_option *opt = po->po_optv[num]; |
231 | size_t next, i; | 235 | size_t next, i; |
232 | int delim; | 236 | int delim; |
233 | int first_option = 1; | 237 | int first_option = 1; |
... | @@ -240,38 +244,47 @@ print_option (mu_stream_t str, | ... | @@ -240,38 +244,47 @@ print_option (mu_stream_t str, |
240 | if (opt->opt_doc[0]) | 244 | if (opt->opt_doc[0]) |
241 | { | 245 | { |
242 | set_margin (str, header_col); | 246 | set_margin (str, header_col); |
243 | mu_stream_printf (str, "%s", gettext (opt->opt_doc)); | 247 | mu_stream_printf (str, "%s\n", gettext (opt->opt_doc)); |
244 | } | 248 | } |
245 | return num + 1; | 249 | return num + 1; |
246 | } | 250 | } |
247 | 251 | ||
248 | /* count aliases */ | 252 | /* count aliases */ |
249 | for (next = num + 1; | 253 | for (next = num + 1; |
250 | next < optcnt && optbuf[next]->opt_flags & MU_OPTION_ALIAS; | 254 | next < po->po_optc && po->po_optv[next]->opt_flags & MU_OPTION_ALIAS; |
251 | next++); | 255 | next++); |
252 | 256 | ||
253 | if (opt->opt_flags & MU_OPTION_HIDDEN) | 257 | if (opt->opt_flags & MU_OPTION_HIDDEN) |
254 | return next; | 258 | return next; |
255 | 259 | ||
256 | set_margin (str, short_opt_col); | 260 | if (po->po_flags & MU_PARSEOPT_SINGLE_DASH) |
257 | for (i = num; i < next; i++) | 261 | { |
262 | if (!opt->opt_long) | ||
263 | return num + 1; /* Ignore erroneous option */ | ||
264 | set_margin (str, long_opt_col); | ||
265 | } | ||
266 | else | ||
258 | { | 267 | { |
259 | if (MU_OPTION_IS_VALID_SHORT_OPTION (optbuf[i])) | 268 | set_margin (str, short_opt_col); |
269 | for (i = num; i < next; i++) | ||
260 | { | 270 | { |
261 | if (first_option) | 271 | if (MU_OPTION_IS_VALID_SHORT_OPTION (po->po_optv[i])) |
262 | first_option = 0; | 272 | { |
263 | else | 273 | if (first_option) |
264 | mu_stream_printf (str, ", "); | 274 | first_option = 0; |
265 | mu_stream_printf (str, "-%c", optbuf[i]->opt_short); | 275 | else |
266 | delim = ' '; | 276 | mu_stream_printf (str, ", "); |
267 | if (opt->opt_arg && dup_args) | 277 | mu_stream_printf (str, "-%c", po->po_optv[i]->opt_short); |
268 | print_opt_arg (str, opt, delim); | 278 | delim = ' '; |
279 | if (opt->opt_arg && dup_args) | ||
280 | print_opt_arg (str, opt, delim); | ||
281 | } | ||
269 | } | 282 | } |
270 | } | 283 | } |
271 | 284 | ||
272 | for (i = num; i < next; i++) | 285 | for (i = num; i < next; i++) |
273 | { | 286 | { |
274 | if (MU_OPTION_IS_VALID_LONG_OPTION (optbuf[i])) | 287 | if (MU_OPTION_IS_VALID_LONG_OPTION (po->po_optv[i])) |
275 | { | 288 | { |
276 | if (first_option) | 289 | if (first_option) |
277 | first_option = 0; | 290 | first_option = 0; |
... | @@ -287,8 +300,12 @@ print_option (mu_stream_t str, | ... | @@ -287,8 +300,12 @@ print_option (mu_stream_t str, |
287 | first_long_option = 0; | 300 | first_long_option = 0; |
288 | } | 301 | } |
289 | 302 | ||
290 | mu_stream_printf (str, "--%s", optbuf[i]->opt_long); | 303 | mu_stream_printf (str, "%s", po->po_long_opt_start); |
291 | delim = '='; | 304 | if (mu_option_possible_negation (po, po->po_optv[i])) |
305 | mu_stream_printf (str, "[%s]", po->po_negation); | ||
306 | mu_stream_printf (str, "%s", po->po_optv[i]->opt_long); | ||
307 | delim = ((po->po_flags & MU_PARSEOPT_SINGLE_DASH) | ||
308 | && !(opt->opt_flags & MU_OPTION_ARG_OPTIONAL)) ? ' ' : '='; | ||
292 | if (opt->opt_arg && dup_args) | 309 | if (opt->opt_arg && dup_args) |
293 | print_opt_arg (str, opt, delim); | 310 | print_opt_arg (str, opt, delim); |
294 | } | 311 | } |
... | @@ -308,14 +325,13 @@ print_option (mu_stream_t str, | ... | @@ -308,14 +325,13 @@ print_option (mu_stream_t str, |
308 | } | 325 | } |
309 | 326 | ||
310 | void | 327 | void |
311 | mu_option_describe_options (mu_stream_t str, | 328 | mu_option_describe_options (mu_stream_t str, struct mu_parseopt *po) |
312 | struct mu_option **optbuf, size_t optcnt) | ||
313 | { | 329 | { |
314 | unsigned i; | 330 | unsigned i; |
315 | int argsused = 0; | 331 | int argsused = 0; |
316 | 332 | ||
317 | for (i = 0; i < optcnt; ) | 333 | for (i = 0; i < po->po_optc; ) |
318 | i = print_option (str, optbuf, optcnt, i, &argsused); | 334 | i = print_option (str, po, i, &argsused); |
319 | mu_stream_printf (str, "\n"); | 335 | mu_stream_printf (str, "\n"); |
320 | 336 | ||
321 | if (argsused && dup_args_note) | 337 | if (argsused && dup_args_note) |
... | @@ -334,7 +350,7 @@ mu_program_help (struct mu_parseopt *po, mu_stream_t outstr) | ... | @@ -334,7 +350,7 @@ mu_program_help (struct mu_parseopt *po, mu_stream_t outstr) |
334 | { | 350 | { |
335 | mu_stream_t str; | 351 | mu_stream_t str; |
336 | int rc; | 352 | int rc; |
337 | 353 | ||
338 | init_usage_vars (po); | 354 | init_usage_vars (po); |
339 | 355 | ||
340 | rc = mu_wordwrap_stream_create (&str, outstr, 0, rmargin); | 356 | rc = mu_wordwrap_stream_create (&str, outstr, 0, rmargin); |
... | @@ -358,7 +374,7 @@ mu_program_help (struct mu_parseopt *po, mu_stream_t outstr) | ... | @@ -358,7 +374,7 @@ mu_program_help (struct mu_parseopt *po, mu_stream_t outstr) |
358 | mu_stream_printf (str, "\n"); | 374 | mu_stream_printf (str, "\n"); |
359 | } | 375 | } |
360 | 376 | ||
361 | mu_option_describe_options (str, po->po_optv, po->po_optc); | 377 | mu_option_describe_options (str, po); |
362 | 378 | ||
363 | if (po->po_help_hook) | 379 | if (po->po_help_hook) |
364 | { | 380 | { |
... | @@ -432,41 +448,44 @@ option_summary (struct mu_parseopt *po, mu_stream_t str) | ... | @@ -432,41 +448,44 @@ option_summary (struct mu_parseopt *po, mu_stream_t str) |
432 | 448 | ||
433 | idxbuf = mu_calloc (optcnt, sizeof (idxbuf[0])); | 449 | idxbuf = mu_calloc (optcnt, sizeof (idxbuf[0])); |
434 | 450 | ||
435 | /* Print a list of short options without arguments. */ | 451 | if (!(po->po_flags & MU_PARSEOPT_SINGLE_DASH)) |
436 | for (i = nidx = 0; i < optcnt; i++) | ||
437 | if (MU_OPTION_IS_VALID_SHORT_OPTION (optbuf[i]) && !optbuf[i]->opt_arg) | ||
438 | idxbuf[nidx++] = i; | ||
439 | |||
440 | if (nidx) | ||
441 | { | 452 | { |
442 | qsort (idxbuf, nidx, sizeof (idxbuf[0]), cmpidx_short); | 453 | /* Print a list of short options without arguments. */ |
443 | mu_stream_printf (str, "[-"); | 454 | for (i = nidx = 0; i < optcnt; i++) |
444 | for (i = 0; i < nidx; i++) | 455 | if (MU_OPTION_IS_VALID_SHORT_OPTION (optbuf[i]) && !optbuf[i]->opt_arg) |
456 | idxbuf[nidx++] = i; | ||
457 | |||
458 | if (nidx) | ||
445 | { | 459 | { |
446 | mu_stream_printf (str, "%c", optbuf[idxbuf[i]]->opt_short); | 460 | qsort (idxbuf, nidx, sizeof (idxbuf[0]), cmpidx_short); |
461 | mu_stream_printf (str, "[-"); | ||
462 | for (i = 0; i < nidx; i++) | ||
463 | { | ||
464 | mu_stream_printf (str, "%c", optbuf[idxbuf[i]]->opt_short); | ||
465 | } | ||
466 | mu_stream_printf (str, "%c", ']'); | ||
447 | } | 467 | } |
448 | mu_stream_printf (str, "%c", ']'); | ||
449 | } | ||
450 | 468 | ||
451 | /* Print a list of short options with arguments. */ | 469 | /* Print a list of short options with arguments. */ |
452 | for (i = nidx = 0; i < optcnt; i++) | 470 | for (i = nidx = 0; i < optcnt; i++) |
453 | { | 471 | { |
454 | if (MU_OPTION_IS_VALID_SHORT_OPTION (optbuf[i]) && optbuf[i]->opt_arg) | 472 | if (MU_OPTION_IS_VALID_SHORT_OPTION (optbuf[i]) && optbuf[i]->opt_arg) |
455 | idxbuf[nidx++] = i; | 473 | idxbuf[nidx++] = i; |
456 | } | 474 | } |
457 | 475 | ||
458 | if (nidx) | 476 | if (nidx) |
459 | { | ||
460 | qsort (idxbuf, nidx, sizeof (idxbuf[0]), cmpidx_short); | ||
461 | |||
462 | for (i = 0; i < nidx; i++) | ||
463 | { | 477 | { |
464 | struct mu_option *opt = optbuf[idxbuf[i]]; | 478 | qsort (idxbuf, nidx, sizeof (idxbuf[0]), cmpidx_short); |
465 | const char *arg = gettext (opt->opt_arg); | 479 | |
466 | if (opt->opt_flags & MU_OPTION_ARG_OPTIONAL) | 480 | for (i = 0; i < nidx; i++) |
467 | mu_stream_printf (str, " [-%c[%s]]", opt->opt_short, arg); | 481 | { |
468 | else | 482 | struct mu_option *opt = optbuf[idxbuf[i]]; |
469 | mu_stream_printf (str, " [-%c %s]", opt->opt_short, arg); | 483 | const char *arg = gettext (opt->opt_arg); |
484 | if (opt->opt_flags & MU_OPTION_ARG_OPTIONAL) | ||
485 | mu_stream_printf (str, " [-%c[%s]]", opt->opt_short, arg); | ||
486 | else | ||
487 | mu_stream_printf (str, " [-%c %s]", opt->opt_short, arg); | ||
488 | } | ||
470 | } | 489 | } |
471 | } | 490 | } |
472 | 491 | ||
... | @@ -486,11 +505,17 @@ option_summary (struct mu_parseopt *po, mu_stream_t str) | ... | @@ -486,11 +505,17 @@ option_summary (struct mu_parseopt *po, mu_stream_t str) |
486 | struct mu_option *opt = optbuf[idxbuf[i]]; | 505 | struct mu_option *opt = optbuf[idxbuf[i]]; |
487 | const char *arg = opt->opt_arg ? gettext (opt->opt_arg) : NULL; | 506 | const char *arg = opt->opt_arg ? gettext (opt->opt_arg) : NULL; |
488 | 507 | ||
489 | mu_stream_printf (str, " [--%s", opt->opt_long); | 508 | mu_stream_printf (str, " [%s", po->po_long_opt_start); |
509 | if (mu_option_possible_negation (po, opt)) | ||
510 | mu_stream_printf (str, "[%s]", po->po_negation); | ||
511 | mu_stream_printf (str, "%s", opt->opt_long); | ||
512 | |||
490 | if (opt->opt_arg) | 513 | if (opt->opt_arg) |
491 | { | 514 | { |
492 | if (opt->opt_flags & MU_OPTION_ARG_OPTIONAL) | 515 | if (opt->opt_flags & MU_OPTION_ARG_OPTIONAL) |
493 | mu_stream_printf (str, "[=%s]", arg); | 516 | mu_stream_printf (str, "[=%s]", arg); |
517 | else if (po->po_flags & MU_PARSEOPT_SINGLE_DASH) | ||
518 | mu_stream_printf (str, " %s", arg); | ||
494 | else | 519 | else |
495 | mu_stream_printf (str, "=%s", arg); | 520 | mu_stream_printf (str, "=%s", arg); |
496 | } | 521 | } | ... | ... |
... | @@ -193,58 +193,94 @@ find_short_option (struct mu_parseopt *po, int chr) | ... | @@ -193,58 +193,94 @@ find_short_option (struct mu_parseopt *po, int chr) |
193 | it in *ARGPTR. */ | 193 | it in *ARGPTR. */ |
194 | struct mu_option * | 194 | struct mu_option * |
195 | find_long_option (struct mu_parseopt *po, char const *optstr, | 195 | find_long_option (struct mu_parseopt *po, char const *optstr, |
196 | char **argptr) | 196 | struct mu_option **used_opt_ptr, |
197 | char **used_value, | ||
198 | char **value) | ||
197 | { | 199 | { |
198 | size_t i; | 200 | size_t i; |
199 | size_t optlen; | 201 | size_t optlen; /* Length of the option in optstr */ |
200 | size_t ind; | 202 | int found = 0; /* 1 if the match was found, 2 if option is ambiguous */ |
201 | int found = 0; | 203 | int neglen; /* Length of the negation prefix, if any */ |
204 | int neg = 0; /* 1 if a boolean option is negated */ | ||
205 | struct mu_option *ret_opt = NULL; | ||
206 | struct mu_option *used_opt; | ||
202 | 207 | ||
203 | optlen = strcspn (optstr, "="); | 208 | optlen = strcspn (optstr, "="); |
209 | if (po->po_negation) | ||
210 | neglen = strlen (po->po_negation); | ||
204 | 211 | ||
205 | for (i = 0; i < po->po_optc; i++) | 212 | for (i = 0; i < po->po_optc; i++) |
206 | { | 213 | { |
207 | if (MU_OPTION_IS_VALID_LONG_OPTION (po->po_optv[i]) | 214 | if (MU_OPTION_IS_VALID_LONG_OPTION (po->po_optv[i])) |
208 | && optlen <= strlen (po->po_optv[i]->opt_long) | ||
209 | && memcmp (po->po_optv[i]->opt_long, optstr, optlen) == 0) | ||
210 | { | 215 | { |
211 | switch (found) | 216 | size_t len = strlen (po->po_optv[i]->opt_long); |
217 | struct mu_option *opt = option_unalias (po, i); | ||
218 | |||
219 | if ((optlen <= len | ||
220 | && memcmp (po->po_optv[i]->opt_long, optstr, optlen) == 0) | ||
221 | || (neg = (mu_option_possible_negation (po, opt) | ||
222 | && optlen <= neglen + len | ||
223 | && memcmp (optstr, po->po_negation, neglen) == 0 | ||
224 | && memcmp (optstr + neglen, po->po_optv[i]->opt_long, | ||
225 | optlen - neglen) == 0))) | ||
212 | { | 226 | { |
213 | case 0: | 227 | switch (found) |
214 | ind = i; | 228 | { |
215 | found++; | 229 | case 0: |
216 | if (optlen == strlen (po->po_optv[i]->opt_long)) | 230 | used_opt = po->po_optv[i]; |
217 | i = po->po_optc - 1; /* exact match: break the loop */ | 231 | ret_opt = opt; |
218 | break; | 232 | found++; |
219 | 233 | if (optlen == len || (neg && optlen == neglen + len)) | |
220 | case 1: | 234 | i = po->po_optc - 1; /* exact match: break the loop */ |
221 | if (option_unalias (po, i) == option_unalias (po, ind)) | 235 | break; |
222 | continue; | 236 | |
223 | if (po->po_flags & MU_PARSEOPT_IGNORE_ERRORS) | 237 | case 1: |
224 | return NULL; | 238 | if (opt == ret_opt) |
225 | mu_parseopt_error (po, | 239 | continue; |
226 | _("option '--%*.*s' is ambiguous; possibilities:"), | 240 | if (po->po_flags & MU_PARSEOPT_IGNORE_ERRORS) |
227 | optlen, optlen, optstr); | 241 | return NULL; |
228 | fprintf (stderr, "--%s\n", po->po_optv[ind]->opt_long); | 242 | mu_parseopt_error (po, |
229 | found++; | 243 | _("option '%s%*.*s' is ambiguous; possibilities:"), |
230 | 244 | po->po_long_opt_start, | |
231 | case 2: | 245 | optlen, optlen, optstr); |
232 | fprintf (stderr, "--%s\n", po->po_optv[i]->opt_long); | 246 | fprintf (stderr, "%s%s%s\n", |
247 | po->po_long_opt_start, | ||
248 | neg ? po->po_negation : "", | ||
249 | used_opt->opt_long); | ||
250 | found++; | ||
251 | |||
252 | case 2: | ||
253 | fprintf (stderr, "%s%s%s\n", | ||
254 | po->po_long_opt_start, | ||
255 | neg ? po->po_negation : "", | ||
256 | po->po_optv[i]->opt_long); | ||
257 | } | ||
233 | } | 258 | } |
234 | } | 259 | } |
235 | } | 260 | } |
236 | 261 | ||
237 | switch (found) | 262 | switch (found) |
238 | { | 263 | { |
239 | case 0: | 264 | case 0: |
240 | mu_parseopt_error (po, _("unrecognized option '--%s'"), optstr); | 265 | mu_parseopt_error (po, _("unrecognized option '%s%s'"), |
266 | po->po_long_opt_start, optstr); | ||
241 | break; | 267 | break; |
242 | 268 | ||
243 | case 1: | 269 | case 1: |
270 | *used_opt_ptr = used_opt; | ||
244 | if (optstr[optlen]) | 271 | if (optstr[optlen]) |
245 | ++optlen; | 272 | ++optlen; |
246 | *argptr = (char *)(optstr + optlen); | 273 | *used_value = (char *)(optstr + optlen); |
247 | return option_unalias (po, ind); | 274 | if (ret_opt->opt_type == mu_c_bool) |
275 | { | ||
276 | if (neg) | ||
277 | *value = "0"; | ||
278 | else | ||
279 | *value = "1"; | ||
280 | } | ||
281 | else | ||
282 | *value = NULL; | ||
283 | return ret_opt; | ||
248 | 284 | ||
249 | case 2: | 285 | case 2: |
250 | break; | 286 | break; |
... | @@ -313,7 +349,36 @@ next_opt (struct mu_parseopt *po) | ... | @@ -313,7 +349,36 @@ next_opt (struct mu_parseopt *po) |
313 | if (!po->po_cur) | 349 | if (!po->po_cur) |
314 | return 1; | 350 | return 1; |
315 | if (po->po_cur[0] == '-' && po->po_cur[1]) | 351 | if (po->po_cur[0] == '-' && po->po_cur[1]) |
316 | break; | 352 | { |
353 | if (*++po->po_cur == '-') | ||
354 | { | ||
355 | if (*++po->po_cur == 0) | ||
356 | { | ||
357 | /* End of options */ | ||
358 | permute (po); | ||
359 | ++po->po_ind; | ||
360 | return 1; | ||
361 | } | ||
362 | |||
363 | if (po->po_flags & MU_PARSEOPT_SINGLE_DASH) | ||
364 | /* a non-optional argument */; | ||
365 | else | ||
366 | { | ||
367 | /* It's a long option */ | ||
368 | po->po_chr = 0; | ||
369 | return 0; | ||
370 | } | ||
371 | } | ||
372 | else if (po->po_flags & MU_PARSEOPT_SINGLE_DASH) | ||
373 | { | ||
374 | /* Assume single-dash long option */ | ||
375 | po->po_chr = 0; | ||
376 | return 0; | ||
377 | } | ||
378 | else | ||
379 | break; | ||
380 | } | ||
381 | |||
317 | if (!(po->po_flags & MU_PARSEOPT_IN_ORDER)) | 382 | if (!(po->po_flags & MU_PARSEOPT_IN_ORDER)) |
318 | { | 383 | { |
319 | if (!po->po_permuted && po->po_arg_count == 0) | 384 | if (!po->po_permuted && po->po_arg_count == 0) |
... | @@ -324,21 +389,6 @@ next_opt (struct mu_parseopt *po) | ... | @@ -324,21 +389,6 @@ next_opt (struct mu_parseopt *po) |
324 | else | 389 | else |
325 | return 1; | 390 | return 1; |
326 | } | 391 | } |
327 | |||
328 | if (*++po->po_cur == '-') | ||
329 | { | ||
330 | if (*++po->po_cur == 0) | ||
331 | { | ||
332 | /* End of options */ | ||
333 | permute (po); | ||
334 | ++po->po_ind; | ||
335 | return 1; | ||
336 | } | ||
337 | |||
338 | /* It's a long option */ | ||
339 | po->po_chr = 0; | ||
340 | return 0; | ||
341 | } | ||
342 | } | 392 | } |
343 | 393 | ||
344 | po->po_chr = *po->po_cur++; | 394 | po->po_chr = *po->po_cur++; |
... | @@ -386,18 +436,18 @@ parse (struct mu_parseopt *po) | ... | @@ -386,18 +436,18 @@ parse (struct mu_parseopt *po) |
386 | 436 | ||
387 | while (next_opt (po) == 0) | 437 | while (next_opt (po) == 0) |
388 | { | 438 | { |
389 | struct mu_option *opt; | 439 | struct mu_option *opt, *uopt; |
390 | char *long_opt; | 440 | char *value; |
391 | 441 | ||
392 | if (po->po_chr) | 442 | if (po->po_chr) |
393 | { | 443 | { |
394 | opt = find_short_option (po, po->po_chr); | 444 | opt = find_short_option (po, po->po_chr); |
395 | long_opt = NULL; | 445 | uopt = NULL; |
446 | value = NULL; | ||
396 | } | 447 | } |
397 | else | 448 | else |
398 | { | 449 | { |
399 | long_opt = po->po_cur; | 450 | opt = find_long_option (po, po->po_cur, &uopt, &po->po_cur, &value); |
400 | opt = find_long_option (po, long_opt, &po->po_cur); | ||
401 | } | 451 | } |
402 | 452 | ||
403 | if (opt) | 453 | if (opt) |
... | @@ -417,14 +467,14 @@ parse (struct mu_parseopt *po) | ... | @@ -417,14 +467,14 @@ parse (struct mu_parseopt *po) |
417 | arg = po->po_argv[po->po_ind++]; | 467 | arg = po->po_argv[po->po_ind++]; |
418 | else | 468 | else |
419 | { | 469 | { |
420 | if (long_opt) | 470 | if (uopt) |
421 | mu_parseopt_error (po, | 471 | mu_parseopt_error (po, |
422 | _("option '--%s' requires an argument"), | 472 | _("option '%s%s' requires an argument"), |
423 | long_opt); | 473 | po->po_long_opt_start, uopt->opt_long); |
424 | else | 474 | else |
425 | mu_parseopt_error (po, | 475 | mu_parseopt_error (po, |
426 | _("option '-%c' requires an argument"), | 476 | _("option '-%c' requires an argument"), |
427 | po->po_chr); | 477 | po->po_chr); |
428 | po->po_opterr = po->po_ind; | 478 | po->po_opterr = po->po_ind; |
429 | if (po->po_flags & MU_PARSEOPT_NO_ERREXIT) | 479 | if (po->po_flags & MU_PARSEOPT_NO_ERREXIT) |
430 | { | 480 | { |
... | @@ -437,13 +487,14 @@ parse (struct mu_parseopt *po) | ... | @@ -437,13 +487,14 @@ parse (struct mu_parseopt *po) |
437 | } | 487 | } |
438 | else | 488 | else |
439 | { | 489 | { |
440 | if (long_opt | 490 | if (uopt |
441 | && po->po_cur[0] | 491 | && po->po_cur[0] |
442 | && !(po->po_flags & MU_OPTION_ARG_OPTIONAL)) | 492 | && !(po->po_flags & MU_OPTION_ARG_OPTIONAL)) |
443 | { | 493 | { |
444 | mu_parseopt_error (po, | 494 | mu_parseopt_error (po, |
445 | _("option '--%s' doesn't allow an argument"), | 495 | _("option '%s%s' doesn't allow an argument"), |
446 | long_opt); | 496 | po->po_long_opt_start, |
497 | uopt->opt_long); | ||
447 | po->po_opterr = po->po_ind; | 498 | po->po_opterr = po->po_ind; |
448 | if (po->po_flags & MU_PARSEOPT_NO_ERREXIT) | 499 | if (po->po_flags & MU_PARSEOPT_NO_ERREXIT) |
449 | { | 500 | { |
... | @@ -455,6 +506,9 @@ parse (struct mu_parseopt *po) | ... | @@ -455,6 +506,9 @@ parse (struct mu_parseopt *po) |
455 | } | 506 | } |
456 | arg = NULL; | 507 | arg = NULL; |
457 | } | 508 | } |
509 | |||
510 | if (!arg && value) | ||
511 | arg = value; | ||
458 | 512 | ||
459 | add_option_cache (po, opt, arg); | 513 | add_option_cache (po, opt, arg); |
460 | } | 514 | } |
... | @@ -515,6 +569,13 @@ parseopt_init (struct mu_parseopt *po, struct mu_option **options, | ... | @@ -515,6 +569,13 @@ parseopt_init (struct mu_parseopt *po, struct mu_option **options, |
515 | po->po_version_hook = NULL; | 569 | po->po_version_hook = NULL; |
516 | if (!(flags & MU_PARSEOPT_PROG_DOC_HOOK)) | 570 | if (!(flags & MU_PARSEOPT_PROG_DOC_HOOK)) |
517 | po->po_prog_doc_hook = NULL; | 571 | po->po_prog_doc_hook = NULL; |
572 | if (!(flags & MU_PARSEOPT_NEGATION)) | ||
573 | po->po_negation = NULL; | ||
574 | |||
575 | if (flags & MU_PARSEOPT_SINGLE_DASH) | ||
576 | po->po_long_opt_start = "-"; | ||
577 | else | ||
578 | po->po_long_opt_start = "--"; | ||
518 | 579 | ||
519 | /* Count the options */ | 580 | /* Count the options */ |
520 | po->po_optc = 0; | 581 | po->po_optc = 0; |
... | @@ -686,3 +747,9 @@ mu_option_set_value (struct mu_parseopt *po, struct mu_option *opt, | ... | @@ -686,3 +747,9 @@ mu_option_set_value (struct mu_parseopt *po, struct mu_option *opt, |
686 | } | 747 | } |
687 | } | 748 | } |
688 | } | 749 | } |
750 | |||
751 | int | ||
752 | mu_option_possible_negation (struct mu_parseopt *po, struct mu_option *opt) | ||
753 | { | ||
754 | return po->po_negation && opt->opt_type == mu_c_bool && !opt->opt_arg; | ||
755 | } | ... | ... |
... | @@ -141,6 +141,10 @@ static struct parseopt_param parseopt_param[] = { | ... | @@ -141,6 +141,10 @@ static struct parseopt_param parseopt_param[] = { |
141 | { "MU_PARSEOPT_EXIT_ERROR", MU_PARSEOPT_EXIT_ERROR, | 141 | { "MU_PARSEOPT_EXIT_ERROR", MU_PARSEOPT_EXIT_ERROR, |
142 | mu_c_int, mu_offsetof(struct mu_parseopt, po_exit_error) }, | 142 | mu_c_int, mu_offsetof(struct mu_parseopt, po_exit_error) }, |
143 | { "MU_PARSEOPT_VERSION_HOOK", MU_PARSEOPT_VERSION_HOOK, mu_c_void }, | 143 | { "MU_PARSEOPT_VERSION_HOOK", MU_PARSEOPT_VERSION_HOOK, mu_c_void }, |
144 | { "MU_PARSEOPT_SINGLE_DASH", MU_PARSEOPT_SINGLE_DASH, mu_c_void }, | ||
145 | { "MU_PARSEOPT_NEGATION", MU_PARSEOPT_NEGATION, | ||
146 | mu_c_string, mu_offsetof(struct mu_parseopt, po_negation) }, | ||
147 | |||
144 | { NULL } | 148 | { NULL } |
145 | }; | 149 | }; |
146 | 150 | ... | ... |
-
Please register or sign in to post a comment