unsigned int *matches;
unsigned int match_count;
+ size_t match_end_pos;
+
int badtab[UCHAR_MAX+1];
int goodtab[FLEXIBLE_ARRAY_MEMBER];
};
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;
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])
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--;
}
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;
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);
#include "primes.h"
#include "priorityq.h"
#include "seq-range-array.h"
+#include "str-find.h"
#include "str-sanitize.h"
#include "utc-mktime.h"
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;
test_primes,
test_priorityq,
test_seq_range_array,
+ test_str_find,
test_str_sanitize,
test_utc_mktime,