@@ -1098,6 +1098,70 @@ int git_config_set(const char *key, const char *value)
10981098 return git_config_set_multivar (key , value , NULL , 0 );
10991099}
11001100
1101+ /*
1102+ * Auxiliary function to sanity-check and split the key into the section
1103+ * identifier and variable name.
1104+ *
1105+ * Returns 0 on success, -1 when there is an invalid character in the key and
1106+ * -2 if there is no section name in the key.
1107+ *
1108+ * store_key - pointer to char* which will hold a copy of the key with
1109+ * lowercase section and variable name
1110+ * baselen - pointer to int which will hold the length of the
1111+ * section + subsection part, can be NULL
1112+ */
1113+ int git_config_parse_key (const char * key , char * * store_key , int * baselen_ )
1114+ {
1115+ int i , dot , baselen ;
1116+ const char * last_dot = strrchr (key , '.' );
1117+
1118+ /*
1119+ * Since "key" actually contains the section name and the real
1120+ * key name separated by a dot, we have to know where the dot is.
1121+ */
1122+
1123+ if (last_dot == NULL ) {
1124+ error ("key does not contain a section: %s" , key );
1125+ return -2 ;
1126+ }
1127+
1128+ baselen = last_dot - key ;
1129+ if (baselen_ )
1130+ * baselen_ = baselen ;
1131+
1132+ /*
1133+ * Validate the key and while at it, lower case it for matching.
1134+ */
1135+ * store_key = xmalloc (strlen (key ) + 1 );
1136+
1137+ dot = 0 ;
1138+ for (i = 0 ; key [i ]; i ++ ) {
1139+ unsigned char c = key [i ];
1140+ if (c == '.' )
1141+ dot = 1 ;
1142+ /* Leave the extended basename untouched.. */
1143+ if (!dot || i > baselen ) {
1144+ if (!iskeychar (c ) ||
1145+ (i == baselen + 1 && !isalpha (c ))) {
1146+ error ("invalid key: %s" , key );
1147+ goto out_free_ret_1 ;
1148+ }
1149+ c = tolower (c );
1150+ } else if (c == '\n' ) {
1151+ error ("invalid key (newline): %s" , key );
1152+ goto out_free_ret_1 ;
1153+ }
1154+ (* store_key )[i ] = c ;
1155+ }
1156+ (* store_key )[i ] = 0 ;
1157+
1158+ return 0 ;
1159+
1160+ out_free_ret_1 :
1161+ free (* store_key );
1162+ return -1 ;
1163+ }
1164+
11011165/*
11021166 * If value==NULL, unset in (remove from) config,
11031167 * if value_regex!=NULL, disregard key/value pairs where value does not match.
@@ -1124,59 +1188,23 @@ int git_config_set(const char *key, const char *value)
11241188int git_config_set_multivar (const char * key , const char * value ,
11251189 const char * value_regex , int multi_replace )
11261190{
1127- int i , dot ;
11281191 int fd = -1 , in_fd ;
11291192 int ret ;
11301193 char * config_filename ;
11311194 struct lock_file * lock = NULL ;
1132- const char * last_dot = strrchr (key , '.' );
11331195
11341196 if (config_exclusive_filename )
11351197 config_filename = xstrdup (config_exclusive_filename );
11361198 else
11371199 config_filename = git_pathdup ("config" );
11381200
1139- /*
1140- * Since "key" actually contains the section name and the real
1141- * key name separated by a dot, we have to know where the dot is.
1142- */
1143-
1144- if (last_dot == NULL ) {
1145- error ("key does not contain a section: %s" , key );
1146- ret = 2 ;
1201+ /* parse-key returns negative; flip the sign to feed exit(3) */
1202+ ret = 0 - git_config_parse_key (key , & store .key , & store .baselen );
1203+ if (ret )
11471204 goto out_free ;
1148- }
1149- store .baselen = last_dot - key ;
11501205
11511206 store .multi_replace = multi_replace ;
11521207
1153- /*
1154- * Validate the key and while at it, lower case it for matching.
1155- */
1156- store .key = xmalloc (strlen (key ) + 1 );
1157- dot = 0 ;
1158- for (i = 0 ; key [i ]; i ++ ) {
1159- unsigned char c = key [i ];
1160- if (c == '.' )
1161- dot = 1 ;
1162- /* Leave the extended basename untouched.. */
1163- if (!dot || i > store .baselen ) {
1164- if (!iskeychar (c ) || (i == store .baselen + 1 && !isalpha (c ))) {
1165- error ("invalid key: %s" , key );
1166- free (store .key );
1167- ret = 1 ;
1168- goto out_free ;
1169- }
1170- c = tolower (c );
1171- } else if (c == '\n' ) {
1172- error ("invalid key (newline): %s" , key );
1173- free (store .key );
1174- ret = 1 ;
1175- goto out_free ;
1176- }
1177- store .key [i ] = c ;
1178- }
1179- store .key [i ] = 0 ;
11801208
11811209 /*
11821210 * The lock serves a purpose in addition to locking: the new
0 commit comments