summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2013-06-09 10:22:26 +0200
committerYorhel <git@yorhel.nl>2013-06-09 10:22:26 +0200
commita96bbfa5c3cfd2b1e5a4abe13e7940fa9d7e0144 (patch)
treee443e62376c10cb8b23b425be8bc12e8a54ec301
parent0fcec90516b6b8da9e128f39b15f53a139e05b4f (diff)
util/casestr: casestr_eq() -> casestr_cmp() + define some order
This makes it suitable for more use cases.
-rw-r--r--src/util/casestr.c13
-rw-r--r--src/util/casestr.h31
-rw-r--r--test/casestr.c8
3 files changed, 35 insertions, 17 deletions
diff --git a/src/util/casestr.c b/src/util/casestr.c
index dceb1f8..2f694e9 100644
--- a/src/util/casestr.c
+++ b/src/util/casestr.c
@@ -165,13 +165,14 @@ size_t casestr_len(const char *buf) {
}
-bool casestr_eq(const char *a, const char *b) {
- if(strcmp(a, b) != 0)
- return false;
+int casestr_cmp(const char *a, const char *b) {
+ int i = strcmp(a, b);
+ if(i)
+ return i;
size_t maskoff = strlen(a)+1; /* == strlen(b)+1, after the above check */
- return a[maskoff] != b[maskoff] ? false : a[maskoff]
- ? memcmp(a+maskoff, b+maskoff, casestr_masklen(a)) == 0
- : strcmp(a+maskoff, b+maskoff) == 0;
+ return a[maskoff] != b[maskoff] ? a[maskoff] - b[maskoff] : a[maskoff]
+ ? memcmp(a+maskoff, b+maskoff, casestr_masklen(a))
+ : strcmp(a+maskoff, b+maskoff);
}
diff --git a/src/util/casestr.h b/src/util/casestr.h
index daf586a..538de68 100644
--- a/src/util/casestr.h
+++ b/src/util/casestr.h
@@ -57,9 +57,9 @@ void casestr_fold(const char *str, kstring_t *dest);
*
* memcpy(.., dest.s, dest.l)
*
- * The length of the buffer does not have to be kept around, casestr_orig() can
- * work without and it and it can be obtained with casestr_len() when needed.
- */
+ * The length of the buffer does not have to be kept around, casestr_orig() and
+ * casestr_cmp() can work without and it and it can be obtained with
+ * casestr_len() when needed. */
void casestr_create(const char *str, kstring_t *dest);
@@ -72,15 +72,32 @@ void casestr_orig(const char *buf, kstring_t *dest);
size_t casestr_len(const char *buf);
-/* Compare two casestr buffers for equality. This should be equivalent to
- * checking for strcmp(a, b) == 0 after obtaining the original strings using
- * casestr_orig(), except that this function is faster.
+/* Compare two casestr buffers. This is roughly equivalent to strcmp(oa, ob)
+ * after obtaining the original strings using casestr_orig(), except that this
+ * function is faster. Note that you can only assume that casestr_cmp(a, b) ==
+ * strcmp(oa, ob) if the two strings are equal. If the strings do not casefold
+ * to the same string, then the result is equivalent to plain strcmp(a, b).
+ * Otherwise, if the strings do not have equal case, then which of the two
+ * strings is considered the largest of the two is somewhat arbitrary, but it
+ * is guaranteed to be deterministic.
+ *
+ * The above properties make this function suitable for two situations:
+ * 1. Checking whether the two strings are equivalent in a case-sensitive
+ * fashion, i.e. casestr_cmp(a, b) == 0.
+ * 2. Sorting a list of casestr buffers while ensuring that the order is
+ * deterministic even if both strings casefold to the same string. (But, of
+ * course, not necessarily when two strings compare as totally equal)
+ *
+ * This function may not really be suitable for sorting the original strings
+ * for human output. But then again, a strcmp() on the original strings likely
+ * isn't, either, since plain strcmp() doesn't understand UTF-8. You probably
+ * want a proper Unicode collation function for that.
*
* Note that two strings are NOT considered equivalent if one is represented
* with a bitmask and the other with the original string appended to it. This
* situation doesn't arise as long as both buffers were created using
* casestr_create(). */
-bool casestr_eq(const char *, const char *);
+int casestr_cmp(const char *, const char *);
#endif
/* vim: set noet sw=4 ts=4: */
diff --git a/test/casestr.c b/test/casestr.c
index ed23db9..7be4a09 100644
--- a/test/casestr.c
+++ b/test/casestr.c
@@ -32,7 +32,7 @@
assert(b.l == sizeof out - 1);\
assert(memcmp(b.s, out, b.l) == 0);\
assert(casestr_len(b.s) == b.l);\
- assert(casestr_eq(b.s, out));\
+ assert(casestr_cmp(b.s, out) == 0);\
kstring_t o = {};\
casestr_fold(in, &o);\
assert(!*in ? o.s == NULL : strcmp(o.s, b.s) == 0);\
@@ -57,9 +57,9 @@ int main(int argc, char **argv) {
T(" 月姫 ≠ вот", " 月姫 ≠ вот\0\1\0");
T("ПрогиШара", "прогишара\0\x43\0");
- assert(!casestr_eq("aaa\0aAa", "aaa\0\5"));
- assert( casestr_eq("aaa\0aaa", "aaa\0aaa"));
- assert(!casestr_eq("прогишара\0\x43\0", "прогишара\0\x43\1"));
+ assert(casestr_cmp("aaa\0aAa", "aaa\0\5") > 0);
+ assert(casestr_cmp("aaa\0aaa", "aaa\0aaa") == 0);
+ assert(casestr_cmp("прогишара\0\x43\0", "прогишара\0\x43\1") < 0);
return 0;
}