@@ -350,14 +350,40 @@ static int is_alias(struct parse_opt_ctx_t *ctx,
350350 return 0 ;
351351}
352352
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+ !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+
353380static enum parse_opt_result parse_long_opt (
354381 struct parse_opt_ctx_t * p , const char * arg ,
355382 const struct option * options )
356383{
357384 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+ struct parsed_option abbrev = { .option = NULL , .flags = OPT_LONG };
386+ struct parsed_option ambiguous = { .option = NULL , .flags = OPT_LONG };
361387
362388 for (; options -> type != OPTION_END ; options ++ ) {
363389 const char * rest , * long_name = options -> long_name ;
@@ -377,44 +403,33 @@ static enum parse_opt_result parse_long_opt(
377403 rest = NULL ;
378404 if (!rest ) {
379405 /* 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- abbrev_option = options ;
395- abbrev_flags = flags ^ opt_flags ;
406+ if (!strncmp (long_name , arg , arg_end - arg )) {
407+ register_abbrev (p , options , flags ^ opt_flags ,
408+ & abbrev , & ambiguous );
396409 continue ;
397410 }
398411 /* negation allowed? */
399412 if (options -> flags & PARSE_OPT_NONEG )
400413 continue ;
401414 /* negated and abbreviated very much? */
402- if (allow_abbrev && starts_with ("no-" , arg )) {
415+ if (starts_with ("no-" , arg )) {
403416 flags |= OPT_UNSET ;
404- goto is_abbreviated ;
417+ register_abbrev (p , options , flags ^ opt_flags ,
418+ & abbrev , & ambiguous );
419+ continue ;
405420 }
406421 /* negated? */
407422 if (!starts_with (arg , "no-" ))
408423 continue ;
409424 flags |= OPT_UNSET ;
410425 if (!skip_prefix (arg + 3 , long_name , & rest )) {
411426 /* abbreviated and negated? */
412- if (allow_abbrev &&
413- !strncmp (long_name , arg + 3 ,
427+ if (!strncmp (long_name , arg + 3 ,
414428 arg_end - arg - 3 ))
415- goto is_abbreviated ;
416- else
417- continue ;
429+ register_abbrev (p , options ,
430+ flags ^ opt_flags ,
431+ & abbrev , & ambiguous );
432+ continue ;
418433 }
419434 }
420435 if (* rest ) {
@@ -425,24 +440,24 @@ static enum parse_opt_result parse_long_opt(
425440 return get_value (p , options , flags ^ opt_flags );
426441 }
427442
428- if (disallow_abbreviated_options && (ambiguous_option || abbrev_option ))
443+ if (disallow_abbreviated_options && (ambiguous . option || abbrev . option ))
429444 die ("disallowed abbreviated or ambiguous option '%.*s'" ,
430445 (int )(arg_end - arg ), arg );
431446
432- if (ambiguous_option ) {
447+ if (ambiguous . option ) {
433448 error (_ ("ambiguous option: %s "
434449 "(could be --%s%s or --%s%s)" ),
435450 arg ,
436- (ambiguous_flags & OPT_UNSET ) ? "no-" : "" ,
437- ambiguous_option -> long_name ,
438- (abbrev_flags & OPT_UNSET ) ? "no-" : "" ,
439- abbrev_option -> long_name );
451+ (ambiguous . flags & OPT_UNSET ) ? "no-" : "" ,
452+ ambiguous . option -> long_name ,
453+ (abbrev . flags & OPT_UNSET ) ? "no-" : "" ,
454+ abbrev . option -> long_name );
440455 return PARSE_OPT_HELP ;
441456 }
442- if (abbrev_option ) {
457+ if (abbrev . option ) {
443458 if (* arg_end )
444459 p -> opt = arg_end + 1 ;
445- return get_value (p , abbrev_option , abbrev_flags );
460+ return get_value (p , abbrev . option , abbrev . flags );
446461 }
447462 return PARSE_OPT_UNKNOWN ;
448463}
0 commit comments