Skip to content

Commit fd8dd71

Browse files
casperisfinebyroot
authored andcommitted
Implement StringIO#pread (#56)
Both for being closer to real IOs and also because it's a convenient API in multithreaded scenarios. Co-authored-by: Jean Boussier <[email protected]>
1 parent 201fd57 commit fd8dd71

File tree

2 files changed

+62
-0
lines changed

2 files changed

+62
-0
lines changed

ext/stringio/stringio.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1583,6 +1583,48 @@ strio_read(int argc, VALUE *argv, VALUE self)
15831583
return str;
15841584
}
15851585

1586+
/*
1587+
* call-seq:
1588+
* pread(maxlen, offset) -> string
1589+
* pread(maxlen, offset, out_string) -> string
1590+
*
1591+
* See IO#pread.
1592+
*/
1593+
static VALUE
1594+
strio_pread(int argc, VALUE *argv, VALUE self)
1595+
{
1596+
VALUE rb_len, rb_offset, rb_buf;
1597+
rb_scan_args(argc, argv, "21", &rb_len, &rb_offset, &rb_buf);
1598+
long len = NUM2LONG(rb_len);
1599+
long offset = NUM2LONG(rb_offset);
1600+
1601+
if (len < 0) {
1602+
rb_raise(rb_eArgError, "negative string size (or size too big): %" PRIsVALUE, rb_len);
1603+
}
1604+
1605+
if (offset < 0) {
1606+
rb_syserr_fail_str(EINVAL, rb_sprintf("pread: Invalid offset argument: %" PRIsVALUE, rb_offset));
1607+
}
1608+
1609+
struct StringIO *ptr = readable(self);
1610+
1611+
if (offset >= RSTRING_LEN(ptr->string)) {
1612+
rb_eof_error();
1613+
}
1614+
1615+
if (NIL_P(rb_buf)) {
1616+
return strio_substr(ptr, offset, len, rb_ascii8bit_encoding());
1617+
}
1618+
1619+
long rest = RSTRING_LEN(ptr->string) - offset;
1620+
if (len > rest) len = rest;
1621+
rb_str_resize(rb_buf, len);
1622+
rb_enc_associate(rb_buf, rb_ascii8bit_encoding());
1623+
MEMCPY(RSTRING_PTR(rb_buf), RSTRING_PTR(ptr->string) + offset, char, len);
1624+
return rb_buf;
1625+
}
1626+
1627+
15861628
/*
15871629
* call-seq:
15881630
* strio.sysread(integer[, outbuf]) -> string
@@ -1843,6 +1885,7 @@ Init_stringio(void)
18431885
rb_define_method(StringIO, "gets", strio_gets, -1);
18441886
rb_define_method(StringIO, "readlines", strio_readlines, -1);
18451887
rb_define_method(StringIO, "read", strio_read, -1);
1888+
rb_define_method(StringIO, "pread", strio_pread, -1);
18461889

18471890
rb_define_method(StringIO, "write", strio_write_m, -1);
18481891
rb_define_method(StringIO, "putc", strio_putc, 1);

test/stringio/test_stringio.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,25 @@ def test_sysread
729729
assert_equal Encoding::ASCII_8BIT, f.sysread(3).encoding
730730
end
731731

732+
def test_pread
733+
f = StringIO.new("pread")
734+
f.read
735+
736+
assert_equal "pre".b, f.pread(3, 0)
737+
assert_equal "read".b, f.pread(4, 1)
738+
assert_equal Encoding::ASCII_8BIT, f.pread(4, 1).encoding
739+
740+
buf = "".b
741+
f.pread(3, 0, buf)
742+
assert_equal "pre".b, buf
743+
f.pread(4, 1, buf)
744+
assert_equal "read".b, buf
745+
746+
assert_raise(EOFError) { f.pread(1, 5) }
747+
assert_raise(ArgumentError) { f.pread(-1, 0) }
748+
assert_raise(Errno::EINVAL) { f.pread(3, -1) }
749+
end
750+
732751
def test_size
733752
f = StringIO.new("1234")
734753
assert_equal(4, f.size)

0 commit comments

Comments
 (0)