Skip to content

Commit 571a36b

Browse files
committed
Support the NULL StringIO as in C
See ruby#90
1 parent a517fd6 commit 571a36b

1 file changed

Lines changed: 57 additions & 20 deletions

File tree

ext/java/org/jruby/ext/stringio/StringIO.java

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ public Encoding getEncoding() {
141141
}
142142

143143
RubyString string = ptr.string;
144-
if (!string.isNil()) {
144+
if (string != null && !string.isNil()) {
145145
return string.getEncoding();
146146
}
147147

@@ -334,8 +334,7 @@ private void strioInit(ThreadContext context, int argc, IRubyObject arg0, IRubyO
334334
EncodingUtils.extractModeEncoding(context, ioEncodable, vmodeAndVpermP, maybeOptions, OFLAGS_UNUSED, FMODE_TL.get());
335335

336336
// clear shared vmodeVperm
337-
EncodingUtils.vmode(vmodeAndVpermP, null);
338-
EncodingUtils.vperm(vmodeAndVpermP, null);
337+
clearVmodeVperm(vmodeAndVpermP);
339338

340339
ptr.flags = FMODE_TL.get()[0];
341340

@@ -357,7 +356,9 @@ private void strioInit(ThreadContext context, int argc, IRubyObject arg0, IRubyO
357356
if (!string.isNil() && (ptr.flags & OpenFile.TRUNC) != 0) {
358357
((RubyString) string).clear();
359358
}
360-
ptr.string = (RubyString) string;
359+
if (string instanceof RubyString) {
360+
ptr.string = (RubyString) string;
361+
}
361362
if (argc == 1 && !string.isNil()) {
362363
ptr.enc = ((RubyString) string).getEncoding();
363364
} else {
@@ -624,7 +625,7 @@ public IRubyObject eof(ThreadContext context) {
624625
}
625626

626627
private boolean isEndOfString() {
627-
return ptr.pos >= ptr.string.size();
628+
return ptr.string == null || ptr.pos >= ptr.string.size();
628629
}
629630

630631
@JRubyMethod(name = "getc")
@@ -721,21 +722,25 @@ private static int bm_search(byte[] little, int lstart, int llen, byte[] big, in
721722

722723
@JRubyMethod(name = "gets", writes = FrameField.LASTLINE)
723724
public IRubyObject gets(ThreadContext context) {
725+
if (ptr.string == null) return context.nil;
724726
return Getline.getlineCall(context, GETLINE, this, getEncoding());
725727
}
726728

727729
@JRubyMethod(name = "gets", writes = FrameField.LASTLINE)
728730
public IRubyObject gets(ThreadContext context, IRubyObject arg0) {
731+
if (ptr.string == null) return context.nil;
729732
return Getline.getlineCall(context, GETLINE, this, getEncoding(), arg0);
730733
}
731734

732735
@JRubyMethod(name = "gets", writes = FrameField.LASTLINE)
733736
public IRubyObject gets(ThreadContext context, IRubyObject arg0, IRubyObject arg1) {
737+
if (ptr.string == null) return context.nil;
734738
return Getline.getlineCall(context, GETLINE, this, getEncoding(), arg0, arg1);
735739
}
736740

737741
@JRubyMethod(name = "gets", writes = FrameField.LASTLINE)
738742
public IRubyObject gets(ThreadContext context, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
743+
if (ptr.string == null) return context.nil;
739744
return Getline.getlineCall(context, GETLINE, this, getEncoding(), arg0, arg1, arg2);
740745
}
741746

@@ -756,6 +761,8 @@ public IRubyObject gets(ThreadContext context, IRubyObject[] args) {
756761
}
757762

758763
private static final Getline.Callback<StringIO, IRubyObject> GETLINE = (context, self, rs, limit, chomp, block) -> {
764+
if (self.isEndOfString()) return context.nil;
765+
759766
if (limit == 0) {
760767
return RubyString.newEmptyString(context.runtime, self.getEncoding());
761768
}
@@ -772,6 +779,11 @@ public IRubyObject gets(ThreadContext context, IRubyObject[] args) {
772779
private static final Getline.Callback<StringIO, StringIO> GETLINE_YIELD = (context, self, rs, limit, chomp, block) -> {
773780
IRubyObject line;
774781

782+
StringIOData ptr = self.ptr;
783+
if (ptr.string == null || ptr.pos > ptr.string.size()) {
784+
return self;
785+
}
786+
775787
if (limit == 0) {
776788
throw context.runtime.newArgumentError("invalid limit: 0 for each_line");
777789
}
@@ -790,6 +802,11 @@ public IRubyObject gets(ThreadContext context, IRubyObject[] args) {
790802
RubyArray<IRubyObject> ary = (RubyArray<IRubyObject>) context.runtime.newArray();
791803
IRubyObject line;
792804

805+
StringIOData ptr = self.ptr;
806+
if (ptr.string == null || ptr.pos > ptr.string.size()) {
807+
return null;
808+
}
809+
793810
if (limit == 0) {
794811
throw context.runtime.newArgumentError("invalid limit: 0 for readlines");
795812
}
@@ -919,10 +936,11 @@ private static int chompNewlineWidth(byte[] bytes, int s, int e) {
919936
}
920937

921938
@JRubyMethod(name = {"length", "size"})
922-
public IRubyObject length() {
939+
public IRubyObject length(ThreadContext context) {
923940
checkInitialized();
924-
checkFinalized();
925-
return getRuntime().newFixnum(ptr.string.size());
941+
RubyString myString = ptr.string;
942+
if (myString == null) return RubyFixnum.zero(context.runtime);
943+
return getRuntime().newFixnum(myString.size());
926944
}
927945

928946
@JRubyMethod(name = "lineno")
@@ -995,10 +1013,12 @@ public IRubyObject putc(ThreadContext context, IRubyObject ch) {
9951013

9961014
checkModifiable();
9971015
if (ch instanceof RubyString) {
1016+
if (ptr.string == null) return context.nil;
9981017
str = substrString((RubyString) ch, str, runtime);
9991018
}
10001019
else {
10011020
byte c = RubyNumeric.num2chr(ch);
1021+
if (ptr.string == null) return context.nil;
10021022
str = RubyString.newString(runtime, new byte[]{c});
10031023
}
10041024
write(context, str);
@@ -1059,6 +1079,10 @@ private IRubyObject readCommon(ThreadContext context, int argc, IRubyObject arg0
10591079
break;
10601080
}
10611081
case 0:
1082+
RubyString myString = ptr.string;
1083+
if (myString == null) {
1084+
return context.nil;
1085+
}
10621086
len = ptr.string.size();
10631087
if (len <= pos) {
10641088
Encoding enc = binary ? ASCIIEncoding.INSTANCE : getEncoding();
@@ -1287,7 +1311,6 @@ public IRubyObject seek(ThreadContext context, IRubyObject arg0, IRubyObject arg
12871311

12881312
private RubyFixnum seekCommon(ThreadContext context, int argc, IRubyObject arg0, IRubyObject arg1) {
12891313
checkFrozen();
1290-
checkFinalized();
12911314

12921315
Ruby runtime = context.runtime;
12931316

@@ -1369,10 +1392,13 @@ public IRubyObject truncate(ThreadContext context, IRubyObject len) {
13691392

13701393
boolean locked = lock(context, ptr);
13711394
try {
1372-
int plen = string.size();
13731395
if (l < 0) {
13741396
throw context.runtime.newErrnoEINVALError("negative legnth");
13751397
}
1398+
if (string == null) {
1399+
return RubyFixnum.zero(context.runtime);
1400+
}
1401+
int plen = string.size();
13761402
string.resize(l);
13771403
ByteList buf = string.getByteList();
13781404
if (plen < l) {
@@ -1393,6 +1419,8 @@ public IRubyObject ungetc(ThreadContext context, IRubyObject arg) {
13931419
checkModifiable();
13941420
checkReadable();
13951421

1422+
if (ptr.string == null) return context.nil;
1423+
13961424
if (arg.isNil()) return arg;
13971425
if (arg instanceof RubyInteger) {
13981426
int len, cc = RubyNumeric.num2int(arg);
@@ -1486,6 +1514,7 @@ public IRubyObject ungetbyte(ThreadContext context, IRubyObject arg) {
14861514
if (arg.isNil()) return arg;
14871515

14881516
checkModifiable();
1517+
if (ptr.string == null) return context.nil;
14891518

14901519
if (arg instanceof RubyInteger) {
14911520
ungetbyteCommon(context, ((RubyInteger) ((RubyInteger) arg).op_mod(context, 256)).getIntValue());
@@ -1597,6 +1626,7 @@ private long stringIOWrite(ThreadContext context, Ruby runtime, IRubyObject arg)
15971626
boolean locked = lock(context, ptr);
15981627
try {
15991628
final Encoding enc = getEncoding();
1629+
if (enc == null) return 0;
16001630
final Encoding encStr = str.getEncoding();
16011631
if (enc != encStr && enc != EncodingUtils.ascii8bitEncoding(runtime)
16021632
// this is a hack because we don't seem to handle incoming ASCII-8BIT properly in transcoder
@@ -1639,11 +1669,19 @@ private long stringIOWrite(ThreadContext context, Ruby runtime, IRubyObject arg)
16391669

16401670
@JRubyMethod
16411671
public IRubyObject set_encoding(ThreadContext context, IRubyObject ext_enc) {
1642-
final Encoding enc;
1672+
Encoding enc;
16431673
if ( ext_enc.isNil() ) {
16441674
enc = EncodingUtils.defaultExternalEncoding(context.runtime);
16451675
} else {
1646-
enc = EncodingUtils.rbToEncoding(context, ext_enc);
1676+
enc = context.runtime.getEncodingService().getEncodingFromObjectNoError(ext_enc);
1677+
if (enc == null) {
1678+
IOEncodable convconfig = new IOEncodable.ConvConfig();
1679+
Object vmodeAndVpermP = VMODE_VPERM_TL.get();
1680+
EncodingUtils.vmode(vmodeAndVpermP, ext_enc.convertToString().prepend(context, context.runtime.newString("r:")));
1681+
EncodingUtils.extractModeEncoding(context, convconfig, vmodeAndVpermP, context.nil, OFLAGS_UNUSED, FMODE_TL.get());
1682+
clearVmodeVperm(vmodeAndVpermP);
1683+
enc = convconfig.getEnc2();
1684+
}
16471685
}
16481686

16491687
StringIOData ptr = this.ptr;
@@ -1653,8 +1691,8 @@ public IRubyObject set_encoding(ThreadContext context, IRubyObject ext_enc) {
16531691
ptr.enc = enc;
16541692

16551693
// in read-only mode, StringIO#set_encoding no longer sets the encoding
1656-
RubyString string;
1657-
if (writable() && (string = ptr.string).getEncoding() != enc) {
1694+
RubyString string = ptr.string;
1695+
if (string != null && writable() && string.getEncoding() != enc) {
16581696
string.modify();
16591697
string.setEncoding(enc);
16601698
}
@@ -1665,6 +1703,11 @@ public IRubyObject set_encoding(ThreadContext context, IRubyObject ext_enc) {
16651703
return this;
16661704
}
16671705

1706+
private static void clearVmodeVperm(Object vmodeAndVpermP) {
1707+
EncodingUtils.vmode(vmodeAndVpermP, null);
1708+
EncodingUtils.vperm(vmodeAndVpermP, null);
1709+
}
1710+
16681711
@JRubyMethod
16691712
public IRubyObject set_encoding(ThreadContext context, IRubyObject enc, IRubyObject ignored) {
16701713
return set_encoding(context, enc);
@@ -2056,12 +2099,6 @@ private void checkInitialized() {
20562099
}
20572100
}
20582101

2059-
private void checkFinalized() {
2060-
if (ptr.string == null) {
2061-
throw getRuntime().newIOError("not opened");
2062-
}
2063-
}
2064-
20652102
private void checkOpen() {
20662103
if (closed()) {
20672104
throw getRuntime().newIOError(RubyIO.CLOSED_STREAM_MSG);

0 commit comments

Comments
 (0)