diff --git a/include/ucore/dstr.h b/include/ucore/dstr.h new file mode 100644 index 0000000..083de2f --- /dev/null +++ b/include/ucore/dstr.h @@ -0,0 +1,162 @@ +#ifndef UC_DSTR_H_ +#define UC_DSTR_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** A managed C-string, using dynalically allocated memory for the string. + * + * The .str member might not always be nul terminated, + * Normally, use uc_dstr_str() to retreive the managed string + * instead of accessing ->str directly. + * + * Normally, let the DSTR manage the nul terminator as manually adding + * a nul byte and potintially adding more data to the DStr would append + * it after that nul terminator. + */ +struct DStr { + /** Length of the managed string.*/ + size_t len; + + //internal fields: + size_t allocated; + char *str; +}; + +#define UC_DSTR_STATIC_INIT {0, 0, NULL} + +/** Initialize a DStr. + * Note that str->str will be NULL after initialization. + * + */ +void uc_dstr_init(struct DStr *str); + +/** Destroy/free the string. + * (Frees str->str, not str itself) + */ +void uc_dstr_destroy(struct DStr *str); + +/** Copy a DStr + * + * @param dest destination string to copy to, must not contain an existing string + * @param src DStr to copy + * + * @return 0 if success, != 0 if allocation fails + */ +int uc_dstr_copy(struct DStr *dest, const struct DStr *src); + +/** + * @return the available/unused tail bytes in the string. + */ +size_t uc_dstr_available(const struct DStr *str); + +/** Ensure the DStr have room for least 'len' bytes, + * allocating room if needed. + * + * This includes the length of the existing string, + * to ensure e.g an additional 10 bytes can be appended, + * one would do uc_dstr_ensure(str, str->len + 10) + * + * @return 0 on success (!= 0 if an allocation fail) + */ +int uc_dstr_ensure(struct DStr *str, size_t total); + +/** Reset the DStr, setting its length to 0 + */ +void uc_dstr_reset(struct DStr *str); + +/** nul terminate the DStr */ +void uc_dstr_terminate(struct DStr *str); + +/** Retreive the managed string, the returned string + * is always nul terminated. The DStr will still be managing + * the returned char *. + */ +char *uc_dstr_str(struct DStr *str); + +/** Reserve len bytes for appending to the dstr + * you must fill in a string in the 0-len range of + * the returned pointer. + * + * @param len bytes to reseve + * @return poiinter to the start of the data to append + */ +char *uc_dstr_put(struct DStr *str, size_t len); + +/** Append a string, filtering out characters. + * e.g. pass in the ctype.h isdigit as the is_x function + * to append only the digits in the supplied string. + * + * @param s string to append + * @param is_x ctype.h compatible function to use as a filter. + * @return number of chars appended + */ +size_t uc_dstr_put_str_filter(struct DStr *str, const char *s, int (*is_x)(int c)); + +/* Append a string of the give size. + * (The nul terminator is not appended) + * + * @param s string to append + * @param len bytes to append (not including the nul terminator) + * @return 0 on success (!= 0 if an allocation fail) + */ +int uc_dstr_put_str_sz(struct DStr *str, const char *s, size_t len); + +/* Append a string. + * (The nul terminator is not appended) + * + * @return 0 on success (!= 0 if an allocation fail) + */ +int uc_dstr_put_str(struct DStr *str, const char *s); + +/* Append a single char. + * + * @return 0 on success (!= 0 if an allocation fail) + */ +int uc_dstr_put_char(struct DStr *str, char c); + +/* Make the DStr take ownership of the given dynamically allocated string. + * Any existing string in the DStr is freed. + */ +void uc_dstr_own(struct DStr *str, char *s); + +/** Release the managed string. + * The caller is now responsible for managing/free'ing the returned string. + * The DStr is considered empty afterwards. + * + * @return The dynamically allocated string that was managed. + */ +char *uc_dstr_steal(struct DStr *str); + +/** Swap the A and B DStr */ +void uc_str_swap(struct DStr *a, struct DStr *b); + +/** Replace all occurences in the DStr + * (This may be used to replace any embedded nul bytes too) + * + * @param f char to find + * @param r char to replace with + */ +size_t uc_dstr_replace(struct DStr *str, char f, char r); + +/** Remove leading and trailing spaces in the DStr + * Spaces are the ascii ones: " \t\r\v\t\n" + */ +void uc_dstr_trim(struct DStr *str); + +/** Append formatted string (just as sprintf)*/ +int uc_dstr_sprintf(struct DStr *str, const char *fmt, ...) __attribute__((format(printf,2,3))); + +/** va_list variant */ +int uc_dstr_vsprintf(struct DStr *str, const char *fmt, va_list ap_)__attribute__((format(printf,2,0))); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/include/ucore/heapsort.h b/include/ucore/heapsort.h new file mode 100644 index 0000000..fcaf426 --- /dev/null +++ b/include/ucore/heapsort.h @@ -0,0 +1,30 @@ +#ifndef UC_HEAPSORT_H_ +#define UC_HEAPSORT_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif +///compare function. Needs only to return < 0 if +//a is less tan b +typedef int (*uc_hs_cmp)(const void *a, const void *b, void *cookie); +//swap function, must swap around element a and b +typedef void (*uc_hs_swp)(void *a, void *b); + +/** Sort an array. + * @param base start of array + * @param count number of elements in array + * @param width size of each element + * @param cmp compare function + * @param swap swap function + * @param cookie user pointer passed back to compare function + */ +void uc_heapsort(void *base, size_t count, size_t width, + uc_hs_cmp cmp, uc_hs_swp swap, void *cookie); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/ucore/utils.h b/include/ucore/utils.h index f3bedef..39db850 100644 --- a/include/ucore/utils.h +++ b/include/ucore/utils.h @@ -14,15 +14,15 @@ //MAX of a and b #define UC_MAX(a,b) \ - ({ __typeof__ (a) _a = (a); \ - __typeof__ (b) _b = (b); \ - _a > _b ? _a : _b; }) + ({ __typeof__ (a) _amx = (a); \ + __typeof__ (b) _bmx = (b); \ + _amx > _bmx ? _amx : _bmx; }) //min of a and b #define UC_MIN(a,b) \ - ({ __typeof__ (a) _a = (a); \ - __typeof__ (b) _b = (b); \ - _a < _b ? _a : _b; }) + ({ __typeof__ (a) _amn = (a); \ + __typeof__ (b) _bmn = (b); \ + _amn < _bmn ? _amn : _bmn; }) #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a)) diff --git a/src/buffer.c b/src/buffer.c index e8c96a3..4a27e57 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -3,6 +3,7 @@ #include #include #include "ucore/buffer.h" +#include "ucore/utils.h" GBuf* uc_new_gbuf(size_t initsz) @@ -48,7 +49,7 @@ uc_gbuf_append(GBuf *buf,const void *data,size_t len) unsigned char *gbuf; if (buf->len - buf->used < len) - if (uc_gbuf_grow(buf, len + len/2)) + if (uc_gbuf_grow(buf, len + UC_MAX(UC_MIN(8U,len/2),256U))) return -1; gbuf = buf->buf; diff --git a/src/dstr.c b/src/dstr.c new file mode 100644 index 0000000..9c64fa2 --- /dev/null +++ b/src/dstr.c @@ -0,0 +1,281 @@ +#include +#include +#include +#include +#include "ucore/dstr.h" +#include "ucore/utils.h" + +void uc_dstr_init(struct DStr *str) +{ + str->len = 0; + str->allocated = 0; + str->str = NULL; +} + +void uc_dstr_destroy(struct DStr *str) +{ + free(str->str); +} + +int uc_dstr_copy(struct DStr *dest, const struct DStr *src) +{ + char *s; + + uc_dstr_init(dest); + if (src->allocated == 0) { + return 0; + } + + s = uc_dstr_put(dest, src->len); + if (s == NULL) { + return -1; + } + + //+1 to copy a potential nul terminator, uc_dstr_put + //guarantees we have room for it. + memcpy(s, src->str, UC_MIN(src->len + 1, src->allocated)); + + return 0; +} + +size_t uc_dstr_available(const struct DStr *str) +{ + return str->allocated - str->len; +} + +int uc_dstr_ensure(struct DStr *str, size_t total) +{ + if (str->allocated < total) { + //allocate a minimum no. of bytes, and one + //additional for the common case of nul terminating + //the string + size_t new_len = UC_MAX(7U, total) + 1; + char *new_str = realloc(str->str, new_len); + + if (new_str == NULL) { + return -1; + } + str->str = new_str; + str->allocated = new_len; + } + + return 0; +} + +void uc_dstr_reset(struct DStr *str) +{ + str->len = 0; + if (str->str) { + str->str[0] = 0; + } +} + +void uc_dstr_terminate(struct DStr *str) +{ + uc_dstr_ensure(str, str->len + 1); + str->str[str->len] = 0; +} + +char *uc_dstr_str(struct DStr *str) +{ + uc_dstr_terminate(str); + + return str->str; +} + +char *uc_dstr_put(struct DStr *str, size_t len) +{ + char *start; + + if (uc_dstr_ensure(str, str->len + len) != 0) { + return NULL; + } + + start = str->str + str->len; + str->len += len; + + return start; +} + +size_t uc_dstr_put_str_filter(struct DStr *str, const char *s, int (*is_x)(int c)) +{ + size_t len = strlen(s); + size_t i; + size_t idx = 0; + + if (uc_dstr_ensure(str, str->len + len) != 0) { + return 0; + } + + for (i = 0; i < len; i++) { + if (is_x(s[i])) { + str->str[str->len + idx]= s[i]; + idx++; + } + } + + str->len += idx; + + return idx; +} + +int uc_dstr_put_str_sz(struct DStr *str, const char *s, size_t len) +{ + char *start = uc_dstr_put(str, len); + + if (start == NULL) { + return -1; + } + memcpy(start, s, len); + + return 0; +} + +int uc_dstr_put_str(struct DStr *str, const char *s) +{ + size_t len = strlen(s); + + return uc_dstr_put_str_sz(str, s ,len); +} + +int uc_dstr_put_char(struct DStr *str, char c) +{ + char *start = uc_dstr_put(str, 1); + + if (start == NULL) { + return -1; + } + *start = c; + + return 0; +} + +void uc_dstr_own(struct DStr *str, char *s) +{ + size_t len = strlen(s); + + if (str->str) { + free(str); + } + + str->len = len; + str->allocated = len + 1; + str->str = s; +} + +char *uc_dstr_steal(struct DStr *str) +{ + char *s = str->str; + + uc_dstr_init(str); + + return s; +} + +void uc_str_swap(struct DStr *a, struct DStr *b) +{ + struct DStr tmp; + + tmp = *a; + *a = *b; + *b = tmp; +} + +size_t uc_dstr_replace(struct DStr *str, char f, char r) +{ + size_t i; + size_t count = 0; + + if (str->len == 0) { + return 0; + } + + for (i = 0; i < str->len; i++) { + if (str->str[i] == f) { + str->str[i] = r; + count++; + } + } + + return count; +} + +void uc_dstr_trim(struct DStr *str) +{ + size_t spaces; + + uc_dstr_terminate(str); + + //spaces at the start + spaces = strspn(str->str, " \t\n\v\f\r"); + if (spaces > 0) { + memmove(str->str, str->str + spaces, str->len - spaces); + str->len -= spaces; + } + + //spaces at the end + if (str->len > 0) { + size_t idx = str->len - 1; + do { + if (strchr(" \t\n\v\f\r", str->str[idx]) == NULL) { + break; + } else { + str->len--; + idx--; + } + } while (idx != 0); + } +} + +int uc_dstr_sprintf(struct DStr *str, const char *fmt, ...) +{ + va_list ap; + int rc; + + va_start(ap, fmt); + rc = uc_dstr_vsprintf(str, fmt, ap); + va_end(ap); + + return rc; +} + +int uc_dstr_vsprintf(struct DStr *str, const char *fmt, va_list ap_) +{ + va_list ap; + int rc; + int available; + int needed; + + rc = uc_dstr_ensure(str, str->len + 1); + if (rc != 0) { + return -1; + } + + available = uc_dstr_available(str); + + va_copy(ap, ap_); + needed = vsnprintf(str->str + str->len, available, fmt, ap); + va_end(ap); + + if (needed <= 0) { + return needed; + } + + if (needed >= available) { + rc = uc_dstr_ensure(str, str->len + needed); + if (rc != 0) { + return -1; + } + + available = uc_dstr_available(str); + + va_copy(ap, ap_); + needed = vsnprintf(str->str + str->len, available, fmt, ap); + va_end(ap); + } + + str->len += needed; + + return needed; +} + diff --git a/src/fd_utils.c b/src/fd_utils.c index e557f60..e14fb12 100644 --- a/src/fd_utils.c +++ b/src/fd_utils.c @@ -89,14 +89,8 @@ int uc_set_ip_dscp(int fd, unsigned int dscp) int val; //only 6 bits for dscp - if (dscp > 63) { - errno = EINVAL; - return -1; - } - - val = dscp << 2; + val = (dscp & 0x3f) << 2; return setsockopt(fd, IPPROTO_IP, IP_TOS, &val, sizeof val); } - diff --git a/src/heapsort.c b/src/heapsort.c new file mode 100644 index 0000000..45a56e5 --- /dev/null +++ b/src/heapsort.c @@ -0,0 +1,53 @@ +#include +#include "ucore/heapsort.h" + +static void +uc_sift(unsigned char *base, size_t start, size_t count, size_t width, + uc_hs_cmp cmp, uc_hs_swp swap, void *cookie) +{ + size_t root = start, child; + + while ((root * 2 + 1) < count) { + child = root * 2 + 1; + if (child < (count - 1)) { + int rc = cmp(&base[child * width], &base[(child + 1) * width], cookie); + if (rc < 0) { + child++; + } + } + + if (cmp(&base[root * width], &base[child * width], cookie) < 0) { + swap(base + root * width, base + child * width); + root = child; + } else { + return; + } + } +} + +void +uc_heapsort(void *base_, size_t count, size_t width, + uc_hs_cmp cmp, uc_hs_swp swap, void *cookie) +{ + long start; + long end; + unsigned char *base = base_; + + if (count == 0 || width == 0) { + return; + } + + start = count / 2 - 1, + end = count - 1; + + while (start >= 0) { + uc_sift(base, start, count, width, cmp, swap, cookie); + start--; + } + + while (end > 0) { + swap(base + end * width, base); + uc_sift(base, 0, end, width, cmp, swap, cookie); + end--; + } +} diff --git a/test/test_dstr.c b/test/test_dstr.c new file mode 100644 index 0000000..6168e98 --- /dev/null +++ b/test/test_dstr.c @@ -0,0 +1,186 @@ +#include +#include +#include +#include + + +START_TEST (test_dstr_basics) + struct DStr str; + int rc; + + char *s; + + uc_dstr_init(&str); + rc = uc_dstr_put_str(&str, "Hello"); + ck_assert_int_eq(rc, 0); + ck_assert_int_eq(str.len, 5); + ck_assert_str_eq(uc_dstr_str(&str), "Hello"); + + rc = uc_dstr_put_char(&str, '!'); + ck_assert_int_eq(rc, 0); + ck_assert_int_eq(str.len, 6); + ck_assert_str_eq(uc_dstr_str(&str), "Hello!"); + + rc = uc_dstr_put_str_sz(&str, " World 12345678", 13); + ck_assert_int_eq(rc, 0); + ck_assert_int_eq(str.len, 19); + ck_assert_str_eq(uc_dstr_str(&str), "Hello! World 123456"); + + uc_dstr_reset(&str); + ck_assert_int_eq(str.len, 0); + ck_assert_str_eq(uc_dstr_str(&str), ""); + + uc_dstr_reset(&str); + ck_assert_int_gt(uc_dstr_available(&str), 0); + + s = uc_dstr_put(&str, 2); + fail_if(s == NULL); + s[0] = '1'; + s[1] = '2'; + + ck_assert_str_eq(uc_dstr_str(&str), "12"); + + uc_dstr_destroy(&str); + + //just test that this doesn't crash: + uc_dstr_init(&str); + uc_dstr_destroy(&str); +END_TEST + +START_TEST (test_dstr_own_steal) + struct DStr str; + char *s; + + uc_dstr_init(&str); + uc_dstr_own(&str, strdup("Hello !")); + ck_assert_int_eq(str.len, 7); + ck_assert_str_eq(uc_dstr_str(&str), "Hello !"); + + s = uc_dstr_steal(&str); + ck_assert_str_eq(s, "Hello !"); + ck_assert_int_eq(str.len, 0); + ck_assert_str_eq(uc_dstr_str(&str), ""); + + free(s); + uc_dstr_destroy(&str); +END_TEST + +START_TEST (test_dstr_trim) + struct DStr str = UC_DSTR_STATIC_INIT; + + uc_dstr_put_str(&str, " \t \nHello !\r\n"); + uc_dstr_trim(&str); + ck_assert_str_eq(uc_dstr_str(&str), "Hello !"); + + uc_dstr_destroy(&str); + uc_dstr_init(&str); + + uc_dstr_put_str(&str, " "); + + uc_dstr_trim(&str); + ck_assert_str_eq(uc_dstr_str(&str), ""); + + uc_dstr_destroy(&str); + uc_dstr_init(&str); + + uc_dstr_trim(&str); + ck_assert_str_eq(uc_dstr_str(&str), ""); + + uc_dstr_destroy(&str); + +END_TEST + +START_TEST (test_dstr_replace) + struct DStr str; + size_t rc; + + uc_dstr_init(&str); + uc_dstr_put_str(&str, "-1-2-3-4-5-"); + rc = uc_dstr_replace(&str, '-',' '); + ck_assert_int_eq(rc, 6); + + ck_assert_str_eq(uc_dstr_str(&str), " 1 2 3 4 5 "); + rc = uc_dstr_replace(&str, 'X','2'); + ck_assert_int_eq(rc, 0); + ck_assert_str_eq(uc_dstr_str(&str), " 1 2 3 4 5 "); + + uc_dstr_destroy(&str); + +END_TEST + +START_TEST (test_dstr_filter) + struct DStr str; + size_t rc; + + uc_dstr_init(&str); + uc_dstr_put_str(&str, "AB:"); + rc = uc_dstr_put_str_filter(&str, "1:2,3 4 ", isdigit); + ck_assert_int_eq(rc, 4); + + ck_assert_str_eq(uc_dstr_str(&str), "AB:1234"); + + uc_dstr_destroy(&str); + +END_TEST + +START_TEST (test_dstr_sprintf) + struct DStr str; + size_t rc; + + uc_dstr_init(&str); + rc = uc_dstr_sprintf(&str, "%d-%d-%d", 1, 2, 3); + ck_assert_int_gt(rc, 0); + ck_assert_str_eq(uc_dstr_str(&str), "1-2-3"); + + rc = uc_dstr_sprintf(&str, " Another, bigger %s.", "string"); + ck_assert_int_gt(rc, 0); + ck_assert_str_eq(uc_dstr_str(&str), "1-2-3 Another, bigger string."); + + uc_dstr_destroy(&str); + +END_TEST + +START_TEST (test_dstr_copy) + struct DStr str; + struct DStr copy; + size_t rc; + + uc_dstr_init(&str); + rc = uc_dstr_put_str(&str, "123"); + ck_assert_int_eq(rc, 0); + + rc = uc_dstr_copy(©, &str); + ck_assert_int_eq(rc, 0); + ck_assert_str_eq(uc_dstr_str(©), uc_dstr_str(&str)); + + uc_dstr_destroy(&str); + uc_dstr_destroy(©); + uc_dstr_init(&str); + uc_dstr_init(©); + + rc = uc_dstr_copy(©, &str); + ck_assert_int_eq(rc, 0); + ck_assert_str_eq(uc_dstr_str(©), ""); + + uc_dstr_destroy(&str); + uc_dstr_destroy(©); + +END_TEST + +Suite *dstr_suite(void) +{ + Suite *s = suite_create("dstr"); + TCase *tc = tcase_create("dstr tests"); + tcase_add_test(tc, test_dstr_basics); + tcase_add_test(tc, test_dstr_own_steal); + tcase_add_test(tc, test_dstr_trim); + tcase_add_test(tc, test_dstr_replace); + tcase_add_test(tc, test_dstr_filter); + tcase_add_test(tc, test_dstr_sprintf); + tcase_add_test(tc, test_dstr_copy); + + suite_add_tcase(s, tc); + + return s; +} + diff --git a/test/test_heapsort.c b/test/test_heapsort.c new file mode 100644 index 0000000..9635e56 --- /dev/null +++ b/test/test_heapsort.c @@ -0,0 +1,140 @@ +#include +#include +#include + +struct Stuff { + char text[11]; + int order; +}; + +static void swap_stuff(void *a_, void *b_) +{ + struct Stuff *a = a_; + struct Stuff *b = b_; + struct Stuff tmp; + + tmp = *a; + *a = *b; + *b = tmp; +} + +static int cmp_stuff(const void *a_, const void *b_, void *cookie) +{ + const struct Stuff *a = a_; + const struct Stuff *b = b_; + (void)cookie; + if (a->order < b->order) + return -1; + + return 1; +} + +void print_stuff(const struct Stuff *s, size_t len) +{ + size_t i; + for(i = 0; i < len; i++) { + printf("%s:%d\n", s[i].text, s[i].order); + } +} + +static int cmp_stuff_array(const struct Stuff *a, const struct Stuff *b, size_t len) +{ + size_t i; + for (i = 0; i < len; i++) { + if (strcmp(a[i].text, b[i].text) != 0) + return -1; + if (a[i].order != b[i].order) + return -1; + } + + return 0; +} + +START_TEST (test_heapsort_odd) + struct Stuff unordered[] = { + {"2", 2}, + {"1", 1}, + {"4", 4}, + {"5", 5}, + {"3", 3}, + }; + + struct Stuff ordered[] = { + {"1", 1}, + {"2", 2}, + {"3", 3}, + {"4", 4}, + {"5", 5}, + }; + + uc_heapsort(unordered, ARRAY_SIZE(unordered), sizeof(struct Stuff), + cmp_stuff, swap_stuff, NULL); + print_stuff(unordered, ARRAY_SIZE(unordered)); + fail_if(cmp_stuff_array(unordered, ordered, ARRAY_SIZE(unordered)) != 0); +END_TEST + +START_TEST (test_heapsort_even) + struct Stuff unordered[] = { + {"1", 1}, + {"7", 7}, + {"3", 3}, + {"4", 4}, + {"6", 6}, + {"2", 2}, + }; + + struct Stuff ordered[] = { + {"1", 1}, + {"2", 2}, + {"3", 3}, + {"4", 4}, + {"6", 6}, + {"7", 7}, + }; + + uc_heapsort(unordered, ARRAY_SIZE(unordered), sizeof(struct Stuff), + cmp_stuff, swap_stuff, NULL); + fail_if(cmp_stuff_array(unordered, ordered, ARRAY_SIZE(unordered)) != 0); +END_TEST + +START_TEST (test_heapsort_zero) + struct Stuff unordered[] = { + {"1", 1}, + {"7", 7}, + {"3", 3}, + {"4", 4}, + {"6", 6}, + {"2", 2}, + }; + + struct Stuff same[] = { + {"1", 1}, + {"7", 7}, + {"3", 3}, + {"4", 4}, + {"6", 6}, + {"2", 2}, + }; + + uc_heapsort(unordered, 0, sizeof(struct Stuff), + cmp_stuff, swap_stuff, NULL); + fail_if(cmp_stuff_array(unordered, same, ARRAY_SIZE(unordered)) != 0); + + uc_heapsort(unordered, ARRAY_SIZE(unordered), 0, + cmp_stuff, swap_stuff, NULL); + fail_if(cmp_stuff_array(unordered, same, ARRAY_SIZE(unordered)) != 0); +END_TEST + +Suite *heapsort_suite(void) +{ + Suite *s = suite_create("heapsort"); + TCase *tc = tcase_create("heapsort tests"); + tcase_add_test(tc, test_heapsort_odd); + tcase_add_test(tc, test_heapsort_even); + tcase_add_test(tc, test_heapsort_zero); + + suite_add_tcase(s, tc); + + return s; +} + diff --git a/test/test_runner.c b/test/test_runner.c index a797d5f..5c09bb3 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -27,6 +27,8 @@ extern Suite *sprintb_suite(void); extern Suite *strv_suite(void); extern Suite *ratelimit_suite(void); extern Suite *htable_suite(void); +extern Suite *heapsort_suite(void); +extern Suite *dstr_suite(void); static suite_func suites[] = { bitvec_suite, @@ -48,7 +50,9 @@ static suite_func suites[] = { ratelimit_suite, htable_suite, clock_suite, - threadqueue_suite + threadqueue_suite, + heapsort_suite, + dstr_suite }; int