parse-options: factor out register_abbrev() and struct parsed_option
Add a function, register_abbrev(), for storing the necessary details for remembering an abbreviated and thus potentially ambiguous option. Call it instead of sharing the code using goto, to make the control flow more explicit. Conveniently collect these details in the new struct parsed_option to reduce the number of necessary function arguments. Signed-off-by: René Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
		
				
					committed by
					
						
						Junio C Hamano
					
				
			
			
				
	
			
			
			
						parent
						
							597f9d037d
						
					
				
				
					commit
					cb46c3faf8
				
			@ -350,14 +350,40 @@ static int is_alias(struct parse_opt_ctx_t *ctx,
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct parsed_option {
 | 
			
		||||
	const struct option *option;
 | 
			
		||||
	enum opt_parsed flags;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void register_abbrev(struct parse_opt_ctx_t *p,
 | 
			
		||||
			    const struct option *option, enum opt_parsed flags,
 | 
			
		||||
			    struct parsed_option *abbrev,
 | 
			
		||||
			    struct parsed_option *ambiguous)
 | 
			
		||||
{
 | 
			
		||||
	if (p->flags & PARSE_OPT_KEEP_UNKNOWN_OPT)
 | 
			
		||||
		return;
 | 
			
		||||
	if (abbrev->option &&
 | 
			
		||||
	    !is_alias(p, abbrev->option, option)) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * If this is abbreviated, it is
 | 
			
		||||
		 * ambiguous. So when there is no
 | 
			
		||||
		 * exact match later, we need to
 | 
			
		||||
		 * error out.
 | 
			
		||||
		 */
 | 
			
		||||
		ambiguous->option = abbrev->option;
 | 
			
		||||
		ambiguous->flags = abbrev->flags;
 | 
			
		||||
	}
 | 
			
		||||
	abbrev->option = option;
 | 
			
		||||
	abbrev->flags = flags;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static enum parse_opt_result parse_long_opt(
 | 
			
		||||
	struct parse_opt_ctx_t *p, const char *arg,
 | 
			
		||||
	const struct option *options)
 | 
			
		||||
{
 | 
			
		||||
	const char *arg_end = strchrnul(arg, '=');
 | 
			
		||||
	const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
 | 
			
		||||
	enum opt_parsed abbrev_flags = OPT_LONG, ambiguous_flags = OPT_LONG;
 | 
			
		||||
	int allow_abbrev = !(p->flags & PARSE_OPT_KEEP_UNKNOWN_OPT);
 | 
			
		||||
	struct parsed_option abbrev = { .option = NULL, .flags = OPT_LONG };
 | 
			
		||||
	struct parsed_option ambiguous = { .option = NULL, .flags = OPT_LONG };
 | 
			
		||||
 | 
			
		||||
	for (; options->type != OPTION_END; options++) {
 | 
			
		||||
		const char *rest, *long_name = options->long_name;
 | 
			
		||||
@ -377,31 +403,20 @@ static enum parse_opt_result parse_long_opt(
 | 
			
		||||
			rest = NULL;
 | 
			
		||||
		if (!rest) {
 | 
			
		||||
			/* abbreviated? */
 | 
			
		||||
			if (allow_abbrev &&
 | 
			
		||||
			    !strncmp(long_name, arg, arg_end - arg)) {
 | 
			
		||||
is_abbreviated:
 | 
			
		||||
				if (abbrev_option &&
 | 
			
		||||
				    !is_alias(p, abbrev_option, options)) {
 | 
			
		||||
					/*
 | 
			
		||||
					 * If this is abbreviated, it is
 | 
			
		||||
					 * ambiguous. So when there is no
 | 
			
		||||
					 * exact match later, we need to
 | 
			
		||||
					 * error out.
 | 
			
		||||
					 */
 | 
			
		||||
					ambiguous_option = abbrev_option;
 | 
			
		||||
					ambiguous_flags = abbrev_flags;
 | 
			
		||||
				}
 | 
			
		||||
				abbrev_option = options;
 | 
			
		||||
				abbrev_flags = flags ^ opt_flags;
 | 
			
		||||
			if (!strncmp(long_name, arg, arg_end - arg)) {
 | 
			
		||||
				register_abbrev(p, options, flags ^ opt_flags,
 | 
			
		||||
						&abbrev, &ambiguous);
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			/* negation allowed? */
 | 
			
		||||
			if (options->flags & PARSE_OPT_NONEG)
 | 
			
		||||
				continue;
 | 
			
		||||
			/* negated and abbreviated very much? */
 | 
			
		||||
			if (allow_abbrev && starts_with("no-", arg)) {
 | 
			
		||||
			if (starts_with("no-", arg)) {
 | 
			
		||||
				flags |= OPT_UNSET;
 | 
			
		||||
				goto is_abbreviated;
 | 
			
		||||
				register_abbrev(p, options, flags ^ opt_flags,
 | 
			
		||||
						&abbrev, &ambiguous);
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			/* negated? */
 | 
			
		||||
			if (!starts_with(arg, "no-"))
 | 
			
		||||
@ -409,12 +424,12 @@ is_abbreviated:
 | 
			
		||||
			flags |= OPT_UNSET;
 | 
			
		||||
			if (!skip_prefix(arg + 3, long_name, &rest)) {
 | 
			
		||||
				/* abbreviated and negated? */
 | 
			
		||||
				if (allow_abbrev &&
 | 
			
		||||
				    !strncmp(long_name, arg + 3,
 | 
			
		||||
				if (!strncmp(long_name, arg + 3,
 | 
			
		||||
					     arg_end - arg - 3))
 | 
			
		||||
					goto is_abbreviated;
 | 
			
		||||
				else
 | 
			
		||||
					continue;
 | 
			
		||||
					register_abbrev(p, options,
 | 
			
		||||
							flags ^ opt_flags,
 | 
			
		||||
							&abbrev, &ambiguous);
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (*rest) {
 | 
			
		||||
@ -425,24 +440,24 @@ is_abbreviated:
 | 
			
		||||
		return get_value(p, options, flags ^ opt_flags);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (disallow_abbreviated_options && (ambiguous_option || abbrev_option))
 | 
			
		||||
	if (disallow_abbreviated_options && (ambiguous.option || abbrev.option))
 | 
			
		||||
		die("disallowed abbreviated or ambiguous option '%.*s'",
 | 
			
		||||
		    (int)(arg_end - arg), arg);
 | 
			
		||||
 | 
			
		||||
	if (ambiguous_option) {
 | 
			
		||||
	if (ambiguous.option) {
 | 
			
		||||
		error(_("ambiguous option: %s "
 | 
			
		||||
			"(could be --%s%s or --%s%s)"),
 | 
			
		||||
			arg,
 | 
			
		||||
			(ambiguous_flags & OPT_UNSET) ?  "no-" : "",
 | 
			
		||||
			ambiguous_option->long_name,
 | 
			
		||||
			(abbrev_flags & OPT_UNSET) ?  "no-" : "",
 | 
			
		||||
			abbrev_option->long_name);
 | 
			
		||||
			(ambiguous.flags & OPT_UNSET) ?  "no-" : "",
 | 
			
		||||
			ambiguous.option->long_name,
 | 
			
		||||
			(abbrev.flags & OPT_UNSET) ?  "no-" : "",
 | 
			
		||||
			abbrev.option->long_name);
 | 
			
		||||
		return PARSE_OPT_HELP;
 | 
			
		||||
	}
 | 
			
		||||
	if (abbrev_option) {
 | 
			
		||||
	if (abbrev.option) {
 | 
			
		||||
		if (*arg_end)
 | 
			
		||||
			p->opt = arg_end + 1;
 | 
			
		||||
		return get_value(p, abbrev_option, abbrev_flags);
 | 
			
		||||
		return get_value(p, abbrev.option, abbrev.flags);
 | 
			
		||||
	}
 | 
			
		||||
	return PARSE_OPT_UNKNOWN;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user