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 <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Jeff King 2012-08-13 21:59:27 -04:00 committed by Junio C Hamano
parent 74991a98df
commit 9442710801
2 changed files with 39 additions and 10 deletions

View File

@ -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);

View File

@ -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 {
PROTO_LOCAL = 1,
PROTO_SSH,