Commit 53eb6813 53eb68133eeede20c49445cd4ff58ad6e4becc07 by Sergey Poznyakoff

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.
1 parent fa7ac605
...@@ -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
......