strv: treat newlines as hard line breaks in strv_rebreak_lines()

A newline embedded in an input entry only reset the width counter and the
leading-whitespace state, but the text collected before it was never flushed.
If nothing but whitespace followed the newline, the end-of-line path then saw
that we were still in the leading whitespace and emitted an empty line,
dropping everything before the newline: "foo\n" turned into "".

Newlines also didn't start a new output entry, so returned entries could
contain newlines and be wider than the requested width, even though callers
expect one output entry per output line.

Flush the collected line at the newline instead, reusing the same logic as at
the end of the string, and treat a trailing newline as terminating the last
line rather than adding an empty one.
This commit is contained in:
Armaan Sandhu
2026-08-13 07:11:49 +09:00
committed by Yu Watanabe
parent 5dc41f8283
commit 32ac7af788
2 changed files with 78 additions and 11 deletions
+32
View File
@@ -1281,6 +1281,38 @@ TEST(strv_rebreak_lines) {
* the whitespace we broke at. */
ASSERT_ERROR(strv_rebreak_lines(STRV_MAKE("a \xF0" "b"), 3, &l), EINVAL);
ASSERT_NULL(l);
/* Newlines embedded in the input are hard line breaks. Previously everything before such a newline
* was silently dropped if nothing but whitespace followed it. */
ASSERT_OK(strv_rebreak_lines(STRV_MAKE("foo\n"), 10, &l));
ASSERT_TRUE(strv_equal(l, STRV_MAKE("foo")));
l = strv_free(l);
ASSERT_OK(strv_rebreak_lines(STRV_MAKE("foo\n "), 10, &l));
ASSERT_TRUE(strv_equal(l, STRV_MAKE("foo")));
l = strv_free(l);
ASSERT_OK(strv_rebreak_lines(STRV_MAKE("foo\nbar"), 10, &l));
ASSERT_TRUE(strv_equal(l, STRV_MAKE("foo", "bar")));
l = strv_free(l);
ASSERT_OK(strv_rebreak_lines(STRV_MAKE("foo \n bar \n"), 10, &l));
ASSERT_TRUE(strv_equal(l, STRV_MAKE("foo", " bar")));
l = strv_free(l);
ASSERT_OK(strv_rebreak_lines(STRV_MAKE("foo\n\nbar"), 10, &l));
ASSERT_TRUE(strv_equal(l, STRV_MAKE("foo", "", "bar")));
l = strv_free(l);
ASSERT_OK(strv_rebreak_lines(STRV_MAKE("foo\r\nbar\r\n"), 10, &l));
ASSERT_TRUE(strv_equal(l, STRV_MAKE("foo", "bar")));
l = strv_free(l);
/* And the resulting lines are properly broken to the requested width, rather than staying glued
* together in a single, over-long entry. */
ASSERT_OK(strv_rebreak_lines(STRV_MAKE("hello world\nfoo bar baz quux waldo"), 10, &l));
ASSERT_TRUE(strv_equal(l, STRV_MAKE("hello", "world", "foo bar", "baz quux", "waldo")));
l = strv_free(l);
}
TEST(strv_find_closest) {