From: Timo Sirainen Date: Fri, 3 Nov 2017 23:39:38 +0000 (+0200) Subject: lib: Implement t_strsplit_tabescaped_inplace() X-Git-Tag: 2.3.0.rc1~580 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7de17a595a44e61714d3fc7e55491449d38a8e62;p=thirdparty%2Fdovecot%2Fcore.git lib: Implement t_strsplit_tabescaped_inplace() This is a more efficient version of t_strsplit_tabescaped(), which modifies the input string instead of duplicating it. --- diff --git a/src/lib/strescape.c b/src/lib/strescape.c index 0fb45cd20a..3be173291c 100644 --- a/src/lib/strescape.c +++ b/src/lib/strescape.c @@ -249,6 +249,50 @@ const char *t_str_tabunescape(const char *str) return str_tabunescape(t_strdup_noconst(str)); } +const char *const *t_strsplit_tabescaped_inplace(char *data) +{ + /* @UNSAFE */ + char **array; + unsigned int count, new_alloc_count, alloc_count; + + if (*data == '\0') + return t_new(const char *, 1); + + alloc_count = 32; + array = t_malloc_no0(sizeof(char *) * alloc_count); + + array[0] = data; count = 1; + bool need_unescape = FALSE; + while ((data = strpbrk(data, "\t\001")) != NULL) { + /* separator or escape char found */ + if (*data == '\001') { + need_unescape = TRUE; + data++; + continue; + } + if (count+1 >= alloc_count) { + new_alloc_count = nearest_power(alloc_count+1); + array = p_realloc(unsafe_data_stack_pool, array, + sizeof(char *) * alloc_count, + sizeof(char *) * + new_alloc_count); + alloc_count = new_alloc_count; + } + *data++ = '\0'; + if (need_unescape) { + str_tabunescape(array[count-1]); + need_unescape = FALSE; + } + array[count++] = data; + } + if (need_unescape) + str_tabunescape(array[count-1]); + i_assert(count < alloc_count); + array[count] = NULL; + + return (const char *const *)array; +} + char **p_strsplit_tabescaped(pool_t pool, const char *str) { char **args; diff --git a/src/lib/strescape.h b/src/lib/strescape.h index acf7cba67d..c910a26825 100644 --- a/src/lib/strescape.h +++ b/src/lib/strescape.h @@ -28,5 +28,8 @@ const char *t_str_tabunescape(const char *str); char **p_strsplit_tabescaped(pool_t pool, const char *str); const char *const *t_strsplit_tabescaped(const char *str); +/* Same as t_strsplit_tabescaped(), but the input string is modified and the + returned pointers inside the array point to the original string. */ +const char *const *t_strsplit_tabescaped_inplace(char *str); #endif diff --git a/src/lib/test-strescape.c b/src/lib/test-strescape.c index 2314956e43..07c52476b3 100644 --- a/src/lib/test-strescape.c +++ b/src/lib/test-strescape.c @@ -155,6 +155,20 @@ static void test_strsplit_tabescaped(void) test_end(); } +static void test_strsplit_tabescaped_inplace(void) +{ + const char *const *args; + + test_begin("*_strsplit_tabescaped_inplace()"); + for (unsigned int i = 0; i < N_ELEMENTS(strsplit_tests); i++) { + char *input = t_strdup_noconst(strsplit_tests[i].input); + args = t_strsplit_tabescaped_inplace(input); + for (unsigned int j = 0; strsplit_tests[i].output[j] != NULL; j++) + test_assert_idx(null_strcmp(strsplit_tests[i].output[j], args[j]) == 0, i); + } + test_end(); +} + void test_strescape(void) { strsplit_tests[0].input = t_strdup_printf("%s\t%s\t%s\t", @@ -162,4 +176,5 @@ void test_strescape(void) test_str_escape(); test_tabescape(); test_strsplit_tabescaped(); + test_strsplit_tabescaped_inplace(); }