@@ -350,98 +350,107 @@ static int is_alias(struct parse_opt_ctx_t *ctx,
350
350
return 0 ;
351
351
}
352
352
353
+ struct parsed_option {
354
+ const struct option * option ;
355
+ enum opt_parsed flags ;
356
+ };
357
+
358
+ static void register_abbrev (struct parse_opt_ctx_t * p ,
359
+ const struct option * option , enum opt_parsed flags ,
360
+ struct parsed_option * abbrev ,
361
+ struct parsed_option * ambiguous )
362
+ {
363
+ if (p -> flags & PARSE_OPT_KEEP_UNKNOWN_OPT )
364
+ return ;
365
+ if (abbrev -> option &&
366
+ !(abbrev -> flags == flags && is_alias (p , abbrev -> option , option ))) {
367
+ /*
368
+ * If this is abbreviated, it is
369
+ * ambiguous. So when there is no
370
+ * exact match later, we need to
371
+ * error out.
372
+ */
373
+ ambiguous -> option = abbrev -> option ;
374
+ ambiguous -> flags = abbrev -> flags ;
375
+ }
376
+ abbrev -> option = option ;
377
+ abbrev -> flags = flags ;
378
+ }
379
+
353
380
static enum parse_opt_result parse_long_opt (
354
381
struct parse_opt_ctx_t * p , const char * arg ,
355
382
const struct option * options )
356
383
{
357
384
const char * arg_end = strchrnul (arg , '=' );
358
- const struct option * abbrev_option = NULL , * ambiguous_option = NULL ;
359
- enum opt_parsed abbrev_flags = OPT_LONG , ambiguous_flags = OPT_LONG ;
360
- int allow_abbrev = !(p -> flags & PARSE_OPT_KEEP_UNKNOWN_OPT );
385
+ const char * arg_start = arg ;
386
+ enum opt_parsed flags = OPT_LONG ;
387
+ int arg_starts_with_no_no = 0 ;
388
+ struct parsed_option abbrev = { .option = NULL , .flags = OPT_LONG };
389
+ struct parsed_option ambiguous = { .option = NULL , .flags = OPT_LONG };
390
+
391
+ if (skip_prefix (arg_start , "no-" , & arg_start )) {
392
+ if (skip_prefix (arg_start , "no-" , & arg_start ))
393
+ arg_starts_with_no_no = 1 ;
394
+ else
395
+ flags |= OPT_UNSET ;
396
+ }
361
397
362
398
for (; options -> type != OPTION_END ; options ++ ) {
363
399
const char * rest , * long_name = options -> long_name ;
364
- enum opt_parsed flags = OPT_LONG , opt_flags = OPT_LONG ;
400
+ enum opt_parsed opt_flags = OPT_LONG ;
401
+ int allow_unset = !(options -> flags & PARSE_OPT_NONEG );
365
402
366
403
if (options -> type == OPTION_SUBCOMMAND )
367
404
continue ;
368
405
if (!long_name )
369
406
continue ;
370
407
371
- if (!starts_with (arg , "no-" ) &&
372
- !(options -> flags & PARSE_OPT_NONEG ) &&
373
- skip_prefix (long_name , "no-" , & long_name ))
408
+ if (skip_prefix (long_name , "no-" , & long_name ))
374
409
opt_flags |= OPT_UNSET ;
410
+ else if (arg_starts_with_no_no )
411
+ continue ;
375
412
376
- if (!skip_prefix (arg , long_name , & rest ))
377
- rest = NULL ;
378
- if (!rest ) {
379
- /* abbreviated? */
380
- if (allow_abbrev &&
381
- !strncmp (long_name , arg , arg_end - arg )) {
382
- is_abbreviated :
383
- if (abbrev_option &&
384
- !is_alias (p , abbrev_option , options )) {
385
- /*
386
- * If this is abbreviated, it is
387
- * ambiguous. So when there is no
388
- * exact match later, we need to
389
- * error out.
390
- */
391
- ambiguous_option = abbrev_option ;
392
- ambiguous_flags = abbrev_flags ;
393
- }
394
- if (!(flags & OPT_UNSET ) && * arg_end )
395
- p -> opt = arg_end + 1 ;
396
- abbrev_option = options ;
397
- abbrev_flags = flags ^ opt_flags ;
398
- continue ;
399
- }
400
- /* negation allowed? */
401
- if (options -> flags & PARSE_OPT_NONEG )
402
- continue ;
403
- /* negated and abbreviated very much? */
404
- if (allow_abbrev && starts_with ("no-" , arg )) {
405
- flags |= OPT_UNSET ;
406
- goto is_abbreviated ;
407
- }
408
- /* negated? */
409
- if (!starts_with (arg , "no-" ))
410
- continue ;
411
- flags |= OPT_UNSET ;
412
- if (!skip_prefix (arg + 3 , long_name , & rest )) {
413
- /* abbreviated and negated? */
414
- if (allow_abbrev &&
415
- starts_with (long_name , arg + 3 ))
416
- goto is_abbreviated ;
417
- else
418
- continue ;
419
- }
420
- }
421
- if (* rest ) {
422
- if (* rest != '=' )
413
+ if (((flags ^ opt_flags ) & OPT_UNSET ) && !allow_unset )
414
+ continue ;
415
+
416
+ if (skip_prefix (arg_start , long_name , & rest )) {
417
+ if (* rest == '=' )
418
+ p -> opt = rest + 1 ;
419
+ else if (* rest )
423
420
continue ;
424
- p -> opt = rest + 1 ;
421
+ return get_value ( p , options , flags ^ opt_flags ) ;
425
422
}
426
- return get_value (p , options , flags ^ opt_flags );
423
+
424
+ /* abbreviated? */
425
+ if (!strncmp (long_name , arg_start , arg_end - arg_start ))
426
+ register_abbrev (p , options , flags ^ opt_flags ,
427
+ & abbrev , & ambiguous );
428
+
429
+ /* negated and abbreviated very much? */
430
+ if (allow_unset && starts_with ("no-" , arg ))
431
+ register_abbrev (p , options , OPT_UNSET ^ opt_flags ,
432
+ & abbrev , & ambiguous );
427
433
}
428
434
429
- if (disallow_abbreviated_options && (ambiguous_option || abbrev_option ))
435
+ if (disallow_abbreviated_options && (ambiguous . option || abbrev . option ))
430
436
die ("disallowed abbreviated or ambiguous option '%.*s'" ,
431
437
(int )(arg_end - arg ), arg );
432
438
433
- if (ambiguous_option ) {
439
+ if (ambiguous . option ) {
434
440
error (_ ("ambiguous option: %s "
435
441
"(could be --%s%s or --%s%s)" ),
436
442
arg ,
437
- (ambiguous_flags & OPT_UNSET ) ? "no-" : "" ,
438
- ambiguous_option -> long_name ,
439
- (abbrev_flags & OPT_UNSET ) ? "no-" : "" ,
440
- abbrev_option -> long_name );
443
+ (ambiguous . flags & OPT_UNSET ) ? "no-" : "" ,
444
+ ambiguous . option -> long_name ,
445
+ (abbrev . flags & OPT_UNSET ) ? "no-" : "" ,
446
+ abbrev . option -> long_name );
441
447
return PARSE_OPT_HELP ;
442
448
}
443
- if (abbrev_option )
444
- return get_value (p , abbrev_option , abbrev_flags );
449
+ if (abbrev .option ) {
450
+ if (* arg_end )
451
+ p -> opt = arg_end + 1 ;
452
+ return get_value (p , abbrev .option , abbrev .flags );
453
+ }
445
454
return PARSE_OPT_UNKNOWN ;
446
455
}
447
456
0 commit comments