diff options
authorJeff King <>2012-08-14 01:59:27 (GMT)
committerJunio C Hamano <>2012-08-14 04:52:36 (GMT)
commit9442710801b0b7b9aeefe60408d1835af138cfcc (patch)
parent74991a98df79ff3702dcb3b5c22c7b9ec20cfead (diff)
parse_feature_request: make it easier to see feature values
We already take care to parse key/value capabilities like "foo=bar", but the code does not provide a good way of actually finding out what is on the right-hand side of the "=". A server using "parse_feature_request" could accomplish this with some extra parsing. You must skip past the "key" portion manually, check for "=" versus NUL or space, and then find the length by searching for the next space (or NUL). But clients can't even do that, since the "server_supports" interface does not even return the pointer. Instead, let's have our parser share more information by providing a pointer to the value and its length. The "parse_feature_value" function returns a pointer to the feature's value portion, along with the length of the value. If the feature is missing, NULL is returned. If it does not have an "=", then a zero-length value is returned. Similarly, "server_feature_value" behaves in the same way, but always checks the static server_feature_list variable. We can then implement "server_supports" in terms of "server_feature_value". We cannot implement the original "parse_feature_request" in terms of our new function, because it returned a pointer to the beginning of the feature. However, no callers actually cared about the value of the returned pointer, so we can simplify it to a boolean just as we do for "server_supports". Signed-off-by: Jeff King <> Signed-off-by: Junio C Hamano <>
2 files changed, 39 insertions, 10 deletions
diff --git a/cache.h b/cache.h
index 06413e1..b71b065 100644
--- a/cache.h
+++ b/cache.h
@@ -1030,7 +1030,9 @@ struct extra_have_objects {
extern struct ref **get_remote_heads(int in, struct ref **list, unsigned int flags, struct extra_have_objects *);
extern int server_supports(const char *feature);
-extern const char *parse_feature_request(const char *features, const char *feature);
+extern int parse_feature_request(const char *features, const char *feature);
+extern const char *server_feature_value(const char *feature, int *len_ret);
+extern const char *parse_feature_value(const char *feature_list, const char *feature, int *len_ret);
extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
diff --git a/connect.c b/connect.c
index 912cdde..9aec10c 100644
--- a/connect.c
+++ b/connect.c
@@ -99,12 +99,7 @@ struct ref **get_remote_heads(int in, struct ref **list,
return list;
-int server_supports(const char *feature)
- return !!parse_feature_request(server_capabilities, feature);
-const char *parse_feature_request(const char *feature_list, const char *feature)
+const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp)
int len;
@@ -116,14 +111,46 @@ const char *parse_feature_request(const char *feature_list, const char *feature)
const char *found = strstr(feature_list, feature);
if (!found)
return NULL;
- if ((feature_list == found || isspace(found[-1])) &&
- (!found[len] || isspace(found[len]) || found[len] == '='))
- return found;
+ if (feature_list == found || isspace(found[-1])) {
+ const char *value = found + len;
+ /* feature with no value (e.g., "thin-pack") */
+ if (!*value || isspace(*value)) {
+ if (lenp)
+ *lenp = 0;
+ return value;
+ }
+ /* feature with a value (e.g., "agent=git/1.2.3") */
+ else if (*value == '=') {
+ value++;
+ if (lenp)
+ *lenp = strcspn(value, " \t\n");
+ return value;
+ }
+ /*
+ * otherwise we matched a substring of another feature;
+ * keep looking
+ */
+ }
feature_list = found + 1;
return NULL;
+int parse_feature_request(const char *feature_list, const char *feature)
+ return !!parse_feature_value(feature_list, feature, NULL);
+const char *server_feature_value(const char *feature, int *len)
+ return parse_feature_value(server_capabilities, feature, len);
+int server_supports(const char *feature)
+ return !!server_feature_value(feature, NULL);
enum protocol {