diff --git a/include/cryb/string.h b/include/cryb/string.h index 9b4c752..a9cea83 100644 --- a/include/cryb/string.h +++ b/include/cryb/string.h @@ -41,6 +41,8 @@ #define string_append_string cryb_string_append_string #define string_printf cryb_string_printf #define string_vprintf cryb_string_vprintf +#define string_compare cryb_string_compare +#define string_equal cryb_string_equal typedef struct cryb_string string; @@ -57,5 +59,7 @@ ssize_t string_printf(string *, const char *, ...); #ifdef va_start ssize_t string_vprintf(string *, const char *, va_list); #endif +int string_compare(const string *, const string *); +int string_equal(const string *, const string *); #endif diff --git a/include/cryb/wstring.h b/include/cryb/wstring.h index e928063..2ff74ee 100644 --- a/include/cryb/wstring.h +++ b/include/cryb/wstring.h @@ -41,6 +41,8 @@ #define wstring_append_wstring cryb_wstring_append_wstring #define wstring_printf cryb_wstring_printf #define wstring_vprintf cryb_wstring_vprintf +#define wstring_compare cryb_wstring_compare +#define wstring_equal cryb_wstring_equal typedef struct cryb_wstring wstring; @@ -50,12 +52,14 @@ void wstring_delete(wstring *); int wstring_expand(wstring *, size_t); void wstring_shrink(wstring *); ssize_t wstring_trunc(wstring *, size_t); -ssize_t wstring_append_c(wstring *, wchar_t); -ssize_t wstring_append_cs(wstring *, const wchar_t *, size_t); +ssize_t wstring_append_wc(wstring *, wchar_t); +ssize_t wstring_append_wcs(wstring *, const wchar_t *, size_t); ssize_t wstring_append_wstring(wstring *, const wstring *, size_t); ssize_t wstring_printf(wstring *, const wchar_t *, ...); #ifdef va_start ssize_t wstring_vprintf(wstring *, const wchar_t *, va_list); #endif +int wstring_compare(const wstring *, const wstring *); +int wstring_equal(const wstring *, const wstring *); #endif diff --git a/lib/core/_string.c b/lib/core/_string.c index f073725..211be73 100644 --- a/lib/core/_string.c +++ b/lib/core/_string.c @@ -280,3 +280,34 @@ string_vprintf(string *str, const char_t *fmt, va_list ap) str->buf[str->len] = 0; return (str->len); } + +/* + * Compare two strings, returning a negative value if the first is + * lexically less than the second, a positive value if the opposite is + * true, and zero if they are equal. + */ +int +string_compare(const string *s1, const string *s2) +{ + const char_t *p1, *p2; + + for (p1 = s1->buf, p2 = s2->buf; *p1 && *p2; ++p1, ++p2) + if (*p1 != *p2) + return (*p1 < *p2 ? -1 : 1); + return (*p1 ? 1 : *p2 ? -1 : 0); +} + +/* + * Compare two strings, returning true (non-zero) if they are equal and + * false (zero) if they are not. + */ +int +string_equal(const string *s1, const string *s2) +{ + const char_t *p1, *p2; + + for (p1 = s1->buf, p2 = s2->buf; *p1 && *p2; ++p1, ++p2) + if (*p1 != *p2) + return (0); + return (1); +} diff --git a/lib/core/wstring.c b/lib/core/wstring.c index ae8c01c..cd9f7e1 100644 --- a/lib/core/wstring.c +++ b/lib/core/wstring.c @@ -54,5 +54,7 @@ #define string_append_string wstring_append_wstring #define string_printf wstring_printf #define string_vprintf wstring_vprintf +#define string_compare wstring_compare +#define string_equal wstring_equal #include "_string.c" diff --git a/t/t__string.c b/t/t__string.c index d52ae7e..3ecb73a 100644 --- a/t/t__string.c +++ b/t/t__string.c @@ -28,7 +28,7 @@ */ static int -t_foo(char **desc CRYB_UNUSED, void *arg) +t_noop(char **desc CRYB_UNUSED, void *arg) { string *str; @@ -38,3 +38,106 @@ t_foo(char **desc CRYB_UNUSED, void *arg) string_delete(str); return (1); } + + +/*************************************************************************** + * Comparisons + */ + +static struct t_compare_case { + const char *desc; + const char_t *s1, *s2; + int cmp; +} t_compare_cases[] = { + { + "both empty", + CS(""), + CS(""), + 0, + }, + { + "empty with non-empty (left)", + CS(""), + CS("xyzzy"), + -1, + }, + { + "empty with non-empty (right)", + CS("xyzzy"), + CS(""), + 1, + }, + { + "equal non-empty", + CS("xyzzy"), + CS("xyzzy"), + 0, + }, + { + "unequal of equal length (left)", + CS("abba"), + CS("baba"), + -1, + }, + { + "unequal of equal length (right)", + CS("baba"), + CS("abba"), + 1, + }, + { + "prefix (left)", + CS("baba"), + CS("babaorum"), + -1, + }, + { + "prefix (right)", + CS("babaorum"), + CS("baba"), + 1, + }, +}; + +static int +t_compare_test(char **desc CRYB_UNUSED, void *arg) +{ + struct t_compare_case *t = arg; + string *s1, *s2; + int ret; + + if ((s1 = string_new()) == NULL || + string_append_cs(s1, t->s1, SIZE_MAX) < 0 || + (s2 = string_new()) == NULL || + string_append_cs(s2, t->s2, SIZE_MAX) < 0) + return (0); + ret = string_compare(s1, s2) == t->cmp; + string_delete(s2); + string_delete(s1); + return (ret); +} + + +/*************************************************************************** + * Boilerplate + */ + +int +t_prepare(int argc, char *argv[]) +{ + unsigned int i; + + (void)argc; + (void)argv; + + t_add_test(t_noop, NULL, "no-op"); + for (i = 0; i < sizeof t_compare_cases / sizeof *t_compare_cases; ++i) + t_add_test(t_compare_test, &t_compare_cases[i], + t_compare_cases[i].desc); + return (0); +} + +void +t_cleanup(void) +{ +} diff --git a/t/t_string.c b/t/t_string.c index 456420d..8336912 100644 --- a/t/t_string.c +++ b/t/t_string.c @@ -38,24 +38,8 @@ #include "t.h" +#define char_t char + +#define CS(lit) lit + #include "t__string.c" - - -/*************************************************************************** - * Boilerplate - */ - -int -t_prepare(int argc, char *argv[]) -{ - - (void)argc; - (void)argv; - t_add_test(t_foo, NULL, "foo"); - return (0); -} - -void -t_cleanup(void) -{ -} diff --git a/t/t_wstring.c b/t/t_wstring.c index d04ae41..c51f5ba 100644 --- a/t/t_wstring.c +++ b/t/t_wstring.c @@ -40,6 +40,7 @@ #include "t.h" #define char_t wchar_t +#define vsnprintf vswprintf #define cryb_string cryb_wstring #define string wstring @@ -55,25 +56,9 @@ #define string_append_string wstring_append_wstring #define string_printf wstring_printf #define string_vprintf wstring_vprintf +#define string_compare wstring_compare +#define string_equal wstring_equal + +#define CS(lit) L ## lit #include "t__string.c" - - -/*************************************************************************** - * Boilerplate - */ - -int -t_prepare(int argc, char *argv[]) -{ - - (void)argc; - (void)argv; - t_add_test(t_foo, NULL, "foo"); - return (0); -} - -void -t_cleanup(void) -{ -}