From: Stephan Bosch Date: Fri, 2 Nov 2018 09:12:20 +0000 (+0100) Subject: lib: strfuncs: Add t_str_oneline(). X-Git-Tag: 2.3.9~1097 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8be34ea0bff4193e837f91bd73a7eda06f8fa67b;p=thirdparty%2Fdovecot%2Fcore.git lib: strfuncs: Add t_str_oneline(). This puts the string on a single line by replacing all newlines with spaces and dropping any carriage returns --- diff --git a/src/lib/strfuncs.c b/src/lib/strfuncs.c index f09782b144..4067629214 100644 --- a/src/lib/strfuncs.c +++ b/src/lib/strfuncs.c @@ -3,6 +3,7 @@ /* @UNSAFE: whole file */ #include "lib.h" +#include "str.h" #include "printf-format-fix.h" #include "strfuncs.h" #include "array.h" @@ -320,6 +321,55 @@ const char *t_str_replace(const char *str, char from, char to) return out; } +const char *t_str_oneline(const char *str) +{ + string_t *out; + size_t len; + const char *p, *pend, *poff; + bool new_line; + + if (strpbrk(str, "\r\n") == NULL) + return str; + + len = strlen(str); + out = t_str_new(len + 1); + new_line = TRUE; + p = poff = str; + pend = str + len; + while (p < pend) { + switch (*p) { + case '\r': + if (p > poff) + str_append_data(out, poff, p - poff); + /* just drop \r */ + poff = p + 1; + break; + case '\n': + if (p > poff) + str_append_data(out, poff, p - poff); + if (new_line) { + /* coalesce multiple \n into a single space */ + } else { + /* first \n after text */ + str_append_c(out, ' '); + new_line = TRUE; + } + poff = p + 1; + break; + default: + new_line = FALSE; + break; + } + p++; + } + + if (new_line && str_len(out) > 0) + str_truncate(out, str_len(out) - 1); + else if (p > poff) + str_append_data(out, poff, p - poff); + return str_c(out); +} + int i_strocpy(char *dest, const char *src, size_t dstsize) { if (dstsize == 0) diff --git a/src/lib/strfuncs.h b/src/lib/strfuncs.h index 974cd468ec..59fb0ad19b 100644 --- a/src/lib/strfuncs.h +++ b/src/lib/strfuncs.h @@ -45,6 +45,10 @@ const char *t_strconcat(const char *str1, ...) const char *t_strcut(const char *str, char cutchar); /* Replace all from->to chars in the string. */ const char *t_str_replace(const char *str, char from, char to); +/* Put the string on a single line by replacing all newlines with spaces and + dropping any carriage returns. Sequences of several newlines are merged into + one space and newlines at the beginning and end of the string are dropped. */ +const char *t_str_oneline(const char *str); /* Like strlcpy(), but return -1 if buffer was overflown, 0 if not. */ int i_strocpy(char *dest, const char *src, size_t dstsize); diff --git a/src/lib/test-strfuncs.c b/src/lib/test-strfuncs.c index d7073be9fd..a2ea307376 100644 --- a/src/lib/test-strfuncs.c +++ b/src/lib/test-strfuncs.c @@ -175,6 +175,45 @@ static void test_t_str_replace(void) test_end(); } +static void test_t_str_oneline(void) +{ + test_begin("t_str_oneline"); + test_assert(strcmp(t_str_oneline("\n"), "") == 0); + test_assert(strcmp(t_str_oneline("\r"), "") == 0); + test_assert(strcmp(t_str_oneline("\n\n"), "") == 0); + test_assert(strcmp(t_str_oneline("\r\r"), "") == 0); + test_assert(strcmp(t_str_oneline("\r\n"), "") == 0); + test_assert(strcmp(t_str_oneline("\r\n\r\n"), "") == 0); + test_assert(strcmp(t_str_oneline("\n\r"), "") == 0); + test_assert(strcmp(t_str_oneline("\n\r\n\r"), "") == 0); + test_assert(strcmp(t_str_oneline("foo"), "foo") == 0); + test_assert(strcmp(t_str_oneline("\nfoo"), "foo") == 0); + test_assert(strcmp(t_str_oneline("foo\n"), "foo") == 0); + test_assert(strcmp(t_str_oneline("\nfoo\n"), "foo") == 0); + test_assert(strcmp(t_str_oneline("foo\nbar"), "foo bar") == 0); + test_assert(strcmp(t_str_oneline("foo\n\nbar"), "foo bar") == 0); + test_assert(strcmp(t_str_oneline("\nfoo\nbar"), "foo bar") == 0); + test_assert(strcmp(t_str_oneline("foo\nbar\n"), "foo bar") == 0); + test_assert(strcmp(t_str_oneline("foo\nbar\nbaz"), "foo bar baz") == 0); + test_assert(strcmp(t_str_oneline("\rfoo"), "foo") == 0); + test_assert(strcmp(t_str_oneline("foo\r"), "foo") == 0); + test_assert(strcmp(t_str_oneline("\rfoo\r"), "foo") == 0); + test_assert(strcmp(t_str_oneline("foo\rbar"), "foobar") == 0); + test_assert(strcmp(t_str_oneline("foo\r\rbar"), "foobar") == 0); + test_assert(strcmp(t_str_oneline("\rfoo\rbar"), "foobar") == 0); + test_assert(strcmp(t_str_oneline("foo\rbar\r"), "foobar") == 0); + test_assert(strcmp(t_str_oneline("foo\rbar\rbaz"), "foobarbaz") == 0); + test_assert(strcmp(t_str_oneline("\r\nfoo\r\n"), "foo") == 0); + test_assert(strcmp(t_str_oneline("foo\r\n"), "foo") == 0); + test_assert(strcmp(t_str_oneline("\r\nfoo"), "foo") == 0); + test_assert(strcmp(t_str_oneline("foo\r\nbar"), "foo bar") == 0); + test_assert(strcmp(t_str_oneline("foo\r\n\r\nbar"), "foo bar") == 0); + test_assert(strcmp(t_str_oneline("\r\nfoo\r\nbar"), "foo bar") == 0); + test_assert(strcmp(t_str_oneline("foo\r\nbar\r\n"), "foo bar") == 0); + test_assert(strcmp(t_str_oneline("foo\r\nbar\r\nbaz"), "foo bar baz") == 0); + test_end(); +} + static void test_t_str_trim(void) { test_begin("t_str_trim"); @@ -416,6 +455,7 @@ void test_strfuncs(void) test_t_strsplit(); test_t_strsplit_spaces(); test_t_str_replace(); + test_t_str_oneline(); test_t_str_trim(); test_t_str_ltrim(); test_t_str_rtrim();