From: Timo Sirainen Date: Tue, 31 Mar 2009 21:34:28 +0000 (-0400) Subject: Added str_find_get_match_end_pos(). Added unit testing. X-Git-Tag: 2.0.alpha1~1038^2~5 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=49a7e4dba84bbf35d82669d1ae79ad43949eed19;p=thirdparty%2Fdovecot%2Fcore.git Added str_find_get_match_end_pos(). Added unit testing. --HG-- branch : HEAD --- diff --git a/src/lib/str-find.c b/src/lib/str-find.c index effd88ecc6..66b8cd33b0 100644 --- a/src/lib/str-find.c +++ b/src/lib/str-find.c @@ -13,6 +13,8 @@ struct str_find_context { unsigned int *matches; unsigned int match_count; + size_t match_end_pos; + int badtab[UCHAR_MAX+1]; int goodtab[FLEXIBLE_ARRAY_MEMBER]; }; @@ -79,6 +81,8 @@ struct str_find_context *str_find_init(pool_t pool, const char *key) struct str_find_context *ctx; unsigned int key_len = strlen(key); + i_assert(key_len > 0); + ctx = p_malloc(pool, sizeof(struct str_find_context) + sizeof(ctx->goodtab[0]) * key_len); ctx->pool = pool; @@ -118,8 +122,10 @@ bool str_find_more(struct str_find_context *ctx, break; } - if (a == key_len) + if (a == key_len) { + ctx->match_end_pos = key_len - ctx->matches[i]; return TRUE; + } } else { for (b = 0; b < size; b++) { if (ctx->key[a+b] != data[b]) @@ -140,8 +146,10 @@ bool str_find_more(struct str_find_context *ctx, while (j + key_len <= size) { i = key_len - 1; while (ctx->key[i] == data[i + j]) { - if (i == 0) + if (i == 0) { + ctx->match_end_pos = j + key_len; return TRUE; + } i--; } @@ -163,6 +171,11 @@ bool str_find_more(struct str_find_context *ctx, return FALSE; } +size_t str_find_get_match_end_pos(struct str_find_context *ctx) +{ + return ctx->match_end_pos; +} + void str_find_reset(struct str_find_context *ctx) { ctx->match_count = 0; diff --git a/src/lib/str-find.h b/src/lib/str-find.h index 2c9bf0ce37..9ab8f37830 100644 --- a/src/lib/str-find.h +++ b/src/lib/str-find.h @@ -10,6 +10,9 @@ void str_find_deinit(struct str_find_context **ctx); blocks and have the key still match. */ bool str_find_more(struct str_find_context *ctx, const unsigned char *data, size_t size); +/* After str_find_more() has returned TRUE, this function returns the end + position in the previous data block where the key had matched. */ +size_t str_find_get_match_end_pos(struct str_find_context *ctx); /* Reset input data. The next str_find_more() call won't try to match the key to earlier data. */ void str_find_reset(struct str_find_context *ctx); diff --git a/src/tests/test-lib.c b/src/tests/test-lib.c index ad35496f68..f937fc7623 100644 --- a/src/tests/test-lib.c +++ b/src/tests/test-lib.c @@ -10,6 +10,7 @@ #include "primes.h" #include "priorityq.h" #include "seq-range-array.h" +#include "str-find.h" #include "str-sanitize.h" #include "utc-mktime.h" @@ -725,6 +726,86 @@ static void test_seq_range_array(void) test_seq_range_array_random(); } +static const char *str_find_text = "xababcd"; + +static bool test_str_find_substring(const char *key, int expected_pos) +{ + const unsigned char *text = (const unsigned char *)str_find_text; + const unsigned int text_len = strlen(str_find_text); + struct str_find_context *ctx; + unsigned int i, j, pos, max, offset; + bool ret; + + ctx = str_find_init(pool_datastack_create(), key); + /* divide text into every possible block combination and test that + it matches */ + max = 1 << (text_len-1); + for (i = 0; i < max; i++) { + str_find_reset(ctx); + pos = 0; offset = 0; ret = FALSE; + for (j = 0; j < text_len; j++) { + if ((i & (1 << j)) != 0) { + if (str_find_more(ctx, text+pos, j-pos+1)) { + ret = TRUE; + break; + } + offset += j-pos + 1; + pos = j + 1; + } + } + if (pos != text_len && !ret) { + if (str_find_more(ctx, text+pos, j-pos)) + ret = TRUE; + } + if (expected_pos < 0) { + if (ret) + return FALSE; + } else { + if (!ret) + return FALSE; + + pos = str_find_get_match_end_pos(ctx) + + offset - strlen(key); + if ((int)pos != expected_pos) + return FALSE; + } + } + return TRUE; +} + +struct str_find_input { + const char *str; + int pos; +}; +static void test_str_find(void) +{ + static const char *fail_input[] = { + "xabc", + "xabd", + "abd" + }; + unsigned int idx, len; + const char *key, *p; + unsigned int i; + bool success = TRUE; + + for (idx = 0; idx < strlen(str_find_text); idx++) { + for (len = strlen(str_find_text)-idx; len > 0; len--) { + /* we'll get a search key for all substrings of text */ + T_BEGIN { + key = t_strndup(str_find_text + idx, len); + p = strstr(str_find_text, key); + success = test_str_find_substring(key, p - str_find_text); + } T_END; + if (!success) + break; + } + } + for (i = 0; i < N_ELEMENTS(fail_input) && success; i++) + success = test_str_find_substring(fail_input[i], -1); + test_out("str_find()", success); +} + struct str_sanitize_input { const char *str; unsigned int max_len; @@ -832,6 +913,7 @@ int main(void) test_primes, test_priorityq, test_seq_range_array, + test_str_find, test_str_sanitize, test_utc_mktime,