config: add git_config_key_is_valid() for quiet validation

Move the body of git_config_parse_key() into a static helper do_parse_config_key() that takes a "quiet" flag and treats store_key as optional. git_config_parse_key() becomes a thin wrapper. Add git_config_key_is_valid() for callers that only need to know whether a key is well-formed. Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Harald Nordgren committed Jun 2, 2026 at 18:43 UTC 9b03e2790af03bebc9bc084cfc921492e6d5ca70
2 files changed +31 -9
config.c
+29 -9
@@ -536,11 +536,14 @@ static inline int iskeychar(int c)
536 * -2 if there is no section name in the key.
537 *
538 * store_key - pointer to char* which will hold a copy of the key with
539 - * lowercase section and variable name
539 + * lowercase section and variable name, can be NULL to skip
540 + * allocation when only validation is needed
541 * baselen - pointer to size_t which will hold the length of the
542 * section + subsection part, can be NULL
543 + * quiet - when non-zero, suppress error() reports on rejection
544 */
543 -int git_config_parse_key(const char *key, char **store_key, size_t *baselen_)
545 +static int do_parse_config_key(const char *key, char **store_key,
546 + size_t *baselen_, int quiet)
547 {
548 size_t i, baselen;
549 int dot;
@@ -552,12 +555,14 @@ int git_config_parse_key(const char *key, char **store_key, size_t *baselen_)
555 */
556
557 if (last_dot == NULL || last_dot == key) {
555 - error(_("key does not contain a section: %s"), key);
558 + if (!quiet)
559 + error(_("key does not contain a section: %s"), key);
560 return -CONFIG_NO_SECTION_OR_NAME;
561 }
562
563 if (!last_dot[1]) {
560 - error(_("key does not contain variable name: %s"), key);
564 + if (!quiet)
565 + error(_("key does not contain variable name: %s"), key);
566 return -CONFIG_NO_SECTION_OR_NAME;
567 }
568
@@ -568,7 +573,8 @@ int git_config_parse_key(const char *key, char **store_key, size_t *baselen_)
573 /*
574 * Validate the key and while at it, lower case it for matching.
575 */
571 - *store_key = xmallocz(strlen(key));
576 + if (store_key)
577 + *store_key = xmallocz(strlen(key));
578
579 dot = 0;
580 for (i = 0; key[i]; i++) {
@@ -579,24 +585,38 @@ int git_config_parse_key(const char *key, char **store_key, size_t *baselen_)
585 if (!dot || i > baselen) {
586 if (!iskeychar(c) ||
587 (i == baselen + 1 && !isalpha(c))) {
582 - error(_("invalid key: %s"), key);
588 + if (!quiet)
589 + error(_("invalid key: %s"), key);
590 goto out_free_ret_1;
591 }
592 c = tolower(c);
593 } else if (c == '\n') {
587 - error(_("invalid key (newline): %s"), key);
594 + if (!quiet)
595 + error(_("invalid key (newline): %s"), key);
596 goto out_free_ret_1;
597 }
590 - (*store_key)[i] = c;
598 + if (store_key)
599 + (*store_key)[i] = c;
600 }
601
602 return 0;
603
604 out_free_ret_1:
596 - FREE_AND_NULL(*store_key);
605 + if (store_key)
606 + FREE_AND_NULL(*store_key);
607 return -CONFIG_INVALID_KEY;
608 }
609
610 +int git_config_parse_key(const char *key, char **store_key, size_t *baselen_)
611 +{
612 + return do_parse_config_key(key, store_key, baselen_, 0);
613 +}
614 +
615 +int git_config_key_is_valid(const char *key)
616 +{
617 + return !do_parse_config_key(key, NULL, NULL, 1);
618 +}
619 +
620 static int config_parse_pair(const char *key, const char *value,
621 struct key_value_info *kvi,
622 config_fn_t fn, void *data)
config.h
+2
@@ -337,6 +337,8 @@ void repo_config_set(struct repository *, const char *, const char *);
337
338 int git_config_parse_key(const char *, char **, size_t *);
339
340 +int git_config_key_is_valid(const char *);
341 +
342 /*
343 * The following macros specify flag bits that alter the behavior
344 * of the repo_config_set_multivar*() methods.