[PATCH v2] die_for_incompatible_opts(): unbounded number of options
From: Junio C Hamano <hidden>
Date: 2026-08-27 17:28:35
We have die_for_incompatible_optN() (for 2 <= N <= 4) to check and complain when two or more among N mutually incompatible options are used. What should a developer do if there are more than four options that cannot be used at once? Introduce die_for_incompatible_opts(), which can handle an arbitrary number of mutually exclusive options, and rewrite existing variants using it. The new function takes N pairs of <bool optN, const char *nameN>, followed by EOF. Note that even if the caller passes bool, it is promoted to platform-natural int when calling this variadic function. Thus, the implementation uses va_arg(ap, int) to extract the value, which allows it to distinguish between bool and EOF serving as the sentinel. Signed-off-by: Junio C Hamano <redacted> --- parse-options.c | 29 +++++++++++++++++------------ parse-options.h | 38 ++++++++++++++++++++++++++------------ 2 files changed, 43 insertions(+), 24 deletions(-)
diff --git c/parse-options.c w/parse-options.c
index 4519ead9dc..0aad1e5373 100644
--- c/parse-options.c
+++ w/parse-options.c@@ -1535,26 +1535,31 @@ void NORETURN usage_msg_optf(const char * const fmt, usage_msg_opt(msg.buf, usagestr, options); } -void die_for_incompatible_opt4(int opt1, const char *opt1_name, - int opt2, const char *opt2_name, - int opt3, const char *opt3_name, - int opt4, const char *opt4_name) +void die_for_incompatible_opts(bool opt1, const char *opt1_name, ...) { - int count = 0; + unsigned count = 0; const char *options[4]; + va_list ap; if (opt1) options[count++] = opt1_name; - if (opt2) - options[count++] = opt2_name; - if (opt3) - options[count++] = opt3_name; - if (opt4) - options[count++] = opt4_name; + va_start(ap, opt1_name); + while (count < ARRAY_SIZE(options)) { + int opt_set = va_arg(ap, int); + const char *opt_name; + + if (opt_set == EOF) + break; + opt_name = va_arg(ap, const char *); + if (opt_set) + options[count++] = opt_name; + } + va_end(ap); + switch (count) { case 4: die(_("options '%s', '%s', '%s', and '%s' cannot be used together"), - opt1_name, opt2_name, opt3_name, opt4_name); + options[0], options[1], options[2], options[3]); break; case 3: die(_("options '%s', '%s', and '%s' cannot be used together"),
diff --git c/parse-options.h w/parse-options.h
index d7f896a933..50bd715b86 100644
--- c/parse-options.h
+++ w/parse-options.h@@ -441,29 +441,43 @@ void NORETURN usage_msg_optf(const char *fmt, const char * const *usagestr, const struct option *options, ...); -void die_for_incompatible_opt4(int opt1, const char *opt1_name, - int opt2, const char *opt2_name, - int opt3, const char *opt3_name, - int opt4, const char *opt4_name); +/* + * Take N pairs of <bool optN, const char *opt_nameN> as parameters, + * followed by EOF. The caller declares "The options opt_name1 through + * opt_nameN exist and the command line has options whose optN is set." + * and asks that an error be raised if two or more of these options are + * set at the same time. + */ +void die_for_incompatible_opts(bool opt1, const char *opt1_name, ...); +static inline void die_for_incompatible_opt4(int opt1, const char *opt1_name, + int opt2, const char *opt2_name, + int opt3, const char *opt3_name, + int opt4, const char *opt4_name) +{ + die_for_incompatible_opts(!!opt1, opt1_name, + !!opt2, opt2_name, + !!opt3, opt3_name, + !!opt4, opt4_name, + EOF); +} static inline void die_for_incompatible_opt3(int opt1, const char *opt1_name, int opt2, const char *opt2_name, int opt3, const char *opt3_name) { - die_for_incompatible_opt4(opt1, opt1_name, - opt2, opt2_name, - opt3, opt3_name, - 0, ""); + die_for_incompatible_opts(!!opt1, opt1_name, + !!opt2, opt2_name, + !!opt3, opt3_name, + EOF); } static inline void die_for_incompatible_opt2(int opt1, const char *opt1_name, int opt2, const char *opt2_name) { - die_for_incompatible_opt4(opt1, opt1_name, - opt2, opt2_name, - 0, "", - 0, ""); + die_for_incompatible_opts(!!opt1, opt1_name, + !!opt2, opt2_name, + EOF); } /*