]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: strfuncs: Add t_str_oneline().
authorStephan Bosch <stephan.bosch@dovecot.fi>
Fri, 2 Nov 2018 09:12:20 +0000 (10:12 +0100)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Tue, 6 Nov 2018 22:42:30 +0000 (22:42 +0000)
This puts the string on a single line by replacing all newlines with spaces and
dropping any carriage returns

src/lib/strfuncs.c
src/lib/strfuncs.h
src/lib/test-strfuncs.c

index f09782b14475db3210843bc402737792961285d3..406762921444fbeeb962501cca2955e22ab57e4b 100644 (file)
@@ -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)
index 974cd468ecf34b4839640d7f122782de9f93eecc..59fb0ad19bf849c62fdaa65daeb362d9aba69783 100644 (file)
@@ -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);
index d7073be9fd54a68b80961493a0210b2882d0fecd..a2ea3073768eab0c21bb0aa3b2bfb9f31420fe1f 100644 (file)
@@ -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();