Commit 0da81d2b39290fe4d444953acb6d68795ed1ef42

Carlos Martín Nieto 2012-11-13T14:43:23

config: return an emtpy string when there is no value Returning NULL for the string when we haven't signaled an error condition is counter-intuitive and causes unnecessary edge cases. Return an empty string when asking for a string value for a configuration variable such as '[section] var' to avoid these edge cases. If the distinction between no value and an empty value is needed, this can be retrieved from the entry directly. As a side-effect, this change stops the int parsing functions from segfaulting on such a variable.

diff --git a/src/config.c b/src/config.c
index ed9901b..4fb1611 100644
--- a/src/config.c
+++ b/src/config.c
@@ -393,24 +393,11 @@ int git_config_get_int32(int32_t *out, git_config *cfg, const char *name)
 	return git_config_parse_int32(out, value);
 }
 
-int git_config_get_bool(int *out, git_config *cfg, const char *name)
-{
-	const char *value;
-	int ret;
-
-	if ((ret = git_config_get_string(&value, cfg, name)) < 0)
-		return ret;
-
-	return git_config_parse_bool(out, value);
-}
-
 static int get_string_at_file(const char **out, git_config_file *file, const char *name)
 {
 	const git_config_entry *entry;
 	int res;
 
-	*out = NULL;
-
 	res = file->get(file, name, &entry);
 	if (!res)
 		*out = entry->value;
@@ -418,7 +405,7 @@ static int get_string_at_file(const char **out, git_config_file *file, const cha
 	return res;
 }
 
-int git_config_get_string(const char **out, git_config *cfg, const char *name)
+static int get_string(const char **out, git_config *cfg, const char *name)
 {
 	file_internal *internal;
 	unsigned int i;
@@ -435,6 +422,29 @@ int git_config_get_string(const char **out, git_config *cfg, const char *name)
 	return GIT_ENOTFOUND;
 }
 
+int git_config_get_bool(int *out, git_config *cfg, const char *name)
+{
+	const char *value;
+	int ret;
+
+	if ((ret = get_string(&value, cfg, name)) < 0)
+		return ret;
+
+	return git_config_parse_bool(out, value);
+}
+
+int git_config_get_string(const char **out, git_config *cfg, const char *name)
+{
+	int ret;
+	const char *str;
+
+	if ((ret = get_string(&str, cfg, name)) < 0)
+		return ret;
+
+	*out = str == NULL ? "" : str;
+	return 0;
+}
+
 int git_config_get_entry(const git_config_entry **out, git_config *cfg, const char *name)
 {
 	file_internal *internal;
diff --git a/src/remote.c b/src/remote.c
index 70a6152..4a4d160 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -136,7 +136,7 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name)
 	if ((error = git_config_get_string(&val, config, git_buf_cstr(&buf))) < 0)
 		goto cleanup;
 	
-	if (!val || strlen(val) == 0) {
+	if (strlen(val) == 0) {
 		giterr_set(GITERR_INVALID, "Malformed remote '%s' - missing URL", name);
 		error = -1;
 		goto cleanup;
@@ -153,8 +153,10 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name)
 	}
 
 	error = git_config_get_string(&val, config, git_buf_cstr(&buf));
-	if (error == GIT_ENOTFOUND)
+	if (error == GIT_ENOTFOUND) {
+		val = NULL;
 		error = 0;
+	}
 
 	if (error < 0) {
 		error = -1;
diff --git a/tests-clar/config/read.c b/tests-clar/config/read.c
index a468a4d..7b30b6e 100644
--- a/tests-clar/config/read.c
+++ b/tests-clar/config/read.c
@@ -87,8 +87,10 @@ void test_config_read__lone_variable(void)
 
 	cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config4")));
 
+	cl_git_fail(git_config_get_int32(&i, cfg, "some.section.variable"));
+
 	cl_git_pass(git_config_get_string(&str, cfg, "some.section.variable"));
-	cl_assert(str == NULL);
+	cl_assert_equal_s(str, "");
 
 	cl_git_pass(git_config_get_bool(&i, cfg, "some.section.variable"));
 	cl_assert(i == 1);