Skip to content

Commit a83ddbb

Browse files
committed
Fix handling of chomp with paragraph separator
Try to mirror IO behavior, where chomp takes out the entire paragraph separators between entries, but does not chomp a single line separator at the end of the string. Partially Fixes [Bug #18768]
1 parent 1edc885 commit a83ddbb

File tree

2 files changed

+27
-24
lines changed

2 files changed

+27
-24
lines changed

ext/stringio/stringio.c

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,6 +1204,7 @@ strio_getline(struct getline_arg *arg, struct StringIO *ptr)
12041204
str = strio_substr(ptr, ptr->pos, e - s - w, enc);
12051205
}
12061206
else if ((n = RSTRING_LEN(str)) == 0) {
1207+
const char *paragraph_end = NULL;
12071208
p = s;
12081209
while (p[(p + 1 < e) && (*p == '\r') && 0] == '\n') {
12091210
p += *p == '\r';
@@ -1213,19 +1214,21 @@ strio_getline(struct getline_arg *arg, struct StringIO *ptr)
12131214
}
12141215
s = p;
12151216
while ((p = memchr(p, '\n', e - p)) && (p != e)) {
1216-
if (*++p == '\n') {
1217-
e = p + 1;
1218-
w = (arg->chomp ? 1 : 0);
1219-
break;
1220-
}
1221-
else if (*p == '\r' && p < e && p[1] == '\n') {
1222-
e = p + 2;
1223-
w = (arg->chomp ? 2 : 0);
1224-
break;
1225-
}
1217+
p++;
1218+
if (!((p < e && *p == '\n') ||
1219+
(p + 1 < e && *p == '\r' && *(p+1) == '\n'))) {
1220+
continue;
1221+
}
1222+
paragraph_end = p - ((*(p-2) == '\r') ? 2 : 1);
1223+
while ((p < e && *p == '\n') ||
1224+
(p + 1 < e && *p == '\r' && *(p+1) == '\n')) {
1225+
p += (*p == '\r') ? 2 : 1;
1226+
}
1227+
e = p;
1228+
break;
12261229
}
1227-
if (!w && arg->chomp) {
1228-
w = chomp_newline_width(s, e);
1230+
if (arg->chomp && paragraph_end) {
1231+
w = e - paragraph_end;
12291232
}
12301233
str = strio_substr(ptr, s - RSTRING_PTR(ptr->string), e - s - w, enc);
12311234
}

test/stringio/test_stringio.rb

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,10 @@ def test_gets_chomp
9393
assert_equal("a", StringIO.new("a\nb").gets(chomp: true))
9494
assert_equal("abc", StringIO.new("abc\n\ndef\n").gets(chomp: true))
9595
assert_equal("abc\n\ndef\n", StringIO.new("abc\n\ndef\n").gets(nil, chomp: true))
96-
assert_equal("abc\n", StringIO.new("abc\n\ndef\n").gets("", chomp: true))
96+
assert_equal("abc", StringIO.new("abc\n\ndef\n").gets("", chomp: true))
9797
stringio = StringIO.new("abc\n\ndef\n")
98-
assert_equal("abc\n", stringio.gets("", chomp: true))
99-
assert_equal("def", stringio.gets("", chomp: true))
98+
assert_equal("abc", stringio.gets("", chomp: true))
99+
assert_equal("def\n", stringio.gets("", chomp: true))
100100

101101
assert_string("", Encoding::UTF_8, StringIO.new("\n").gets(chomp: true))
102102
end
@@ -110,10 +110,10 @@ def test_gets_chomp_eol
110110
assert_equal("a", StringIO.new("a\r\nb").gets(chomp: true))
111111
assert_equal("abc", StringIO.new("abc\r\n\r\ndef\r\n").gets(chomp: true))
112112
assert_equal("abc\r\n\r\ndef\r\n", StringIO.new("abc\r\n\r\ndef\r\n").gets(nil, chomp: true))
113-
assert_equal("abc\r\n", StringIO.new("abc\r\n\r\ndef\r\n").gets("", chomp: true))
113+
assert_equal("abc", StringIO.new("abc\r\n\r\ndef\r\n").gets("", chomp: true))
114114
stringio = StringIO.new("abc\r\n\r\ndef\r\n")
115-
assert_equal("abc\r\n", stringio.gets("", chomp: true))
116-
assert_equal("def", stringio.gets("", chomp: true))
115+
assert_equal("abc", stringio.gets("", chomp: true))
116+
assert_equal("def\r\n", stringio.gets("", chomp: true))
117117
end
118118

119119
def test_readlines
@@ -596,15 +596,15 @@ def test_each
596596
assert_equal(["foo\n", "bar\n", "baz\n"], f.each.to_a)
597597
f.rewind
598598
assert_equal(["foo", "bar", "baz"], f.each(chomp: true).to_a)
599-
f = StringIO.new("foo\nbar\n\nbaz\n")
600-
assert_equal(["foo\nbar\n\n", "baz\n"], f.each("").to_a)
599+
f = StringIO.new("foo\nbar\n\n\nbaz\n")
600+
assert_equal(["foo\nbar\n\n\n", "baz\n"], f.each("").to_a)
601601
f.rewind
602-
assert_equal(["foo\nbar\n", "baz"], f.each("", chomp: true).to_a)
602+
assert_equal(["foo\nbar", "baz\n"], f.each("", chomp: true).to_a)
603603

604-
f = StringIO.new("foo\r\nbar\r\n\r\nbaz\r\n")
605-
assert_equal(["foo\r\nbar\r\n\r\n", "baz\r\n"], f.each("").to_a)
604+
f = StringIO.new("foo\r\nbar\r\n\r\n\r\nbaz\r\n")
605+
assert_equal(["foo\r\nbar\r\n\r\n\r\n", "baz\r\n"], f.each("").to_a)
606606
f.rewind
607-
assert_equal(["foo\r\nbar\r\n", "baz"], f.each("", chomp: true).to_a)
607+
assert_equal(["foo\r\nbar", "baz\r\n"], f.each("", chomp: true).to_a)
608608

609609
f = StringIO.new("abc\n\ndef\n")
610610
assert_equal(["ab", "c\n", "\nd", "ef", "\n"], f.each(nil, 2, chomp: true).to_a)

0 commit comments

Comments
 (0)