Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
    **** BEGIN LICENSE BLOCK *****
    * Version: CPL 1.0/GPL 2.0/LGPL 2.1
    *
    * The contents of this file are subject to the Common Public
    * License Version 1.0 (the "License"); you may not use this file
    * except in compliance with the License. You may obtain a copy of
    * the License at http://www.eclipse.org/legal/cpl-v10.html
    *
   * Software distributed under the License is distributed on an "AS
   * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
   * implied. See the License for the specific language governing
   * rights and limitations under the License.
   *
   * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
   * Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
   * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
   * Copyright (C) 2002-2006 Thomas E Enebo <enebo@acm.org>
   * Copyright (C) 2004-2006 Charles O Nutter <headius@headius.com>
   * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
   * Copyright (C) 2006 Evan Buswell <ebuswell@gmail.com>
   * Copyright (C) 2007 Miguel Covarrubias <mlcovarrubias@gmail.com>
   * 
   * Alternatively, the contents of this file may be used under the terms of
   * either of the GNU General Public License Version 2 or later (the "GPL"),
   * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
   * in which case the provisions of the GPL or the LGPL are applicable instead
   * of those above. If you wish to allow use of your version of this file only
   * under the terms of either the GPL or the LGPL, and not to allow others to
   * use your version of this file under the terms of the CPL, indicate your
   * decision by deleting the provisions above and replace them with the notice
   * and other provisions required by the GPL or the LGPL. If you do not delete
   * the provisions above, a recipient may use your version of this file under
   * the terms of any one of the CPL, the GPL or the LGPL.
   ***** END LICENSE BLOCK *****/
  package org.jruby;
  
  import java.util.Arrays;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Set;
  
  import static org.jruby.runtime.Visibility.*;
  
 
 import static org.jruby.CompatVersion.*;
 import static org.jruby.RubyEnumerator.enumeratorize;

Author(s):
jpetersen
 
 @JRubyClass(name="IO", include="Enumerable")
 public class RubyIO extends RubyObject {
     // This should only be called by this and RubyFile.
     // It allows this object to be created without a IOHandler.
     public RubyIO(Ruby runtimeRubyClass type) {
         super(runtimetype);
         
          = new OpenFile();
     }
     
     public RubyIO(Ruby runtimeOutputStream outputStream) {
         this(runtimeoutputStreamtrue);
     }
 
     public RubyIO(Ruby runtimeOutputStream outputStreamboolean autoclose) {
         super(runtimeruntime.getIO());
         
         // We only want IO objects with valid streams (better to error now). 
         if (outputStream == null) {
             throw runtime.newRuntimeError("Opening null stream");
         }
         
          = new OpenFile();
         
         try {
             .setMainStream(ChannelStream.open(runtimenew ChannelDescriptor(Channels.newChannel(outputStream)), autoclose));
         } catch (InvalidValueException e) {
             throw getRuntime().newErrnoEINVALError();
         }
         
     }
     
     public RubyIO(Ruby runtimeInputStream inputStream) {
         super(runtimeruntime.getIO());
         
         if (inputStream == null) {
             throw runtime.newRuntimeError("Opening null stream");
         }
         
          = new OpenFile();
         
         try {
             .setMainStream(ChannelStream.open(runtimenew ChannelDescriptor(Channels.newChannel(inputStream))));
         } catch (InvalidValueException e) {
             throw getRuntime().newErrnoEINVALError();
         }
         
         .setMode(.);
     }
     
     public RubyIO(Ruby runtimeChannel channel) {
         super(runtimeruntime.getIO());
         
         // We only want IO objects with valid streams (better to error now). 
         if (channel == null) {
             throw runtime.newRuntimeError("Opening null channel");
         }
         
          = new OpenFile();
         
         try {
             .setMainStream(ChannelStream.open(runtimenew ChannelDescriptor(channel)));
         } catch (InvalidValueException e) {
             throw getRuntime().newErrnoEINVALError();
         }
         
     }
 
     public RubyIO(Ruby runtimeShellLauncher.POpenProcess processIOOptions ioOptions) {
         this(runtimeruntime.getIO(), processnullioOptions);
     }
 
     public RubyIO(Ruby runtimeRubyClass clsShellLauncher.POpenProcess processRubyHash optionsIOOptions ioOptions) {
         super(runtimecls);
 
         ioOptions = updateIOOptionsFromOptions(runtime.getCurrentContext(), (RubyHashoptionsioOptions);
         setEncodingFromOptions(ioOptions.getEncodingOption());
 
          = new OpenFile();
         
         .setMode(ioOptions.getModeFlags().getOpenFileFlags() | .);
         .setProcess(process);
 
         try {
             if (.isReadable()) {
                 Channel inChannel;
                 if (process.getInput() != null) {
                     // NIO-based
                     inChannel = process.getInput();
                 } else {
                     // Stream-based
                     inChannel = Channels.newChannel(process.getInputStream());
                 }
                 
                 ChannelDescriptor main = new ChannelDescriptor(
                         inChannel);
                 main.setCanBeSeekable(false);
                 
                 .setMainStream(ChannelStream.open(getRuntime(), main));
             }
             
             if (.isWritable() && process.hasOutput()) {
                 Channel outChannel;
                 if (process.getOutput() != null) {
                     // NIO-based
                     outChannel = process.getOutput();
                 } else {
                     outChannel = Channels.newChannel(process.getOutputStream());
                 }
 
                 ChannelDescriptor pipe = new ChannelDescriptor(
                         outChannel);
                 pipe.setCanBeSeekable(false);
                 
                 if (.getMainStream() != null) {
                     .setPipeStream(ChannelStream.open(getRuntime(), pipe));
                 } else {
                     .setMainStream(ChannelStream.open(getRuntime(), pipe));
                 }
             }
         } catch (InvalidValueException e) {
             throw getRuntime().newErrnoEINVALError();
         }
     }
     
     public RubyIO(Ruby runtimeSTDIO stdio) {
         super(runtimeruntime.getIO());
         
          = new OpenFile();
         ChannelDescriptor descriptor;
         Stream mainStream;
 
         switch (stdio) {
         case :
             // special constructor that accepts stream, not channel
             descriptor = new ChannelDescriptor(runtime.getIn(), newModeFlags(runtime.), .);
             runtime.putFilenoMap(0, descriptor.getFileno());
             mainStream = ChannelStream.open(runtimedescriptor);
             .setMainStream(mainStream);
             break;
         case :
             descriptor = new ChannelDescriptor(Channels.newChannel(runtime.getOut()), newModeFlags(runtime. | .), .);
             runtime.putFilenoMap(1, descriptor.getFileno());
             mainStream = ChannelStream.open(runtimedescriptor);
             .setMainStream(mainStream);
             .getMainStream().setSync(true);
             break;
         case :
             descriptor = new ChannelDescriptor(Channels.newChannel(runtime.getErr()), newModeFlags(runtime. | .), .);
             runtime.putFilenoMap(2, descriptor.getFileno());
             mainStream = ChannelStream.open(runtimedescriptor);
             .setMainStream(mainStream);
             .getMainStream().setSync(true);
             break;
         }
 
         // never autoclose stdio streams
         .setAutoclose(false);
     }
     
     public static RubyIO newIO(Ruby runtimeChannel channel) {
         return new RubyIO(runtimechannel);
     }
     
     public OpenFile getOpenFile() {
         return ;
     }
     
     protected OpenFile getOpenFileChecked() {
         .checkClosed(getRuntime());
         return ;
     }
     
     private static ObjectAllocator IO_ALLOCATOR = new ObjectAllocator() {
         public IRubyObject allocate(Ruby runtimeRubyClass klass) {
             return new RubyIO(runtimeklass);
         }
     };
 
     /*
      * We use FILE versus IO to match T_FILE in MRI.
      */
     @Override
     public int getNativeTypeIndex() {
         return .;
     }
 
     public static RubyClass createIOClass(Ruby runtime) {
         RubyClass ioClass = runtime.defineClass("IO"runtime.getObject(), );
 
         ioClass.index = .;
         ioClass.setReifiedClass(RubyIO.class);
 
         ioClass.kindOf = new RubyModule.KindOf() {
             @Override
             public boolean isKindOf(IRubyObject objRubyModule type) {
                 return obj instanceof RubyIO;
             }
         };
 
         ioClass.includeModule(runtime.getEnumerable());
         
         // TODO: Implement tty? and isatty.  We have no real capability to
         // determine this from java, but if we could set tty status, then
         // we could invoke jruby differently to allow stdin to return true
         // on this.  This would allow things like cgi.rb to work properly.
         
         ioClass.defineAnnotatedMethods(RubyIO.class);
 
         // Constants for seek
         ioClass.setConstant("SEEK_SET"runtime.newFixnum(.));
         ioClass.setConstant("SEEK_CUR"runtime.newFixnum(.));
         ioClass.setConstant("SEEK_END"runtime.newFixnum(.));
 
         if (runtime.is1_9()) {
             ioClass.defineModuleUnder("WaitReadable");
             ioClass.defineModuleUnder("WaitWritable");
         }
 
         return ioClass;
     }
 
     public OutputStream getOutStream() {
         try {
             return getOpenFileChecked().getMainStreamSafe().newOutputStream();
         } catch (BadDescriptorException e) {
             throw getRuntime().newErrnoEBADFError();
         }
     }
 
     public InputStream getInStream() {
         try {
             return getOpenFileChecked().getMainStreamSafe().newInputStream();
         } catch (BadDescriptorException e) {
             throw getRuntime().newErrnoEBADFError();
         }
     }
 
     public Channel getChannel() {
         try {
             return getOpenFileChecked().getMainStreamSafe().getChannel();
         } catch (BadDescriptorException e) {
             throw getRuntime().newErrnoEBADFError();
         }
     }
 
     @Deprecated
     public Stream getHandler() throws BadDescriptorException {
         return getOpenFileChecked().getMainStreamSafe();
     }
 
     protected void reopenPath(Ruby runtimeIRubyObject[] args) {
         IRubyObject pathString;
         
         if (runtime.is1_9()) {
             pathString = RubyFile.get_path(runtime.getCurrentContext(), args[0]);
         } else {
             pathString = args[0].convertToString();
         }
 
         // TODO: check safe, taint on incoming string
 
         try {
             IOOptions modes;
             if (args.length > 1) {
                 IRubyObject modeString = args[1].convertToString();
                 modes = newIOOptions(runtimemodeString.toString());
 
                 .setMode(modes.getModeFlags().getOpenFileFlags());
             } else {
                 modes = newIOOptions(runtime"r");
             }
 
             String path = pathString.toString();
 
             // Ruby code frequently uses a platform check to choose "NUL:" on windows
             // but since that check doesn't work well on JRuby, we help it out
 
             .setPath(path);
 
             if (.getMainStream() == null) {
                 try {
                     .setMainStream(ChannelStream.fopen(runtimepathmodes.getModeFlags()));
                 } catch (FileExistsException fee) {
                     throw runtime.newErrnoEEXISTError(path);
                 }
 
                 if (.getPipeStream() != null) {
                     .getPipeStream().fclose();
                     .setPipeStream(null);
                 }
             } else {
                 // TODO: This is an freopen in MRI, this is close, but not quite the same
                 .getMainStreamSafe().freopen(runtimepathnewIOOptions(runtime.getModeAsString(runtime)).getModeFlags());
                 
                 if (.getPipeStream() != null) {
                     // TODO: pipe handler to be reopened with path and "w" mode
                 }
             }
         } catch (PipeException pe) {
             throw runtime.newErrnoEPIPEError();
         } catch (IOException ex) {
             throw runtime.newIOErrorFromException(ex);
         } catch (BadDescriptorException ex) {
             throw runtime.newErrnoEBADFError();
         } catch (InvalidValueException e) {
             throw runtime.newErrnoEINVALError();
         }
     }
 
     protected void reopenIO(Ruby runtimeRubyIO ios) {
         try {
             if (ios.openFile == this.return;
 
             OpenFile origFile = ios.getOpenFileChecked();
             OpenFile selfFile = getOpenFileChecked();
 
             long pos = 0;
             Stream origStream = origFile.getMainStreamSafe();
             ChannelDescriptor origDescriptor = origStream.getDescriptor();
             boolean origIsSeekable = origDescriptor.isSeekable();
 
             if (origFile.isReadable() && origIsSeekable) {
                 pos = origFile.getMainStreamSafe().fgetpos();
             }
 
             if (origFile.getPipeStream() != null) {
                 origFile.getPipeStream().fflush();
             } else if (origFile.isWritable()) {
                 origStream.fflush();
             }
 
             if (selfFile.isWritable()) {
                 selfFile.getWriteStreamSafe().fflush();
             }
 
             selfFile.setMode(origFile.getMode());
             selfFile.setProcess(origFile.getProcess());
             selfFile.setLineNumber(origFile.getLineNumber());
             selfFile.setPath(origFile.getPath());
             selfFile.setFinalizer(origFile.getFinalizer());
 
             Stream selfStream = selfFile.getMainStreamSafe();
             ChannelDescriptor selfDescriptor = selfFile.getMainStreamSafe().getDescriptor();
             boolean selfIsSeekable = selfDescriptor.isSeekable();
 
             // confirm we're not reopening self's channel
             if (selfDescriptor.getChannel() != origDescriptor.getChannel()) {
                 // check if we're a stdio IO, and ensure we're not badly mutilated
                 if (runtime.getFileno(selfDescriptor) >= 0 && runtime.getFileno(selfDescriptor) <= 2) {
                     selfFile.getMainStreamSafe().clearerr();
 
                     // dup2 new fd into self to preserve fileno and references to it
                     origDescriptor.dup2Into(selfDescriptor);
                 } else {
                     Stream pipeFile = selfFile.getPipeStream();
                     int mode = selfFile.getMode();
                     selfFile.getMainStreamSafe().fclose();
                     selfFile.setPipeStream(null);
 
                     // TODO: turn off readable? am I reading this right?
                     // This only seems to be used while duping below, since modes gets
                     // reset to actual modes afterward
                     //fptr->mode &= (m & FMODE_READABLE) ? ~FMODE_READABLE : ~FMODE_WRITABLE;
 
                     if (pipeFile != null) {
                         selfFile.setMainStream(ChannelStream.fdopen(runtimeorigDescriptororigDescriptor.getOriginalModes()));
                         selfFile.setPipeStream(pipeFile);
                     } else {
                         // only use internal fileno here, stdio is handled above
                         selfFile.setMainStream(
                                 ChannelStream.open(
                                 runtime,
                                 origDescriptor.dup2(selfDescriptor.getFileno())));
 
                         // since we're not actually duping the incoming channel into our handler, we need to
                         // copy the original sync behavior from the other handler
                         selfFile.getMainStreamSafe().setSync(selfFile.getMainStreamSafe().isSync());
                     }
                     selfFile.setMode(mode);
                 }
 
                 // TODO: anything threads attached to original fd are notified of the close...
                 // see rb_thread_fd_close
 
                 if (origFile.isReadable() && pos >= 0) {
                     if (selfIsSeekable) {
                         selfFile.seek(pos.);
                     }
 
                     if (origIsSeekable) {
                         origFile.seek(pos.);
                     }
                 }
             }
 
             // only use internal fileno here, stdio is handled above
             if (selfFile.getPipeStream() != null && selfDescriptor.getFileno() != selfFile.getPipeStream().getDescriptor().getFileno()) {
                 int fd = selfFile.getPipeStream().getDescriptor().getFileno();
 
                 if (origFile.getPipeStream() == null) {
                     selfFile.getPipeStream().fclose();
                     selfFile.setPipeStream(null);
                 } else if (fd != origFile.getPipeStream().getDescriptor().getFileno()) {
                     selfFile.getPipeStream().fclose();
                     ChannelDescriptor newFD2 = origFile.getPipeStream().getDescriptor().dup2(fd);
                     selfFile.setPipeStream(ChannelStream.fdopen(runtimenewFD2newIOOptions(runtime"w").getModeFlags()));
                 }
             }
 
             // TODO: restore binary mode
             //            if (fptr->mode & FMODE_BINMODE) {
             //                rb_io_binmode(io);
             //            }
 
             // TODO: set our metaclass to target's class (i.e. scary!)
 
         } catch (IOException ex) { // TODO: better error handling
             throw runtime.newIOErrorFromException(ex);
         } catch (BadDescriptorException ex) {
             throw runtime.newIOError("could not reopen: " + ex.getMessage());
         } catch (PipeException ex) {
             ex.printStackTrace();
             throw runtime.newIOError("could not reopen: " + ex.getMessage());
         } catch (InvalidValueException ive) {
             throw runtime.newErrnoEINVALError();
         }
     }
 
     @JRubyMethod(name = "reopen", required = 1, optional = 1)
     public IRubyObject reopen(ThreadContext contextIRubyObject[] args) {
         Ruby runtime = context.runtime;
     	IRubyObject tmp = TypeConverter.convertToTypeWithCheck(args[0], runtime.getIO(), "to_io");
         
     	if (!tmp.isNil()) {
             reopenIO(runtime, (RubyIOtmp);
         } else {
             reopenPath(runtimeargs);
         }
         
         return this;
     }
 
     @Deprecated
     public static ModeFlags getIOModes(Ruby runtimeString modesString) {
         return newModeFlags(runtimemodesString);
     }
 
     @Deprecated
     public static int getIOModesIntFromString(Ruby runtimeString modesString) {
         try {
             return ModeFlags.getOFlagsFromString(modesString);
         } catch (InvalidValueException ive) {
             throw runtime.newArgumentError("illegal access mode");
         }
     }
 
     /*
      * Ensure that separator is valid otherwise give it the default paragraph separator.
      */
     private ByteList separator(Ruby runtime) {
         return separator(runtimeruntime.getRecordSeparatorVar().get());
     }
 
     private ByteList separator(Ruby runtimeIRubyObject separatorValue) {
         ByteList separator = separatorValue.isNil() ? null :
             separatorValue.convertToString().getByteList();
 
         if (separator != null) {
             if (separator.getRealSize() == 0) return .;
 
             if (runtime.is1_9()) {
                 if (separator.getEncoding() != getReadEncoding(runtime)) {
                     separator = CharsetTranscoder.transcode(runtime.getCurrentContext(), separator,
                             getInputEncoding(runtime), getReadEncoding(runtime), runtime.getNil());
                 }
             }
         }
 
         return separator;
     }
 
     private ByteList getSeparatorFromArgs(Ruby runtimeIRubyObject[] argsint idx) {
         return separator(runtimeargs.length > idx ? args[idx] : runtime.getRecordSeparatorVar().get());
     }
 
     private ByteList getSeparatorForGets(Ruby runtimeIRubyObject[] args) {
         return getSeparatorFromArgs(runtimeargs, 0);
     }
 
     private IRubyObject getline(Ruby runtimeByteList separatorByteListCache cache) {
         return getline(runtimeseparator, -1, cache);
     }
 
     public IRubyObject getline(Ruby runtimeByteList separator) {
         return getline(runtimeseparator, -1, null);
     }


    
getline using logic of gets. If limit is -1 then read unlimited amount.
 
     public IRubyObject getline(Ruby runtimeByteList separatorlong limit) {
         return getline(runtimeseparatorlimitnull);
     }
 
     private IRubyObject getline(Ruby runtimeByteList separatorlong limitByteListCache cache) {
         return getlineInner(runtimeseparatorlimitcache);
     }
     
     private IRubyObject getlineEmptyString(Ruby runtime) {
         if (runtime.is1_9()) return RubyString.newEmptyString(runtimegetReadEncoding(runtime));
 
         return RubyString.newEmptyString(runtime);
     }
     
     private IRubyObject getlineAll(Ruby runtimeOpenFile myOpenFilethrows IOExceptionBadDescriptorException {
         RubyString str = readAll();
 
         if (str.getByteList().length() == 0) return runtime.getNil();
         incrementLineno(runtimemyOpenFile);
         
         return str;
     }
    
    
getline using logic of gets. If limit is -1 then read unlimited amount. mri: rb_io_getline_1 (mostly)
 
     private IRubyObject getlineInner(Ruby runtimeByteList separatorlong limitByteListCache cache) {
         try {
             boolean is19 = runtime.is1_9();
             
             OpenFile myOpenFile = getOpenFileChecked();
 
             myOpenFile.checkReadable(runtime);
             myOpenFile.setReadBuffered();
 
             boolean isParagraph = separator == .;
             separator = isParagraph ? . : separator;
             
             if (isParagraphswallow('\n');
             
             if (separator == null && limit < 0) {
                 return getlineAll(runtimemyOpenFile);
             } else if (limit == 0) {
                 return getlineEmptyString(runtime);
             } else if (separator != null && separator.length() == 1 && limit < 0 && 
                     (!is19 || (!needsReadConversion() && getReadEncoding(runtime).isAsciiCompatible()))) {
                 return getlineFast(runtimeseparator.get(0) & 0xFF, cache);
             } else {
                 Stream readStream = myOpenFile.getMainStreamSafe();
                 int c = -1;
                 int n = -1;
                 int newline = (separator != null) ? (separator.get(separator.length() - 1) & 0xFF) : -1;
                 
                 // FIXME: Change how we consume streams to match MRI (see append_line/more_char/fill_cbuf)
                 // Awful hack.  MRI pre-transcodes lines into read-ahead whereas
                 // we read a single line at a time PRE-transcoded.  To keep our
                 // logic we need to do one additional transcode of the sep to
                 // match the pre-transcoded encoding.  This is gross and we should
                 // mimick MRI.
                 if (is19 && separator != null && separator.getEncoding() != getInputEncoding(runtime)) {
                     separator = CharsetTranscoder.transcode(runtime.getCurrentContext(), separatorseparator.getEncoding(), getInputEncoding(runtime), null);
                     newline = separator.get(separator.length() - 1) & 0xFF;
                 }
 
                 ByteList buf = cache != null ? cache.allocate(0) : new ByteList(0);
                 try {
                     ThreadContext context = runtime.getCurrentContext();
                     boolean update = false;
                     boolean limitReached = false;
                     
                     if (is19makeReadConversion(context);
                     
                     while (true) {
                         do {
                             readCheck(readStream);
                             readStream.clearerr();
 
                             try {
                                 runtime.getCurrentContext().getThread().beforeBlockingCall();
                                 if (limit == -1) {
                                     n = readStream.getline(buf, (bytenewline);
                                 } else {
                                     n = readStream.getline(buf, (bytenewlinelimit);
                                     limit -= n;
                                     if (limit <= 0) {
                                         update = limitReached = true;
                                         break;
                                     }
                                 }
 
                                 c = buf.length() > 0 ? buf.get(buf.length() - 1) & 0xff : -1;
                             } catch (EOFException e) {
                                 n = -1;
                             } finally {
                                 runtime.getCurrentContext().getThread().afterBlockingCall();
                             }
                             
                             // CRuby checks ferror(f) and retry getc for
                             // non-blocking IO.
                             if (n == 0) {
                                 waitReadable(readStream);
                                 continue;
                             } else if (n == -1) {
                                 break;
                             }
 
                             update = true;
                         } while (c != newline); // loop until we see the nth separator char
 
 
                         // if we hit EOF or reached limit then we're done
                         if (n == -1 || limitReached) {
                             break;
                         }
 
                         // if we've found the last char of the separator,
                         // and we've found at least as many characters as separator length,
                         // and the last n characters of our buffer match the separator, we're done
                         if (c == newline && separator != null && buf.length() >= separator.length() &&
                                 0 == ByteList.memcmp(buf.getUnsafeBytes(), buf.getBegin() + buf.getRealSize() - separator.length(), separator.getUnsafeBytes(), separator.getBegin(), separator.getRealSize())) {
                             break;
                         }
                     }
                     
                     if (is19buf = .transcode(contextbuf);
                     
                     if (isParagraph && c != -1) swallow('\n');
                     if (!updatereturn runtime.getNil();
 
                     incrementLineno(runtimemyOpenFile);
 
                     return makeString(runtimebufcache != null);
                 }
                 finally {
                     if (cache != nullcache.release(buf);
                 }
             }
         } catch (InvalidValueException ex) {
             throw runtime.newErrnoEINVALError();
         } catch (EOFException e) {
             return runtime.getNil();
         } catch (BadDescriptorException e) {
             throw runtime.newErrnoEBADFError();
         } catch (IOException e) {
             throw runtime.newIOErrorFromException(e);
         }
     }
 
     // mri: io_read_encoding
     private Encoding getReadEncoding(Ruby runtime) {
         return  != null ?  : runtime.getDefaultExternalEncoding();
     }
     
     // mri: io_input_encoding
     private Encoding getInputEncoding(Ruby runtime) {
         return  != null ?  : getReadEncoding(runtime);
     }
 
     private RubyString makeString(Ruby runtimeByteList bufferboolean isCached) {
         ByteList newBuf = isCached ? new ByteList(buffer) : buffer;
 
         if (runtime.is1_9()) newBuf.setEncoding(getReadEncoding(runtime));
 
         RubyString str = RubyString.newString(runtimenewBuf);
         str.setTaint(true);
 
         return str;
     }
 
     private void incrementLineno(Ruby runtimeOpenFile myOpenFile) {
         int lineno = myOpenFile.getLineNumber() + 1;
         myOpenFile.setLineNumber(lineno);
         runtime.setCurrentLine(lineno);
         RubyArgsFile.setCurrentLineNumber(runtime.getArgsFile(), lineno);
     }
 
     protected boolean swallow(int termthrows IOExceptionBadDescriptorException {
         Stream readStream = .getMainStreamSafe();
         int c;
         
         do {
             readCheck(readStream);
             
             try {
                 c = readStream.fgetc();
             } catch (EOFException e) {
                 c = -1;
             }
             
             if (c != term) {
                 readStream.ungetc(c);
                 return true;
             }
         } while (c != -1);
         
         return false;
     }
     
     private static String vendor;
     static { String v = SafePropertyAccessor.getProperty("java.vendor") ;  = (v == null) ? "" : v; };
     private static String msgEINTR = "Interrupted system call";
 
     public static boolean restartSystemCall(Exception e) {
         return .startsWith("Apple") && e.getMessage().equals();
     }
     
     private IRubyObject getlineFast(Ruby runtimeint delimByteListCache cachethrows IOExceptionBadDescriptorException {
         Stream readStream = .getMainStreamSafe();
         int c = -1;
 
         ByteList buf = cache != null ? cache.allocate(0) : new ByteList(0);
         try {
             boolean update = false;
             do {
                 readCheck(readStream);
                 readStream.clearerr();
                 int n;
                 try {
                     runtime.getCurrentContext().getThread().beforeBlockingCall();
                     n = readStream.getline(buf, (bytedelim);
                     c = buf.length() > 0 ? buf.get(buf.length() - 1) & 0xff : -1;
                 } catch (EOFException e) {
                     n = -1;
                 } finally {
                     runtime.getCurrentContext().getThread().afterBlockingCall();
                 }
 
                 // CRuby checks ferror(f) and retry getc for non-blocking IO.
                 if (n == 0) {
                     waitReadable(readStream);
                     continue;
                 } else if (n == -1) {
                     break;
                 }
                 
                 update = true;
             } while (c != delim);
 
             if (!updatereturn runtime.getNil();
                 
             incrementLineno(runtime);
 
             return makeString(runtimebufcache != null);
         } finally {
             if (cache != nullcache.release(buf);
         }
     }
     // IO class methods.
 
     @JRubyMethod(name = {"new""for_fd"}, rest = true, meta = true)
     public static IRubyObject newInstance(ThreadContext contextIRubyObject recvIRubyObject[] argsBlock block) {
         RubyClass klass = (RubyClass)recv;
         
         if (block.isGiven()) {
             String className = klass.getName();
             context.runtime.getWarnings().warn(
                     .,
                     className + "::new() does not take block; use " + className + "::open() instead");
         }
         
         return klass.newInstance(contextargsblock);
     }
 
     private IRubyObject initializeCommon19(ThreadContext contextint filenoIRubyObject optionsIOOptions ioOptions) {
         Ruby runtime = context.runtime;
         try {
             ChannelDescriptor descriptor = ChannelDescriptor.getDescriptorByFileno(runtime.getFilenoExtMap(fileno));
 
             if (descriptor == nullthrow runtime.newErrnoEBADFError();
 
             descriptor.checkOpen();
 
             if (options != null && !(options instanceof RubyHash)) {
                 throw context.runtime.newTypeError(optionsruntime.getHash());
             }
 
             if (ioOptions == null) {
                 ioOptions = newIOOptions(runtimedescriptor.getOriginalModes());
             }
 
             ioOptions = updateIOOptionsFromOptions(context, (RubyHashoptionsioOptions);
             setEncodingFromOptions(ioOptions.getEncodingOption());
 
             if (ioOptions == nullioOptions = newIOOptions(runtimedescriptor.getOriginalModes());
 
             if (.isOpen()) {
                 // JRUBY-4650: Make sure we clean up the old data,
                 // if it's present.
                 .cleanup(runtimefalse);
             }
 
             .setMode(ioOptions.getModeFlags().getOpenFileFlags());
             .setMainStream(fdopen(descriptorioOptions.getModeFlags()));
         } catch (BadDescriptorException ex) {
             throw getRuntime().newErrnoEBADFError();
         }
 
         return this;
     }
 
     @JRubyMethod(name = "initialize", visibility = , compat = )
     public IRubyObject initialize19(ThreadContext contextIRubyObject fileNumberBlock unused) {
         return initializeCommon19(context, RubyNumeric.fix2int(fileNumber), nullnull);
     }
 
     @JRubyMethod(name = "initialize", visibility = , compat = )
     public IRubyObject initialize19(ThreadContext contextIRubyObject fileNumberIRubyObject secondBlock unused) {
         int fileno = RubyNumeric.fix2int(fileNumber);
         IOOptions ioOptions = null;
         RubyHash options = null;
         if (second instanceof RubyHash) {
             options = (RubyHash)second;
         } else {
             ioOptions = parseIOOptions19(second);
         }
 
         return initializeCommon19(contextfilenooptionsioOptions);
     }
 
     @JRubyMethod(name = "initialize", visibility = , compat = )
     public IRubyObject initialize19(ThreadContext contextIRubyObject fileNumberIRubyObject modeValueIRubyObject optionsBlock unused) {
         int fileno = RubyNumeric.fix2int(fileNumber);
         IOOptions ioOptions = parseIOOptions19(modeValue);
 
         return initializeCommon19(contextfilenooptionsioOptions);
     }
 
     // No encoding processing
     protected IOOptions parseIOOptions(IRubyObject arg) {
         Ruby runtime = getRuntime();
 
         if (arg instanceof RubyFixnumreturn newIOOptions(runtime, (int) RubyFixnum.fix2long(arg));
 
         return newIOOptions(runtimenewModeFlags(runtimearg.convertToString().toString()));
     }
 
     // Encoding processing
     protected IOOptions parseIOOptions19(IRubyObject arg) {
         Ruby runtime = getRuntime();
 
         if (arg instanceof RubyFixnumreturn newIOOptions(runtime, (int) RubyFixnum.fix2long(arg));
 
         String modeString = arg.convertToString().toString();
         try {
             return new IOOptions(runtimemodeString);
         } catch (InvalidValueException ive) {
             throw runtime.newArgumentError("invalid access mode " + modeString);
         }
     }
 
     @JRubyMethod(required = 1, optional = 1, visibility = , compat = )
     public IRubyObject initialize(IRubyObject[] argsBlock unusedBlock) {
         Ruby runtime = getRuntime();
         int argCount = args.length;
         IOOptions ioOptions;
         
         int fileno = RubyNumeric.fix2int(args[0]);
         
         try {
             ChannelDescriptor descriptor = ChannelDescriptor.getDescriptorByFileno(runtime.getFilenoExtMap(fileno));
             
             if (descriptor == null) {
                 throw runtime.newErrnoEBADFError();
             }
             
             descriptor.checkOpen();
             
             if (argCount == 2) {
                 if (args[1] instanceof RubyFixnum) {
                     ioOptions = newIOOptions(runtime, RubyFixnum.fix2long(args[1]));
                 } else {
                     ioOptions = newIOOptions(runtimeargs[1].convertToString().toString());
                 }
             } else {
                 // use original modes
                 ioOptions = newIOOptions(runtimedescriptor.getOriginalModes());
             }
 
             if (.isOpen()) {
                 // JRUBY-4650: Make sure we clean up the old data,
                 // if it's present.
                .cleanup(runtimefalse);
            }
            .setMode(ioOptions.getModeFlags().getOpenFileFlags());
        
            .setMainStream(fdopen(descriptorioOptions.getModeFlags()));
        } catch (BadDescriptorException ex) {
            throw runtime.newErrnoEBADFError();
        }
        
        return this;
    }
    
    protected Stream fdopen(ChannelDescriptor existingDescriptorModeFlags modes) {
        Ruby runtime = getRuntime