Commit a8db6c92 by Edward Thomson Committed by Patrick Steinhardt

util: introduce `git__prefixncmp` and consolidate implementations

Introduce `git_prefixncmp` that will search up to the first `n`
characters of a string to see if it is prefixed by another string.
This is useful for examining if a non-null terminated character
array is prefixed by a particular substring.

Consolidate the various implementations of `git__prefixcmp` around a
single core implementation and add some test cases to validate its
behavior.

(cherry picked from commit 86219f40)
parent 5f557780
...@@ -250,35 +250,47 @@ void git__strtolower(char *str) ...@@ -250,35 +250,47 @@ void git__strtolower(char *str)
git__strntolower(str, strlen(str)); git__strntolower(str, strlen(str));
} }
int git__prefixcmp(const char *str, const char *prefix) GIT_INLINE(int) prefixcmp(const char *str, size_t str_n, const char *prefix, bool icase)
{ {
for (;;) { int s, p;
unsigned char p = *(prefix++), s;
while (str_n--) {
s = (unsigned char)*str++;
p = (unsigned char)*prefix++;
if (icase) {
s = git__tolower(s);
p = git__tolower(p);
}
if (!p) if (!p)
return 0; return 0;
if ((s = *(str++)) != p)
if (s != p)
return s - p; return s - p;
} }
return (0 - *prefix);
} }
int git__prefixcmp_icase(const char *str, const char *prefix) int git__prefixcmp(const char *str, const char *prefix)
{ {
return strncasecmp(str, prefix, strlen(prefix)); return prefixcmp(str, SIZE_MAX, prefix, false);
} }
int git__prefixncmp_icase(const char *str, size_t str_n, const char *prefix) int git__prefixncmp(const char *str, size_t str_n, const char *prefix)
{ {
int s, p; return prefixcmp(str, str_n, prefix, false);
}
while(str_n--) {
s = (unsigned char)git__tolower(*str++);
p = (unsigned char)git__tolower(*prefix++);
if (s != p) int git__prefixcmp_icase(const char *str, const char *prefix)
return s - p; {
} return prefixcmp(str, SIZE_MAX, prefix, true);
}
return (0 - *prefix); int git__prefixncmp_icase(const char *str, size_t str_n, const char *prefix)
{
return prefixcmp(str, str_n, prefix, true);
} }
int git__suffixcmp(const char *str, const char *suffix) int git__suffixcmp(const char *str, const char *suffix)
......
...@@ -254,6 +254,7 @@ GIT_INLINE(void) git__free(void *ptr) ...@@ -254,6 +254,7 @@ GIT_INLINE(void) git__free(void *ptr)
extern int git__prefixcmp(const char *str, const char *prefix); extern int git__prefixcmp(const char *str, const char *prefix);
extern int git__prefixcmp_icase(const char *str, const char *prefix); extern int git__prefixcmp_icase(const char *str, const char *prefix);
extern int git__prefixncmp(const char *str, size_t str_n, const char *prefix);
extern int git__prefixncmp_icase(const char *str, size_t str_n, const char *prefix); extern int git__prefixncmp_icase(const char *str, size_t str_n, const char *prefix);
extern int git__suffixcmp(const char *str, const char *suffix); extern int git__suffixcmp(const char *str, const char *suffix);
......
...@@ -40,6 +40,48 @@ void test_core_string__2(void) ...@@ -40,6 +40,48 @@ void test_core_string__2(void)
cl_assert(git__strcasesort_cmp("fooBar", "foobar") < 0); cl_assert(git__strcasesort_cmp("fooBar", "foobar") < 0);
} }
/* compare prefixes with len */
void test_core_string__prefixncmp(void)
{
cl_assert(git__prefixncmp("", 0, "") == 0);
cl_assert(git__prefixncmp("a", 1, "") == 0);
cl_assert(git__prefixncmp("", 0, "a") < 0);
cl_assert(git__prefixncmp("a", 1, "b") < 0);
cl_assert(git__prefixncmp("b", 1, "a") > 0);
cl_assert(git__prefixncmp("ab", 2, "a") == 0);
cl_assert(git__prefixncmp("ab", 1, "a") == 0);
cl_assert(git__prefixncmp("ab", 2, "ac") < 0);
cl_assert(git__prefixncmp("a", 1, "ac") < 0);
cl_assert(git__prefixncmp("ab", 1, "ac") < 0);
cl_assert(git__prefixncmp("ab", 2, "aa") > 0);
cl_assert(git__prefixncmp("ab", 1, "aa") < 0);
}
/* compare prefixes with len */
void test_core_string__prefixncmp_icase(void)
{
cl_assert(git__prefixncmp_icase("", 0, "") == 0);
cl_assert(git__prefixncmp_icase("a", 1, "") == 0);
cl_assert(git__prefixncmp_icase("", 0, "a") < 0);
cl_assert(git__prefixncmp_icase("a", 1, "b") < 0);
cl_assert(git__prefixncmp_icase("A", 1, "b") < 0);
cl_assert(git__prefixncmp_icase("a", 1, "B") < 0);
cl_assert(git__prefixncmp_icase("b", 1, "a") > 0);
cl_assert(git__prefixncmp_icase("B", 1, "a") > 0);
cl_assert(git__prefixncmp_icase("b", 1, "A") > 0);
cl_assert(git__prefixncmp_icase("ab", 2, "a") == 0);
cl_assert(git__prefixncmp_icase("Ab", 2, "a") == 0);
cl_assert(git__prefixncmp_icase("ab", 2, "A") == 0);
cl_assert(git__prefixncmp_icase("ab", 1, "a") == 0);
cl_assert(git__prefixncmp_icase("ab", 2, "ac") < 0);
cl_assert(git__prefixncmp_icase("Ab", 2, "ac") < 0);
cl_assert(git__prefixncmp_icase("ab", 2, "Ac") < 0);
cl_assert(git__prefixncmp_icase("a", 1, "ac") < 0);
cl_assert(git__prefixncmp_icase("ab", 1, "ac") < 0);
cl_assert(git__prefixncmp_icase("ab", 2, "aa") > 0);
cl_assert(git__prefixncmp_icase("ab", 1, "aa") < 0);
}
void test_core_string__strcmp(void) void test_core_string__strcmp(void)
{ {
cl_assert(git__strcmp("", "") == 0); cl_assert(git__strcmp("", "") == 0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment