summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--include/libwapcaplet/libwapcaplet.h75
-rw-r--r--src/libwapcaplet.c23
-rw-r--r--test/basictests.c124
4 files changed, 143 insertions, 81 deletions
diff --git a/Makefile b/Makefile
index 9525989..8bcb977 100644
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@
# Component settings
COMPONENT := wapcaplet
-COMPONENT_VERSION := 0.4.0
+COMPONENT_VERSION := 0.4.3
# Default to a static library
COMPONENT_TYPE ?= lib-static
diff --git a/include/libwapcaplet/libwapcaplet.h b/include/libwapcaplet/libwapcaplet.h
index d8cc841..57e2e48 100644
--- a/include/libwapcaplet/libwapcaplet.h
+++ b/include/libwapcaplet/libwapcaplet.h
@@ -133,7 +133,17 @@ extern lwc_error lwc_string_tolower(lwc_string *str, lwc_string **ret);
* @note Use this if copying the string and intending both sides to retain
* ownership.
*/
+#if defined(STMTEXPR)
#define lwc_string_ref(str) ({lwc_string *__lwc_s = (str); assert(__lwc_s != NULL); __lwc_s->refcnt++; __lwc_s;})
+#else
+static inline lwc_string *
+lwc_string_ref(lwc_string *str)
+{
+ assert(str != NULL);
+ str->refcnt++;
+ return str;
+}
+#endif
/**
* Release a reference on an lwc_string.
@@ -177,6 +187,21 @@ extern void lwc_string_destroy(lwc_string *str);
((*(ret) = ((str1) == (str2))), lwc_error_ok)
/**
+ * Intern a caseless copy of the passed string.
+ *
+ * @param str The string to intern the caseless copy of.
+ *
+ * @return lwc_error_ok if successful, otherwise the
+ * error code describing the issue.,
+ *
+ * @note This is for "internal" use by the caseless comparison
+ * macro and not for users.
+ */
+extern lwc_error
+lwc__intern_caseless_string(lwc_string *str);
+
+#if defined(STMTEXPR)
+/**
* Check if two interned strings are case-insensitively equal.
*
* @param _str1 The first string in the comparison.
@@ -202,19 +227,37 @@ extern void lwc_string_destroy(lwc_string *str);
__lwc_err; \
})
+#else
/**
- * Intern a caseless copy of the passed string.
- *
- * @param str The string to intern the caseless copy of.
- *
- * @return lwc_error_ok if successful, otherwise the
- * error code describing the issue.,
+ * Check if two interned strings are case-insensitively equal.
*
- * @note This is for "internal" use by the caseless comparison
- * macro and not for users.
- */
-extern lwc_error
-lwc__intern_caseless_string(lwc_string *str);
+ * @param str1 The first string in the comparison.
+ * @param str2 The second string in the comparison.
+ * @param ret A pointer to a boolean to be filled out with the result.
+ * @return Result of operation, if not ok then value pointed to by \a ret will
+ * not be valid.
+ */
+static inline lwc_error
+lwc_string_caseless_isequal(lwc_string *str1, lwc_string *str2, bool *ret)
+{
+ lwc_error err = lwc_error_ok;
+ if (str1->insensitive == NULL) {
+ err = lwc__intern_caseless_string(str1);
+ }
+ if (err == lwc_error_ok && str2->insensitive == NULL) {
+ err = lwc__intern_caseless_string(str2);
+ }
+ if (err == lwc_error_ok)
+ *ret = (str1->insensitive == str2->insensitive);
+ return err;
+}
+#endif
+
+#if defined(STMTEXPR)
+#define lwc__assert_and_expr(str, expr) ({assert(str != NULL); expr;})
+#else
+#define lwc__assert_and_expr(str, expr) (expr)
+#endif
/**
* Retrieve the data pointer for an interned string.
@@ -228,7 +271,7 @@ lwc__intern_caseless_string(lwc_string *str);
* in future. Any code relying on it currently should be
* modified to use ::lwc_string_length if possible.
*/
-#define lwc_string_data(str) ({assert(str != NULL); (const char *)((str)+1);})
+#define lwc_string_data(str) lwc__assert_and_expr(str, (const char *)((str)+1))
/**
* Retrieve the data length for an interned string.
@@ -236,7 +279,7 @@ lwc__intern_caseless_string(lwc_string *str);
* @param str The string to retrieve the length of.
* @return The length of \a str.
*/
-#define lwc_string_length(str) ({assert(str != NULL); (str)->len;})
+#define lwc_string_length(str) lwc__assert_and_expr(str, (str)->len)
/**
* Retrieve (or compute if unavailable) a hash value for the content of the string.
@@ -250,7 +293,7 @@ lwc__intern_caseless_string(lwc_string *str);
* to be stable between invocations of the program. Never use the hash
* value as a way to directly identify the value of the string.
*/
-#define lwc_string_hash_value(str) ({assert(str != NULL); (str)->hash;})
+#define lwc_string_hash_value(str) lwc__assert_and_expr(str, (str)->hash)
/**
* Retrieve a hash value for the caseless content of the string.
@@ -278,6 +321,10 @@ static inline lwc_error lwc_string_caseless_hash_value(
/**
* Iterate the context and return every string in it.
*
+ * If there are no strings found in the context, then this has the
+ * side effect of removing the global context which will reduce the
+ * chances of false-positives on leak checkers.
+ *
* @param cb The callback to give the string to.
* @param pw The private word for the callback.
*/
diff --git a/src/libwapcaplet.c b/src/libwapcaplet.c
index 9521e96..34a72cd 100644
--- a/src/libwapcaplet.c
+++ b/src/libwapcaplet.c
@@ -47,7 +47,7 @@ static lwc_context *ctx = NULL;
typedef lwc_hash (*lwc_hasher)(const char *, size_t);
typedef int (*lwc_strncmp)(const char *, const char *, size_t);
-typedef void (*lwc_memcpy)(char *, const char *, size_t);
+typedef void * (*lwc_memcpy)(void * restrict, const void * restrict, size_t);
static lwc_error
lwc__initialise(void)
@@ -238,12 +238,17 @@ lwc__lcase_strncmp(const char *s1, const char *s2, size_t n)
return 0;
}
-static void
-lwc__lcase_memcpy(char *target, const char *source, size_t n)
+static void *
+lwc__lcase_memcpy(void *restrict _target, const void *restrict _source, size_t n)
{
+ char *restrict target = _target;
+ const char *restrict source = _source;
+
while (n--) {
*target++ = lwc__dolower(*source++);
}
+
+ return _target;
}
lwc_error
@@ -266,12 +271,22 @@ lwc_iterate_strings(lwc_iteration_callback_fn cb, void *pw)
{
lwc_hash n;
lwc_string *str;
+ bool found = false;
if (ctx == NULL)
return;
for (n = 0; n < ctx->bucketcount; ++n) {
- for (str = ctx->buckets[n]; str != NULL; str = str->next)
+ for (str = ctx->buckets[n]; str != NULL; str = str->next) {
+ found = true;
cb(str, pw);
+ }
+ }
+
+ if (found == false) {
+ /* We found no strings, so remove the global context. */
+ free(ctx->buckets);
+ free(ctx);
+ ctx = NULL;
}
}
diff --git a/test/basictests.c b/test/basictests.c
index 7711da7..48b9beb 100644
--- a/test/basictests.c
+++ b/test/basictests.c
@@ -43,7 +43,7 @@ END_TEST
START_TEST (test_lwc_intern_substring_aborts2)
{
lwc_string *str;
- fail_unless(lwc_intern_string("Jam", 3, &str) == lwc_error_ok,
+ ck_assert_msg(lwc_intern_string("Jam", 3, &str) == lwc_error_ok,
"unable to intern 'Jam'");
lwc_intern_substring(str, 88, 77, null_lwc_p);
@@ -59,7 +59,7 @@ END_TEST
START_TEST (test_lwc_string_tolower_aborts2)
{
lwc_string *str;
- fail_unless(lwc_intern_string("Badger", 6, &str) == lwc_error_ok,
+ ck_assert_msg(lwc_intern_string("Badger", 6, &str) == lwc_error_ok,
"unable to intern 'Badger'");
lwc_string_tolower(str, null_lwc_p);
@@ -115,9 +115,9 @@ with_simple_context_teardown(void)
START_TEST (test_lwc_intern_string_ok)
{
lwc_string *str = NULL;
- fail_unless(lwc_intern_string("A", 1, &str) == lwc_error_ok,
+ ck_assert_msg(lwc_intern_string("A", 1, &str) == lwc_error_ok,
"Unable to intern a simple string");
- fail_unless(str != NULL,
+ ck_assert_msg(str != NULL,
"Returned OK but str was still NULL");
}
END_TEST
@@ -125,13 +125,13 @@ END_TEST
START_TEST (test_lwc_intern_string_twice_ok)
{
lwc_string *str1 = NULL, *str2 = NULL;
- fail_unless(lwc_intern_string("A", 1, &str1) == lwc_error_ok,
+ ck_assert_msg(lwc_intern_string("A", 1, &str1) == lwc_error_ok,
"Unable to intern a simple string");
- fail_unless(str1 != NULL,
+ ck_assert_msg(str1 != NULL,
"Returned OK but str was still NULL");
- fail_unless(lwc_intern_string("B", 1, &str2) == lwc_error_ok,
+ ck_assert_msg(lwc_intern_string("B", 1, &str2) == lwc_error_ok,
"Unable to intern a simple string");
- fail_unless(str2 != NULL,
+ ck_assert_msg(str2 != NULL,
"Returned OK but str was still NULL");
}
END_TEST
@@ -139,13 +139,13 @@ END_TEST
START_TEST (test_lwc_intern_string_twice_same_ok)
{
lwc_string *str1 = NULL, *str2 = NULL;
- fail_unless(lwc_intern_string("A", 1, &str1) == lwc_error_ok,
+ ck_assert_msg(lwc_intern_string("A", 1, &str1) == lwc_error_ok,
"Unable to intern a simple string");
- fail_unless(str1 != NULL,
+ ck_assert_msg(str1 != NULL,
"Returned OK but str was still NULL");
- fail_unless(lwc_intern_string("A", 1, &str2) == lwc_error_ok,
+ ck_assert_msg(lwc_intern_string("A", 1, &str2) == lwc_error_ok,
"Unable to intern a simple string");
- fail_unless(str2 != NULL,
+ ck_assert_msg(str2 != NULL,
"Returned OK but str was still NULL");
}
END_TEST
@@ -157,18 +157,18 @@ static lwc_string *intern_one = NULL, *intern_two = NULL, *intern_three = NULL,
static void
with_filled_context_setup(void)
{
- fail_unless(lwc_intern_string("one", 3, &intern_one) == lwc_error_ok,
+ ck_assert_msg(lwc_intern_string("one", 3, &intern_one) == lwc_error_ok,
"Unable to intern 'one'");
- fail_unless(lwc_intern_string("two", 3, &intern_two) == lwc_error_ok,
+ ck_assert_msg(lwc_intern_string("two", 3, &intern_two) == lwc_error_ok,
"Unable to intern 'two'");
- fail_unless(lwc_intern_string("three", 5, &intern_three) == lwc_error_ok,
+ ck_assert_msg(lwc_intern_string("three", 5, &intern_three) == lwc_error_ok,
"Unable to intern 'three'");
- fail_unless(lwc_intern_string("YAY", 3, &intern_YAY) == lwc_error_ok,
+ ck_assert_msg(lwc_intern_string("YAY", 3, &intern_YAY) == lwc_error_ok,
"Unable to intern 'YAY'");
- fail_unless(intern_one != intern_two, "'one' == 'two'");
- fail_unless(intern_one != intern_three, "'one' == 'three'");
- fail_unless(intern_two != intern_three, "'two' == 'three'");
+ ck_assert_msg(intern_one != intern_two, "'one' == 'two'");
+ ck_assert_msg(intern_one != intern_three, "'one' == 'three'");
+ ck_assert_msg(intern_two != intern_three, "'two' == 'three'");
}
static void
@@ -185,10 +185,10 @@ START_TEST (test_lwc_interning_works)
{
lwc_string *new_one = NULL;
- fail_unless(lwc_intern_string("one", 3, &new_one) == lwc_error_ok,
+ ck_assert_msg(lwc_intern_string("one", 3, &new_one) == lwc_error_ok,
"Unable to re-intern 'one'");
- fail_unless(new_one == intern_one,
+ ck_assert_msg(new_one == intern_one,
"Internalising of the string failed");
}
END_TEST
@@ -197,12 +197,12 @@ START_TEST (test_lwc_intern_substring)
{
lwc_string *new_hre = NULL, *sub_hre = NULL;
- fail_unless(lwc_intern_string("hre", 3, &new_hre) == lwc_error_ok,
+ ck_assert_msg(lwc_intern_string("hre", 3, &new_hre) == lwc_error_ok,
"Unable to intern 'hre'");
- fail_unless(lwc_intern_substring(intern_three,
+ ck_assert_msg(lwc_intern_substring(intern_three,
1, 3, &sub_hre) == lwc_error_ok,
"Unable to re-intern 'hre' by substring");
- fail_unless(new_hre == sub_hre,
+ ck_assert_msg(new_hre == sub_hre,
"'hre' != 'hre' -- wow!");
}
END_TEST
@@ -211,7 +211,7 @@ START_TEST (test_lwc_intern_substring_bad_offset)
{
lwc_string *str;
- fail_unless(lwc_intern_substring(intern_three, 100, 1, &str) == lwc_error_range,
+ ck_assert_msg(lwc_intern_substring(intern_three, 100, 1, &str) == lwc_error_range,
"Able to intern substring starting out of range");
}
END_TEST
@@ -220,14 +220,14 @@ START_TEST (test_lwc_intern_substring_bad_size)
{
lwc_string *str;
- fail_unless(lwc_intern_substring(intern_three, 1, 100, &str) == lwc_error_range,
+ ck_assert_msg(lwc_intern_substring(intern_three, 1, 100, &str) == lwc_error_range,
"Able to intern substring ending out of range");
}
END_TEST
START_TEST (test_lwc_string_ref_ok)
{
- fail_unless(lwc_string_ref(intern_one) == intern_one,
+ ck_assert_msg(lwc_string_ref(intern_one) == intern_one,
"Oddly, reffing a string didn't return it");
}
END_TEST
@@ -249,9 +249,9 @@ END_TEST
START_TEST (test_lwc_string_isequal_ok)
{
bool result = true;
- fail_unless((lwc_string_isequal(intern_one, intern_two, &result)) == lwc_error_ok,
+ ck_assert_msg((lwc_string_isequal(intern_one, intern_two, &result)) == lwc_error_ok,
"Failure comparing 'one' and 'two'");
- fail_unless(result == false,
+ ck_assert_msg(result == false,
"'one' == 'two' ?!");
}
END_TEST
@@ -261,16 +261,16 @@ START_TEST (test_lwc_string_caseless_isequal_ok1)
bool result = true;
lwc_string *new_ONE;
- fail_unless(lwc_intern_string("ONE", 3, &new_ONE) == lwc_error_ok,
+ ck_assert_msg(lwc_intern_string("ONE", 3, &new_ONE) == lwc_error_ok,
"Failure interning 'ONE'");
- fail_unless((lwc_string_isequal(intern_one, new_ONE, &result)) == lwc_error_ok);
- fail_unless(result == false,
+ ck_assert((lwc_string_isequal(intern_one, new_ONE, &result)) == lwc_error_ok);
+ ck_assert_msg(result == false,
"'one' == 'ONE' ?!");
- fail_unless((lwc_string_caseless_isequal(intern_one, new_ONE, &result)) == lwc_error_ok,
+ ck_assert_msg((lwc_string_caseless_isequal(intern_one, new_ONE, &result)) == lwc_error_ok,
"Failure comparing 'one' and 'ONE' caselessly");
- fail_unless(result == true,
+ ck_assert_msg(result == true,
"'one' !~= 'ONE' ?!");
}
END_TEST
@@ -280,16 +280,16 @@ START_TEST (test_lwc_string_caseless_isequal_ok2)
bool result = true;
lwc_string *new_yay;
- fail_unless(lwc_intern_string("yay", 3, &new_yay) == lwc_error_ok,
+ ck_assert_msg(lwc_intern_string("yay", 3, &new_yay) == lwc_error_ok,
"Failure interning 'yay'");
- fail_unless((lwc_string_isequal(intern_YAY, new_yay, &result)) == lwc_error_ok);
- fail_unless(result == false,
+ ck_assert((lwc_string_isequal(intern_YAY, new_yay, &result)) == lwc_error_ok);
+ ck_assert_msg(result == false,
"'yay' == 'YAY' ?!");
- fail_unless((lwc_string_caseless_isequal(intern_YAY, new_yay, &result)) == lwc_error_ok,
+ ck_assert_msg((lwc_string_caseless_isequal(intern_YAY, new_yay, &result)) == lwc_error_ok,
"Failure comparing 'yay' and 'YAY' caselessly");
- fail_unless(result == true,
+ ck_assert_msg(result == true,
"'yay' !~= 'YAY' ?!");
}
END_TEST
@@ -298,16 +298,16 @@ START_TEST (test_lwc_string_caseless_isequal_bad)
{
bool result = true;
- fail_unless(lwc_string_caseless_isequal(intern_YAY, intern_one, &result) == lwc_error_ok,
+ ck_assert_msg(lwc_string_caseless_isequal(intern_YAY, intern_one, &result) == lwc_error_ok,
"Failure comparing 'YAY' and 'one' caselessly");
- fail_unless(result == false,
+ ck_assert_msg(result == false,
"'YAY' ~= 'one' ?!");
}
END_TEST
START_TEST (test_lwc_extract_data_ok)
{
- fail_unless(memcmp("one",
+ ck_assert_msg(memcmp("one",
lwc_string_data(intern_one),
lwc_string_length(intern_one)) == 0,
"Extracting data ptr etc failed");
@@ -324,10 +324,10 @@ START_TEST (test_lwc_string_is_nul_terminated)
{
lwc_string *new_ONE;
- fail_unless(lwc_intern_string("ONE", 3, &new_ONE) == lwc_error_ok,
+ ck_assert_msg(lwc_intern_string("ONE", 3, &new_ONE) == lwc_error_ok,
"Failure interning 'ONE'");
- fail_unless(lwc_string_data(new_ONE)[lwc_string_length(new_ONE)] == '\0',
+ ck_assert_msg(lwc_string_data(new_ONE)[lwc_string_length(new_ONE)] == '\0',
"Interned string isn't NUL terminated");
}
END_TEST
@@ -337,13 +337,13 @@ START_TEST (test_lwc_substring_is_nul_terminated)
lwc_string *new_ONE;
lwc_string *new_O;
- fail_unless(lwc_intern_string("ONE", 3, &new_ONE) == lwc_error_ok,
+ ck_assert_msg(lwc_intern_string("ONE", 3, &new_ONE) == lwc_error_ok,
"Failure interning 'ONE'");
- fail_unless(lwc_intern_substring(new_ONE, 0, 1, &new_O) == lwc_error_ok,
+ ck_assert_msg(lwc_intern_substring(new_ONE, 0, 1, &new_O) == lwc_error_ok,
"Failure interning substring 'O'");
- fail_unless(lwc_string_data(new_O)[lwc_string_length(new_O)] == '\0',
+ ck_assert_msg(lwc_string_data(new_O)[lwc_string_length(new_O)] == '\0',
"Interned substring isn't NUL terminated");
}
END_TEST
@@ -354,13 +354,13 @@ START_TEST (test_lwc_string_tolower_ok1)
lwc_string *new_ONE;
lwc_string *new_one;
- fail_unless(lwc_intern_string("ONE", 3, &new_ONE) == lwc_error_ok,
+ ck_assert_msg(lwc_intern_string("ONE", 3, &new_ONE) == lwc_error_ok,
"Failure interning 'ONE'");
- fail_unless(lwc_string_tolower(new_ONE, &new_one) == lwc_error_ok);
- fail_unless(lwc_string_isequal(intern_one, new_ONE, &result) == lwc_error_ok);
- fail_unless(result == false, "'one' == 'ONE' ?!");
- fail_unless(lwc_string_isequal(intern_one, new_one, &result) == lwc_error_ok);
- fail_unless(result == true, "'one' != 'one' ?!");
+ ck_assert(lwc_string_tolower(new_ONE, &new_one) == lwc_error_ok);
+ ck_assert(lwc_string_isequal(intern_one, new_ONE, &result) == lwc_error_ok);
+ ck_assert_msg(result == false, "'one' == 'ONE' ?!");
+ ck_assert(lwc_string_isequal(intern_one, new_one, &result) == lwc_error_ok);
+ ck_assert_msg(result == true, "'one' != 'one' ?!");
}
END_TEST
@@ -370,16 +370,16 @@ START_TEST (test_lwc_string_tolower_ok2)
lwc_string *new_ONE;
lwc_string *new_one;
- fail_unless(lwc_intern_string("ONE", 3, &new_ONE) == lwc_error_ok,
+ ck_assert_msg(lwc_intern_string("ONE", 3, &new_ONE) == lwc_error_ok,
"Failure interning 'ONE'");
/* Ensure new_ONE has an insensitive pointer set */
- fail_unless(lwc_string_caseless_isequal(intern_one, new_ONE, &result) == lwc_error_ok);
- fail_unless(result == true, "'one' != 'ONE' (caseless) ?!");
- fail_unless(lwc_string_tolower(new_ONE, &new_one) == lwc_error_ok);
- fail_unless(lwc_string_isequal(intern_one, new_ONE, &result) == lwc_error_ok);
- fail_unless(result == false, "'one' == 'ONE' ?!");
- fail_unless(lwc_string_isequal(intern_one, new_one, &result) == lwc_error_ok);
- fail_unless(result == true, "'one' != 'one' ?!");
+ ck_assert(lwc_string_caseless_isequal(intern_one, new_ONE, &result) == lwc_error_ok);
+ ck_assert_msg(result == true, "'one' != 'ONE' (caseless) ?!");
+ ck_assert(lwc_string_tolower(new_ONE, &new_one) == lwc_error_ok);
+ ck_assert(lwc_string_isequal(intern_one, new_ONE, &result) == lwc_error_ok);
+ ck_assert_msg(result == false, "'one' == 'ONE' ?!");
+ ck_assert(lwc_string_isequal(intern_one, new_one, &result) == lwc_error_ok);
+ ck_assert_msg(result == true, "'one' != 'one' ?!");
}
END_TEST
@@ -395,7 +395,7 @@ START_TEST (test_lwc_string_iteration)
{
int counter = 0;
lwc_iterate_strings(counting_cb, (void*)&counter);
- fail_unless(counter == 4, "Incorrect string count");
+ ck_assert_msg(counter == 4, "Incorrect string count");
}
END_TEST