parse-options: add OPT_CMDMODE()
This can be used to define a set of mutually exclusive "command mode" options, and automatically catch use of more than one from that set as an error. Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									35f5eaa2ee
								
							
						
					
					
						commit
						1158826394
					
				|  | @ -43,8 +43,42 @@ static void fix_filename(const char *prefix, const char **file) | ||||||
| 	*file = xstrdup(prefix_filename(prefix, strlen(prefix), *file)); | 	*file = xstrdup(prefix_filename(prefix, strlen(prefix), *file)); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static int opt_command_mode_error(const struct option *opt, | ||||||
|  | 				  const struct option *all_opts, | ||||||
|  | 				  int flags) | ||||||
|  | { | ||||||
|  | 	const struct option *that; | ||||||
|  | 	struct strbuf message = STRBUF_INIT; | ||||||
|  | 	struct strbuf that_name = STRBUF_INIT; | ||||||
|  |  | ||||||
|  | 	/* | ||||||
|  | 	 * Find the other option that was used to set the variable | ||||||
|  | 	 * already, and report that this is not compatible with it. | ||||||
|  | 	 */ | ||||||
|  | 	for (that = all_opts; that->type != OPTION_END; that++) { | ||||||
|  | 		if (that == opt || | ||||||
|  | 		    that->type != OPTION_CMDMODE || | ||||||
|  | 		    that->value != opt->value || | ||||||
|  | 		    that->defval != *(int *)opt->value) | ||||||
|  | 			continue; | ||||||
|  |  | ||||||
|  | 		if (that->long_name) | ||||||
|  | 			strbuf_addf(&that_name, "--%s", that->long_name); | ||||||
|  | 		else | ||||||
|  | 			strbuf_addf(&that_name, "-%c", that->short_name); | ||||||
|  | 		strbuf_addf(&message, ": incompatible with %s", that_name.buf); | ||||||
|  | 		strbuf_release(&that_name); | ||||||
|  | 		opterror(opt, message.buf, flags); | ||||||
|  | 		strbuf_release(&message); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  | 	return opterror(opt, ": incompatible with something else", flags); | ||||||
|  | } | ||||||
|  |  | ||||||
| static int get_value(struct parse_opt_ctx_t *p, | static int get_value(struct parse_opt_ctx_t *p, | ||||||
| 		     const struct option *opt, int flags) | 		     const struct option *opt, | ||||||
|  | 		     const struct option *all_opts, | ||||||
|  | 		     int flags) | ||||||
| { | { | ||||||
| 	const char *s, *arg; | 	const char *s, *arg; | ||||||
| 	const int unset = flags & OPT_UNSET; | 	const int unset = flags & OPT_UNSET; | ||||||
|  | @ -83,6 +117,16 @@ static int get_value(struct parse_opt_ctx_t *p, | ||||||
| 		*(int *)opt->value = unset ? 0 : opt->defval; | 		*(int *)opt->value = unset ? 0 : opt->defval; | ||||||
| 		return 0; | 		return 0; | ||||||
|  |  | ||||||
|  | 	case OPTION_CMDMODE: | ||||||
|  | 		/* | ||||||
|  | 		 * Giving the same mode option twice, although is unnecessary, | ||||||
|  | 		 * is not a grave error, so let it pass. | ||||||
|  | 		 */ | ||||||
|  | 		if (*(int *)opt->value && *(int *)opt->value != opt->defval) | ||||||
|  | 			return opt_command_mode_error(opt, all_opts, flags); | ||||||
|  | 		*(int *)opt->value = opt->defval; | ||||||
|  | 		return 0; | ||||||
|  |  | ||||||
| 	case OPTION_SET_PTR: | 	case OPTION_SET_PTR: | ||||||
| 		*(void **)opt->value = unset ? NULL : (void *)opt->defval; | 		*(void **)opt->value = unset ? NULL : (void *)opt->defval; | ||||||
| 		return 0; | 		return 0; | ||||||
|  | @ -143,12 +187,13 @@ static int get_value(struct parse_opt_ctx_t *p, | ||||||
|  |  | ||||||
| static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options) | static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options) | ||||||
| { | { | ||||||
|  | 	const struct option *all_opts = options; | ||||||
| 	const struct option *numopt = NULL; | 	const struct option *numopt = NULL; | ||||||
|  |  | ||||||
| 	for (; options->type != OPTION_END; options++) { | 	for (; options->type != OPTION_END; options++) { | ||||||
| 		if (options->short_name == *p->opt) { | 		if (options->short_name == *p->opt) { | ||||||
| 			p->opt = p->opt[1] ? p->opt + 1 : NULL; | 			p->opt = p->opt[1] ? p->opt + 1 : NULL; | ||||||
| 			return get_value(p, options, OPT_SHORT); | 			return get_value(p, options, all_opts, OPT_SHORT); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		/* | 		/* | ||||||
|  | @ -177,6 +222,7 @@ static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *optio | ||||||
| static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg, | static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg, | ||||||
|                           const struct option *options) |                           const struct option *options) | ||||||
| { | { | ||||||
|  | 	const struct option *all_opts = options; | ||||||
| 	const char *arg_end = strchr(arg, '='); | 	const char *arg_end = strchr(arg, '='); | ||||||
| 	const struct option *abbrev_option = NULL, *ambiguous_option = NULL; | 	const struct option *abbrev_option = NULL, *ambiguous_option = NULL; | ||||||
| 	int abbrev_flags = 0, ambiguous_flags = 0; | 	int abbrev_flags = 0, ambiguous_flags = 0; | ||||||
|  | @ -253,7 +299,7 @@ is_abbreviated: | ||||||
| 				continue; | 				continue; | ||||||
| 			p->opt = rest + 1; | 			p->opt = rest + 1; | ||||||
| 		} | 		} | ||||||
| 		return get_value(p, options, flags ^ opt_flags); | 		return get_value(p, options, all_opts, flags ^ opt_flags); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (ambiguous_option) | 	if (ambiguous_option) | ||||||
|  | @ -265,18 +311,20 @@ is_abbreviated: | ||||||
| 			(abbrev_flags & OPT_UNSET) ?  "no-" : "", | 			(abbrev_flags & OPT_UNSET) ?  "no-" : "", | ||||||
| 			abbrev_option->long_name); | 			abbrev_option->long_name); | ||||||
| 	if (abbrev_option) | 	if (abbrev_option) | ||||||
| 		return get_value(p, abbrev_option, abbrev_flags); | 		return get_value(p, abbrev_option, all_opts, abbrev_flags); | ||||||
| 	return -2; | 	return -2; | ||||||
| } | } | ||||||
|  |  | ||||||
| static int parse_nodash_opt(struct parse_opt_ctx_t *p, const char *arg, | static int parse_nodash_opt(struct parse_opt_ctx_t *p, const char *arg, | ||||||
| 			    const struct option *options) | 			    const struct option *options) | ||||||
| { | { | ||||||
|  | 	const struct option *all_opts = options; | ||||||
|  |  | ||||||
| 	for (; options->type != OPTION_END; options++) { | 	for (; options->type != OPTION_END; options++) { | ||||||
| 		if (!(options->flags & PARSE_OPT_NODASH)) | 		if (!(options->flags & PARSE_OPT_NODASH)) | ||||||
| 			continue; | 			continue; | ||||||
| 		if (options->short_name == arg[0] && arg[1] == '\0') | 		if (options->short_name == arg[0] && arg[1] == '\0') | ||||||
| 			return get_value(p, options, OPT_SHORT); | 			return get_value(p, options, all_opts, OPT_SHORT); | ||||||
| 	} | 	} | ||||||
| 	return -2; | 	return -2; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -13,6 +13,7 @@ enum parse_opt_type { | ||||||
| 	OPTION_COUNTUP, | 	OPTION_COUNTUP, | ||||||
| 	OPTION_SET_INT, | 	OPTION_SET_INT, | ||||||
| 	OPTION_SET_PTR, | 	OPTION_SET_PTR, | ||||||
|  | 	OPTION_CMDMODE, | ||||||
| 	/* options with arguments (usually) */ | 	/* options with arguments (usually) */ | ||||||
| 	OPTION_STRING, | 	OPTION_STRING, | ||||||
| 	OPTION_INTEGER, | 	OPTION_INTEGER, | ||||||
|  | @ -130,6 +131,8 @@ struct option { | ||||||
| #define OPT_BOOL(s, l, v, h)        OPT_SET_INT(s, l, v, h, 1) | #define OPT_BOOL(s, l, v, h)        OPT_SET_INT(s, l, v, h, 1) | ||||||
| #define OPT_SET_PTR(s, l, v, h, p)  { OPTION_SET_PTR, (s), (l), (v), NULL, \ | #define OPT_SET_PTR(s, l, v, h, p)  { OPTION_SET_PTR, (s), (l), (v), NULL, \ | ||||||
| 				      (h), PARSE_OPT_NOARG, NULL, (p) } | 				      (h), PARSE_OPT_NOARG, NULL, (p) } | ||||||
|  | #define OPT_CMDMODE(s, l, v, h, i) { OPTION_CMDMODE, (s), (l), (v), NULL, \ | ||||||
|  | 				      (h), PARSE_OPT_NOARG|PARSE_OPT_NONEG, NULL, (i) } | ||||||
| #define OPT_INTEGER(s, l, v, h)     { OPTION_INTEGER, (s), (l), (v), N_("n"), (h) } | #define OPT_INTEGER(s, l, v, h)     { OPTION_INTEGER, (s), (l), (v), N_("n"), (h) } | ||||||
| #define OPT_STRING(s, l, v, a, h)   { OPTION_STRING,  (s), (l), (v), (a), (h) } | #define OPT_STRING(s, l, v, a, h)   { OPTION_STRING,  (s), (l), (v), (a), (h) } | ||||||
| #define OPT_STRING_LIST(s, l, v, a, h) \ | #define OPT_STRING_LIST(s, l, v, a, h) \ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Junio C Hamano
						Junio C Hamano