Add "tristate" functions to go along with the "bool" functions and migrate the common pattern of checking if something is "bool" or "auto" in various places over to the new functions. We also have e.g. "repo_config_get_bool" and "config_error_nonbool". I'm not adding corresponding "tristate" functions as they're not needed by anything, but we could add those in the future if they are. I'm not migrating over "core.abbrev" parsing as part of this change. When "core.abbrev" was made optionally boolean in a9ecaa06a7 (core.abbrev=no disables abbreviations, 2020-09-01) the "die if empty" code added in g48d5014dd4 (config.abbrev: document the new default that auto-scales, 2016-11-01) wasn't adjusted. It thus behaves unlike all other "maybe bool" config variables. I have a planned series to start adding some tests for "core.abbrev", but AFAICT there's not even a test for "core.abbrev=true", and I'd like to focus on thing that have no behavior change here, so let's leave it for now. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@xxxxxxxxx> --- builtin/log.c | 13 +++++++------ compat/mingw.c | 6 +++--- config.c | 16 ++++++++++++++++ config.h | 12 ++++++++++++ http.c | 5 +++-- userdiff.c | 6 ++---- 6 files changed, 43 insertions(+), 15 deletions(-) diff --git a/builtin/log.c b/builtin/log.c index 8acd285daf..0d945313d8 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -868,11 +868,12 @@ static int git_format_config(const char *var, const char *value, void *cb) return 0; } if (!strcmp(var, "format.numbered")) { - if (value && !strcasecmp(value, "auto")) { + int tristate = git_config_tristate(var, value); + if (tristate == 2) { auto_number = 1; return 0; } - numbered = git_config_bool(var, value); + numbered = tristate; auto_number = auto_number && numbered; return 0; } @@ -904,11 +905,11 @@ static int git_format_config(const char *var, const char *value, void *cb) if (!strcmp(var, "format.signaturefile")) return git_config_pathname(&signature_file, var, value); if (!strcmp(var, "format.coverletter")) { - if (value && !strcasecmp(value, "auto")) { + int tristate = git_config_tristate(var, value); + if (tristate == 2) config_cover_letter = COVER_AUTO; - return 0; - } - config_cover_letter = git_config_bool(var, value) ? COVER_ON : COVER_OFF; + else + config_cover_letter = tristate ? COVER_ON : COVER_OFF; return 0; } if (!strcmp(var, "format.outputdirectory")) diff --git a/compat/mingw.c b/compat/mingw.c index a43599841c..e6e85ae99a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -247,11 +247,11 @@ int mingw_core_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "core.restrictinheritedhandles")) { - if (value && !strcasecmp(value, "auto")) + int tristate = git_config_tristate(var, value); + if (tristate == 2) core_restrict_inherited_handles = -1; else - core_restrict_inherited_handles = - git_config_bool(var, value); + core_restrict_inherited_handles = tristate; return 0; } diff --git a/config.c b/config.c index fc28dbd97c..74d2b2c0df 100644 --- a/config.c +++ b/config.c @@ -1257,6 +1257,14 @@ int git_parse_maybe_bool(const char *value) return -1; } +int git_parse_maybe_tristate(const char *value) +{ + int v = git_parse_maybe_bool(value); + if (v < 0 && !strcasecmp(value, "auto")) + return 2; + return v; +} + int git_config_bool_or_int(const char *name, const char *value, int *is_bool) { int v = git_parse_maybe_bool_text(value); @@ -1268,6 +1276,14 @@ int git_config_bool_or_int(const char *name, const char *value, int *is_bool) return git_config_int(name, value); } +int git_config_tristate(const char *name, const char *value) +{ + int v = git_parse_maybe_tristate(value); + if (v < 0) + die(_("bad tristate config value '%s' for '%s'"), value, name); + return v; +} + int git_config_bool(const char *name, const char *value) { int v = git_parse_maybe_bool(value); diff --git a/config.h b/config.h index 19a9adbaa9..c5129e4392 100644 --- a/config.h +++ b/config.h @@ -197,6 +197,12 @@ int git_parse_ulong(const char *, unsigned long *); */ int git_parse_maybe_bool(const char *); +/** + * Same as `git_parse_maybe_bool`, except that "auto" is recognized and + * will return "2". + */ +int git_parse_maybe_tristate(const char *); + /** * Parse the string to an integer, including unit factors. Dies on error; * otherwise, returns the parsed result. @@ -226,6 +232,12 @@ int git_config_bool_or_int(const char *, const char *, int *); */ int git_config_bool(const char *, const char *); +/** + * Like git_config_bool() except "auto" is also recognized and will + * return "2" + */ +int git_config_tristate(const char *, const char *); + /** * Allocates and copies the value string into the `dest` parameter; if no * string is given, prints an error message and returns -1. diff --git a/http.c b/http.c index 406410f884..b54a232e90 100644 --- a/http.c +++ b/http.c @@ -406,10 +406,11 @@ static int http_options(const char *var, const char *value, void *cb) return git_config_string(&user_agent, var, value); if (!strcmp("http.emptyauth", var)) { - if (value && !strcmp("auto", value)) + int tristate = git_config_tristate(var, value); + if (tristate == 2) curl_empty_auth = -1; else - curl_empty_auth = git_config_bool(var, value); + curl_empty_auth = tristate; return 0; } diff --git a/userdiff.c b/userdiff.c index 3f81a2261c..7ff010961f 100644 --- a/userdiff.c +++ b/userdiff.c @@ -277,10 +277,8 @@ static int parse_funcname(struct userdiff_funcname *f, const char *k, static int parse_tristate(int *b, const char *k, const char *v) { - if (v && !strcasecmp(v, "auto")) - *b = -1; - else - *b = git_config_bool(k, v); + int tristate = git_config_tristate(k, v); + *b = tristate == 2 ? -1 : tristate; return 0; } -- 2.31.1.527.g9b8f7de2547