Thread (2 messages) 2 messages, 2 authors, 2023-02-07

Re: [PATCH v4 3/9] config API: add and use a "git_config_get()" family of functions

From: Ævar Arnfjörð Bjarmason <hidden>
Date: 2023-02-07 10:49:09

On Thu, Feb 02 2023, Junio C Hamano wrote:
Ævar Arnfjörð Bjarmason  [off-list ref] writes:
quoted
We already have the basic "git_config_get_value()" function and its
"repo_*" and "configset" siblings to get a given "key" and assign the
last key found to a provided "value".

But some callers don't care about that value, but just want to use the
return value of the "get_value()" function to check whether the key
exist (or another non-zero return value).

The immediate motivation for this is that a subsequent commit will
need to change all callers of the "*_get_value_multi()" family of
functions. In two cases here we (ab)used it to check whether we had
any values for the given key, but didn't care about the return value.
So, the idea is that 

	if (!git_config_get_string(key, &discard))
		free(discard);
	else
		... the key is missing ...

becomes

	if (git_config_get(key))
		... the key is missing ...

In other words, git_config_get() returns 0 only when the key is
used, and non-zero return signals that the key is not used?

Similarly, get_value_multi() was an interface to get to the
value_list associated to the given key, and was abused like

	if (git_config_get_value_multi(key))
		... the key exists ...

which will become

	if (!git_config_get(key))
		... the key exists ...

right?
Yes, I've amended this in a re-roll to add tests to the configset tests,
so how the new API should be used becomes obvious.
quoted
@@ -3185,7 +3184,7 @@ static void configure_added_submodule(struct add_data *add_data)
 	 * is_submodule_active(), since that function needs to find
 	 * out the value of "submodule.active" again anyway.
 	 */
-	if (!git_config_get_string_tmp("submodule.active", &val)) {
+	if (!git_config_get("submodule.active")) {
string_tmp() variant is to retrieve borrowed value, and it returns 0
when there is a value.  If it is a valueless true, we get -1 back
with an error message.  What does the updated version do in the
valueless true case?
No, we'll get back 0, as a value-less key exists. 

This sort of code would be correct in general, as if we really want to
check if the key exists a value-less is a valid boolean true.

In this case we happen to segfault later on if we encounter such a key,
but that's unrelated to this being correct.

The segfault is then fixed later in this topic.
quoted
@@ -2425,8 +2433,25 @@ int git_configset_get_value(struct config_set *cs, const char *key, const char *
 
 const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key)
 {
-	struct config_set_element *e = configset_find_element(cs, key);
-	return e ? &e->value_list : NULL;
+	struct config_set_element *e;
+
+	if (configset_find_element(cs, key, &e))
+		return NULL;
+	else if (!e)
+		return NULL;
+	return &e->value_list;
+}
OK.  !e means "we got a healthy key and peeking into the hash table,
there wasn't any entry for the key", and that is reported with NULL.
Do we evern return a string list with .nr == 0, I wonder.  Having to
deal with such a list would make the caller's job more complex, but
perhaps we are not allowing the code to shrink value_list.nr to
avoid such a situation?
No, we never return a list with .nr == 0. That's why Stolee's earlier
RFC tried to solve a subset of the problem this topic addresse by
returning such a list as a way to indicate "does not exist".

That would work to an extent, but would leave the main problem (which
Stolee wasn't aware of at the time) of having a ".nr > 0" list with
"NULL" elements in it.

It also wouldn't be idiomatic with the rest of the API, as this topic
shows, and means you can't distinguish non-existence from other errors.
quoted
+int git_configset_get(struct config_set *cs, const char *key)
+{
+	struct config_set_element *e;
+	int ret;
+
+	if ((ret = configset_find_element(cs, key, &e)))
+		return ret;
+	else if (!e)
+		return 1;
+	return 0;
 }
OK.  So 0 return from the function means there is a value (or more)
for a given key.  Good.
quoted
diff --git a/config.h b/config.h
index ef9eade6414..04c5e594015 100644
--- a/config.h
+++ b/config.h
@@ -471,9 +471,12 @@ void git_configset_clear(struct config_set *cs);
 
 /*
  * These functions return 1 if not found, and 0 if found, leaving the found
- * value in the 'dest' pointer.
+ * value in the 'dest' pointer (if any).
  */
Now the returned non-zero values are no longer 1 alone, no?
Whatever lower-level functions use to signal an error is propagated
up with the

	if ((ret = func())
		return ret;
That's still mostly true, but I should have added the new
git_configset_get() below this comment, and split it up, i.e. it's still
true for the functions that populate "dest".

I have a topic-on-top to fix those (to propagate them up), and it was
hard to know where to draw the line, in this case I got it wrong. Will
fix it.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help