Skip to content

Commit 779f713

Browse files
committed
NULL StringIO by StringIO.new(nil)
1 parent 86e4a96 commit 779f713

File tree

2 files changed

+34
-15
lines changed

2 files changed

+34
-15
lines changed

ext/stringio/stringio.c

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ static long strio_write(VALUE self, VALUE str);
4848

4949
#define IS_STRIO(obj) (rb_typeddata_is_kind_of((obj), &strio_data_type))
5050
#define error_inval(msg) (rb_syserr_fail(EINVAL, msg))
51-
#define get_enc(ptr) ((ptr)->enc ? (ptr)->enc : rb_enc_get((ptr)->string))
51+
#define get_enc(ptr) ((ptr)->enc ? (ptr)->enc : !NIL_P((ptr)->string) ? rb_enc_get((ptr)->string) : NULL)
5252

5353
static struct StringIO *
5454
strio_alloc(void)
@@ -281,13 +281,13 @@ strio_init(int argc, VALUE *argv, struct StringIO *ptr, VALUE self)
281281

282282
argc = rb_scan_args(argc, argv, "02:", &string, &vmode, &opt);
283283
rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &ptr->flags, &convconfig);
284-
if (argc) {
284+
if (!NIL_P(string)) {
285285
StringValue(string);
286286
}
287-
else {
287+
else if (!argc) {
288288
string = rb_enc_str_new("", 0, rb_default_external_encoding());
289289
}
290-
if (OBJ_FROZEN_RAW(string)) {
290+
if (!NIL_P(string) && OBJ_FROZEN_RAW(string)) {
291291
if (ptr->flags & FMODE_WRITABLE) {
292292
rb_syserr_fail(EACCES, 0);
293293
}
@@ -297,11 +297,11 @@ strio_init(int argc, VALUE *argv, struct StringIO *ptr, VALUE self)
297297
ptr->flags |= FMODE_WRITABLE;
298298
}
299299
}
300-
if (ptr->flags & FMODE_TRUNC) {
300+
if (!NIL_P(string) && (ptr->flags & FMODE_TRUNC)) {
301301
rb_str_resize(string, 0);
302302
}
303303
RB_OBJ_WRITE(self, &ptr->string, string);
304-
if (argc == 1) {
304+
if (argc == 1 && !NIL_P(string)) {
305305
ptr->enc = rb_enc_get(string);
306306
}
307307
else {
@@ -595,6 +595,7 @@ static struct StringIO *
595595
strio_to_read(VALUE self)
596596
{
597597
struct StringIO *ptr = readable(self);
598+
if (NIL_P(ptr->string)) return NULL;
598599
if (ptr->pos < RSTRING_LEN(ptr->string)) return ptr;
599600
return NULL;
600601
}
@@ -872,7 +873,7 @@ strio_getc(VALUE self)
872873
int len;
873874
char *p;
874875

875-
if (pos >= RSTRING_LEN(str)) {
876+
if (NIL_P(str) || pos >= RSTRING_LEN(str)) {
876877
return Qnil;
877878
}
878879
p = RSTRING_PTR(str)+pos;
@@ -893,7 +894,7 @@ strio_getbyte(VALUE self)
893894
{
894895
struct StringIO *ptr = readable(self);
895896
int c;
896-
if (ptr->pos >= RSTRING_LEN(ptr->string)) {
897+
if (NIL_P(ptr->string) || ptr->pos >= RSTRING_LEN(ptr->string)) {
897898
return Qnil;
898899
}
899900
c = RSTRING_PTR(ptr->string)[ptr->pos++];
@@ -931,6 +932,7 @@ strio_ungetc(VALUE self, VALUE c)
931932
rb_encoding *enc, *enc2;
932933

933934
check_modifiable(ptr);
935+
if (NIL_P(ptr->string)) return Qnil;
934936
if (NIL_P(c)) return Qnil;
935937
if (RB_INTEGER_TYPE_P(c)) {
936938
int len, cc = NUM2INT(c);
@@ -968,6 +970,7 @@ strio_ungetbyte(VALUE self, VALUE c)
968970
struct StringIO *ptr = readable(self);
969971

970972
check_modifiable(ptr);
973+
if (NIL_P(ptr->string)) return Qnil;
971974
if (NIL_P(c)) return Qnil;
972975
if (RB_INTEGER_TYPE_P(c)) {
973976
/* rb_int_and() not visible from exts */
@@ -1171,7 +1174,7 @@ prepare_getline_args(struct StringIO *ptr, struct getline_arg *arg, int argc, VA
11711174
if (!NIL_P(lim)) limit = NUM2LONG(lim);
11721175
break;
11731176
}
1174-
if (!NIL_P(rs)) {
1177+
if (!NIL_P(ptr->string) && !NIL_P(rs)) {
11751178
rb_encoding *enc_rs, *enc_io;
11761179
enc_rs = rb_enc_get(rs);
11771180
enc_io = get_enc(ptr);
@@ -1226,7 +1229,7 @@ strio_getline(struct getline_arg *arg, struct StringIO *ptr)
12261229
long w = 0;
12271230
rb_encoding *enc = get_enc(ptr);
12281231

1229-
if (ptr->pos >= (n = RSTRING_LEN(ptr->string))) {
1232+
if (NIL_P(ptr->string) || ptr->pos >= (n = RSTRING_LEN(ptr->string))) {
12301233
return Qnil;
12311234
}
12321235
s = RSTRING_PTR(ptr->string);
@@ -1323,6 +1326,7 @@ strio_gets(int argc, VALUE *argv, VALUE self)
13231326
VALUE str;
13241327

13251328
if (prepare_getline_args(ptr, &arg, argc, argv)->limit == 0) {
1329+
if (NIL_P(ptr->string)) return Qnil;
13261330
return rb_enc_str_new(0, 0, get_enc(ptr));
13271331
}
13281332

@@ -1437,6 +1441,7 @@ strio_write(VALUE self, VALUE str)
14371441
if (!RB_TYPE_P(str, T_STRING))
14381442
str = rb_obj_as_string(str);
14391443
enc = get_enc(ptr);
1444+
if (!enc) return 0;
14401445
enc2 = rb_enc_get(str);
14411446
if (enc != enc2 && enc != ascii8bit && enc != (usascii = rb_usascii_encoding())) {
14421447
VALUE converted = rb_str_conv_enc(str, enc2, enc);
@@ -1509,10 +1514,12 @@ strio_putc(VALUE self, VALUE ch)
15091514

15101515
check_modifiable(ptr);
15111516
if (RB_TYPE_P(ch, T_STRING)) {
1517+
if (NIL_P(ptr->string)) return ch;
15121518
str = rb_str_substr(ch, 0, 1);
15131519
}
15141520
else {
15151521
char c = NUM2CHR(ch);
1522+
if (NIL_P(ptr->string)) return ch;
15161523
str = rb_str_new(&c, 1);
15171524
}
15181525
strio_write(self, str);
@@ -1555,7 +1562,8 @@ strio_read(int argc, VALUE *argv, VALUE self)
15551562
if (len < 0) {
15561563
rb_raise(rb_eArgError, "negative length %ld given", len);
15571564
}
1558-
if (len > 0 && ptr->pos >= RSTRING_LEN(ptr->string)) {
1565+
if (len > 0 &&
1566+
(NIL_P(ptr->string) || ptr->pos >= RSTRING_LEN(ptr->string))) {
15591567
if (!NIL_P(str)) rb_str_resize(str, 0);
15601568
return Qnil;
15611569
}
@@ -1564,6 +1572,7 @@ strio_read(int argc, VALUE *argv, VALUE self)
15641572
}
15651573
/* fall through */
15661574
case 0:
1575+
if (NIL_P(ptr->string)) return Qnil;
15671576
len = RSTRING_LEN(ptr->string);
15681577
if (len <= ptr->pos) {
15691578
rb_encoding *enc = get_enc(ptr);
@@ -1733,7 +1742,7 @@ strio_size(VALUE self)
17331742
{
17341743
VALUE string = StringIO(self)->string;
17351744
if (NIL_P(string)) {
1736-
rb_raise(rb_eIOError, "not opened");
1745+
return INT2FIX(0);
17371746
}
17381747
return ULONG2NUM(RSTRING_LEN(string));
17391748
}
@@ -1750,10 +1759,12 @@ strio_truncate(VALUE self, VALUE len)
17501759
{
17511760
VALUE string = writable(self)->string;
17521761
long l = NUM2LONG(len);
1753-
long plen = RSTRING_LEN(string);
1762+
long plen;
17541763
if (l < 0) {
17551764
error_inval("negative length");
17561765
}
1766+
if (NIL_P(string)) return 0;
1767+
plen = RSTRING_LEN(string);
17571768
rb_str_resize(string, l);
17581769
if (plen < l) {
17591770
MEMZERO(RSTRING_PTR(string) + plen, char, l - plen);
@@ -1824,7 +1835,7 @@ strio_set_encoding(int argc, VALUE *argv, VALUE self)
18241835
}
18251836
}
18261837
ptr->enc = enc;
1827-
if (WRITABLE(self)) {
1838+
if (!NIL_P(ptr->string) && WRITABLE(self)) {
18281839
rb_enc_associate(ptr->string, enc);
18291840
}
18301841

test/stringio/test_stringio.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@ def test_initialize
2222
assert_kind_of StringIO, StringIO.new
2323
assert_kind_of StringIO, StringIO.new('str')
2424
assert_kind_of StringIO, StringIO.new('str', 'r+')
25+
assert_kind_of StringIO, StringIO.new(nil)
2526
assert_raise(ArgumentError) { StringIO.new('', 'x') }
2627
assert_raise(ArgumentError) { StringIO.new('', 'rx') }
2728
assert_raise(ArgumentError) { StringIO.new('', 'rbt') }
28-
assert_raise(TypeError) { StringIO.new(nil) }
29+
assert_raise(TypeError) { StringIO.new(Object) }
2930

3031
o = Object.new
3132
def o.to_str
@@ -40,6 +41,13 @@ def o.to_str
4041
assert_kind_of StringIO, StringIO.new(o)
4142
end
4243

44+
def test_null
45+
io = StringIO.new(nil)
46+
assert_nil io.gets
47+
io.puts "abc"
48+
assert_nil io.string
49+
end
50+
4351
def test_truncate
4452
io = StringIO.new("")
4553
io.puts "abc"

0 commit comments

Comments
 (0)