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) 2006 Ola Bini <ola@ologix.com> Copyright (C) 2006 Ryan Bell <ryan.l.bell@gmail.com> Copyright (C) 2007 Thomas E Enebo <enebo@acm.org> Copyright (C) 2008 Vladimir Sizikov <vsizikov@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.ext.stringio;
  
  import java.util.Arrays;
  import java.util.List;
  import org.jruby.Ruby;
  import org.jruby.RubyIO;
  
  import static org.jruby.runtime.Visibility.*;
  import static org.jruby.CompatVersion.*;
  
  import static org.jruby.RubyEnumerator.enumeratorize;
  
  @JRubyClass(name="StringIO")
  @SuppressWarnings("deprecation")
  public class RubyStringIO extends org.jruby.RubyStringIO {
      static class StringIOData {
          long pos = 0L;
          int lineno = 0;
          boolean eof = false;
          boolean closedRead = false;
          boolean closedWrite = false;
          ModeFlags modes;
        
ATTN: the value of internal might be reset to null (during StringIO.open with block), so watch out for that.
  
          RubyString internal;
      }
      StringIOData data;
  
      private static ObjectAllocator STRINGIO_ALLOCATOR = new ObjectAllocator() {
          public IRubyObject allocate(Ruby runtimeRubyClass klass) {
              return new RubyStringIO(runtimeklass);
          }
      };
  
      public static RubyClass createStringIOClass(final Ruby runtime) {
          RubyClass stringIOClass = runtime.defineClass(
                  "StringIO"runtime.getClass("Data"), );
  
          stringIOClass.defineAnnotatedMethods(RubyStringIO.class);
          stringIOClass.includeModule(runtime.getEnumerable());
  
          if (runtime.getObject().isConstantDefined("Java")) {
              stringIOClass.defineAnnotatedMethods(IOJavaAddons.AnyIO.class);
          }
  
         return stringIOClass;
     }
 
     @JRubyMethod(optional = 2, meta = true)
     public static IRubyObject open(ThreadContext contextIRubyObject recvIRubyObject[] argsBlock block) {
         RubyStringIO strio = (RubyStringIO)((RubyClass)recv).newInstance(contextargs.);
         IRubyObject val = strio;
 
         if (block.isGiven()) {
             try {
                 val = block.yield(contextstrio);
             } finally {
                 strio.doFinalize();
             }
         }
         return val;
     }
 
     protected RubyStringIO(Ruby runtimeRubyClass klass) {
         super(runtimeklass);
          = new StringIOData();
     }
 
     private void initializeModes(Object modeArgument) {
         Ruby runtime = getRuntime();
 
         if (modeArgument == null) {
             . = RubyIO.newModeFlags(runtime"r+");
         } else if (modeArgument instanceof Long) {
             . = RubyIO.newModeFlags(runtime, ((LongmodeArgument).longValue());
         } else {
             . = RubyIO.newModeFlags(runtime, (StringmodeArgument);
         }
 
         setupModes();
     }
 
     @JRubyMethod(optional = 2, visibility = )
     public IRubyObject initialize(IRubyObject[] argsBlock unusedBlock) {
         Object modeArgument = null;
         Ruby runtime = getRuntime();
         
         switch (args.length) {
             case 0:
                 . = runtime.is1_9() ? RubyString.newEmptyString(runtimeruntime.getDefaultExternalEncoding()) : RubyString.newEmptyString(getRuntime());
                 modeArgument = "r+";
                 break;
             case 1:
                 . = args[0].convertToString();
                 modeArgument = ..isFrozen() ? "r" : "r+";
                 break;
             case 2:
                 . = args[0].convertToString();
                 if (args[1] instanceof RubyFixnum) {
                     modeArgument = RubyFixnum.fix2long(args[1]);
                 } else {
                     modeArgument = args[1].convertToString().toString();
                 }
                 break;
         }
 
         initializeModes(modeArgument);
 
         if (..isWritable() && ..isFrozen()) {
             throw getRuntime().newErrnoEACCESError("Permission denied");
         }
 
         if (..isTruncate()) {
             ..modifyCheck();
             ..empty();
         }
 
         return this;
     }
 
     @JRubyMethod(visibility = )
     @Override
     public IRubyObject initialize_copy(IRubyObject other) {
 
         RubyStringIO otherIO = (RubyStringIO) TypeConverter.convertToType(
                 othergetRuntime().getClass("StringIO"), "to_strio");
 
         if (this == otherIO) {
             return this;
         }
 
          = otherIO.data;
         if (otherIO.isTaint()) {
             setTaint(true);
         }
 
         return this;
     }
 
     @JRubyMethod(name = "<<", required = 1)
     public IRubyObject append(ThreadContext contextIRubyObject arg) {
         writeInternal(contextarg);
         return this;
     }
 
     @JRubyMethod
     public IRubyObject binmode() {
         return this;
     }
 
     @JRubyMethod
     public IRubyObject close() {
         checkInitialized();
         checkOpen();
 
         . = true;
         . = true;
 
         return getRuntime().getNil();
     }
 
     private void doFinalize() {
         . = true;
         . = true;
         . = null;
     }
 
     @JRubyMethod(name = "closed?")
     public IRubyObject closed_p() {
         checkInitialized();
         return getRuntime().newBoolean(. && .);
     }
 
     @JRubyMethod
     public IRubyObject close_read() {
         checkReadable();
         . = true;
 
         return getRuntime().getNil();
     }
 
     @JRubyMethod(name = "closed_read?")
     public IRubyObject closed_read_p() {
         checkInitialized();
         return getRuntime().newBoolean(.);
     }
 
     @JRubyMethod
     public IRubyObject close_write() {
         checkWritable();
         . = true;
 
         return getRuntime().getNil();
     }
 
     @JRubyMethod(name = "closed_write?")
     public IRubyObject closed_write_p() {
         checkInitialized();
         return getRuntime().newBoolean(.);
     }
 
     public IRubyObject eachInternal(ThreadContext contextIRubyObject[] argsBlock block) {
         IRubyObject line = getsOnly(contextargs);
 
         while (!line.isNil()) {
             block.yield(contextline);
             line = getsOnly(contextargs);
         }
 
         return this;
     }
 
     @JRubyMethod(name = "each", optional = 1, writes = .)
     public IRubyObject each(ThreadContext contextIRubyObject[] argsBlock block) {
         return block.isGiven() ? eachInternal(contextargsblock) : enumeratorize(context.runtimethis"each"args);
     }
 
     @JRubyMethod(optional = 1)
     public IRubyObject each_line(ThreadContext contextIRubyObject[] argsBlock block) {
         return block.isGiven() ? eachInternal(contextargsblock) : enumeratorize(context.runtimethis"each_line"args);
     }
 
     @JRubyMethod(optional = 1)
     public IRubyObject lines(ThreadContext contextIRubyObject[] argsBlock block) {
         return block.isGiven() ? each(contextargsblock) : enumeratorize(context.runtimethis"lines"args);
     }
 
     public IRubyObject each_byte(ThreadContext contextBlock block) {
         checkReadable();
         Ruby runtime = context.runtime;
         ByteList bytes = ..getByteList();
 
         // Check the length every iteration, since
         // the block can modify this string.
         while (. < bytes.length()) {
             block.yield(contextruntime.newFixnum(bytes.get((int.++) & 0xFF));
         }
         return this;
     }
 
     @JRubyMethod(name = "each_byte")
     public IRubyObject each_byte19(ThreadContext contextBlock block) {
         return block.isGiven() ? each_byte(contextblock) : enumeratorize(context.runtimethis"each_byte");
     }
 
     @JRubyMethod
     public IRubyObject bytes(ThreadContext contextBlock block) {
         return block.isGiven() ? each_byte(contextblock) : enumeratorize(context.runtimethis"bytes");
     }
 
     public IRubyObject each_charInternal(final ThreadContext contextfinal Block block) {
         checkReadable();
 
         Ruby runtime = context.runtime;
         ByteList bytes = ..getByteList();
         int len = bytes.getRealSize();
         int end = bytes.getBegin() + len;
         Encoding enc = runtime.is1_9() ? bytes.getEncoding() : runtime.getKCode().getEncoding();        
         while (. < len) {
             int pos = (int.;
             int n = StringSupport.length(encbytes.getUnsafeBytes(), posend);
 
             if(len < pos + nn = len - pos;
 
             . += n;
 
             block.yield(context..makeShared19(runtimeposn));
         }
 
         return this;
     }
 
     @JRubyMethod
     public IRubyObject each_char(final ThreadContext contextfinal Block block) {
         return block.isGiven() ? each_charInternal(contextblock) : enumeratorize(context.runtimethis"each_char");
     }
 
     @JRubyMethod
     public IRubyObject chars(final ThreadContext contextfinal Block block) {
         return block.isGiven() ? each_charInternal(contextblock) : enumeratorize(context.runtimethis"chars");
     }
 
     @JRubyMethod(name = {"eof""eof?"})
     public IRubyObject eof() {
         return getRuntime().newBoolean(isEOF());
     }
 
     private boolean isEOF() {
         return (. >= ..getByteList().length()) || .;
     }
 
     @JRubyMethod(name = "fcntl")
     public IRubyObject fcntl() {
         throw getRuntime().newNotImplementedError("fcntl not implemented");
     }
 
     @JRubyMethod(name = "fileno")
     public IRubyObject fileno() {
         return getRuntime().getNil();
     }
 
     @JRubyMethod(name = "flush")
     public IRubyObject flush() {
         return this;
     }
 
     @JRubyMethod(name = "fsync")
     public IRubyObject fsync() {
         return RubyFixnum.zero(getRuntime());
     }
 
     @JRubyMethod(name = {"getc""getbyte"})
     public IRubyObject getc() {
         checkReadable();
         if (. >= ..getByteList().length()) {
             return getRuntime().getNil();
         }
         return getRuntime().newFixnum(..getByteList().get((int).++) & 0xFF);
     }
 
     @JRubyMethod(name = "getc", compat = .)
     public IRubyObject getc19(ThreadContext context) {
         checkReadable();
         if (. >= ..getByteList().length()) {
             return context.runtime.getNil();
         }
         return context.runtime.newString("" + (char) (..getByteList().get((int.++) & 0xFF));
     }
 
     private IRubyObject internalGets(ThreadContext contextIRubyObject[] args) {
         Ruby runtime = context.runtime;
 
         if (. < ..getByteList().getRealSize() && !.) {
             boolean isParagraph = false;
             boolean is19 = runtime.is1_9();
             ByteList sep = ((RubyString)runtime.getGlobalVariables().get("$/")).getByteList();
             IRubyObject sepArg = null;
             int limit = -1;
 
             if (is19) {
                 IRubyObject limitArg = (args.length > 1 ? args[1] :
                                         (args.length > 0 && args[0] instanceof RubyFixnum ? args[0] :
                                          null));
                 if (limitArg != null) {
                     limit = RubyNumeric.fix2int(limitArg);
                 }
 
                 sepArg = (args.length > 0 && !(args[0] instanceof RubyFixnum) ? args[0] : null);
             } else {
                 sepArg = (args.length > 0 ? args[0] : null);
             }
 
             if (sepArg != null) {
                 if (sepArg.isNil()) {
                     int bytesAvailable = ..getByteList().getRealSize() - (int).;
                     int bytesToUse = (limit < 0 || limit >= bytesAvailable ? bytesAvailable : limit);
                     ByteList buf = ..getByteList().makeShared(
                         (int).bytesToUse);
                     . += buf.getRealSize();
                     return makeString(runtimebuf);
                 }
 
                 sep = sepArg.convertToString().getByteList();
                 if (sep.getRealSize() == 0) {
                     isParagraph = true;
                     sep = .;
                 }
             }
 
             ByteList ss = ..getByteList();
 
             if (isParagraph) {
                 swallowLF(ss);
                 if (. == ss.getRealSize()) {
                     return runtime.getNil();
                 }
             }
 
             int ix = ss.indexOf(sep, (int).);
 
             ByteList add;
             if (-1 == ix) {
                 ix = ..getByteList().getRealSize();
                 add = .;
             } else {
                 add = sep;
             }
 
             int bytes = ix - (int).;
             int bytesToUse = (limit < 0 || limit >= bytes ? bytes : limit);
 
             int bytesWithSep = ix - (int). + add.getRealSize();
             int bytesToUseWithSep = (limit < 0 || limit >= bytesWithSep ? bytesWithSep : limit);
 
             ByteList line = new ByteList(bytesToUseWithSep);
             if (is19line.setEncoding(..getByteList().getEncoding());
             line.append(..getByteList(), (int).bytesToUse);
             . += bytesToUse;
 
             int sepBytesToUse = bytesToUseWithSep - bytesToUse;
             line.append(add, 0, sepBytesToUse);
             . += sepBytesToUse;
 
             if (sepBytesToUse >= add.getRealSize()) {
                 .++;
             }
 
             return makeString(runtimeline);
         }
         return runtime.getNil();
     }
 
     private void swallowLF(ByteList list) {
         while (. < list.getRealSize()) {
             if (list.get((int).) == '\n') {
                 .++;
             } else {
                 break;
             }
         }
     }
 
     @JRubyMethod(name = "gets", optional = 1, writes = ., compat = .)
     public IRubyObject gets(ThreadContext contextIRubyObject[] args) {
         IRubyObject result = getsOnly(contextargs);
         context.getCurrentScope().setLastLine(result);
 
         return result;
     }
 
     @JRubyMethod(name = "gets", optional = 2, writes = ., compat = .)
     public IRubyObject gets19(ThreadContext contextIRubyObject[] args) {
         IRubyObject result = getsOnly(contextargs);
         context.getCurrentScope().setLastLine(result);
 
         return result;
     }
 
     public IRubyObject getsOnly(ThreadContext contextIRubyObject[] args) {
         checkReadable();
 
         return internalGets(contextargs);
     }
 
     @JRubyMethod(name = {"tty?""isatty"})
     public IRubyObject isatty() {
         return getRuntime().getFalse();
     }
 
     @JRubyMethod(name = {"length""size"})
     public IRubyObject length() {
         checkFinalized();
         return getRuntime().newFixnum(..getByteList().length());
     }
 
     @JRubyMethod(name = "lineno")
     public IRubyObject lineno() {
         return getRuntime().newFixnum(.);
     }
 
     @JRubyMethod(name = "lineno=", required = 1)
     public IRubyObject set_lineno(IRubyObject arg) {
         . = RubyNumeric.fix2int(arg);
 
         return getRuntime().getNil();
     }
 
     @JRubyMethod(name = "path", compat = .)
     public IRubyObject path() {
         return getRuntime().getNil();
     }
 
     @JRubyMethod(name = "pid")
     public IRubyObject pid() {
         return getRuntime().getNil();
     }
 
     @JRubyMethod(name = {"pos""tell"})
     public IRubyObject pos() {
         return getRuntime().newFixnum(.);
     }
 
     @JRubyMethod(name = "pos=", required = 1)
     public IRubyObject set_pos(IRubyObject arg) {
         . = RubyNumeric.fix2int(arg);
         if (. < 0) {
             throw getRuntime().newErrnoEINVALError("Invalid argument");
         }
         if (. < ..getByteList().length()) {
             . = false;
         }
         return getRuntime().getNil();
     }
 
     @JRubyMethod(name = "print", rest = true)
     public IRubyObject print(ThreadContext contextIRubyObject[] args) {
         Ruby runtime = context.runtime;
         if (args.length != 0) {
             for (int i=0,j=args.length;i<j;i++) {
                 append(contextargs[i]);
             }
         } else {
             IRubyObject arg = runtime.getGlobalVariables().get("$_");
             append(contextarg.isNil() ? makeString(runtimenew ByteList(new byte[] {'n''i''l'})) : arg);
         }
         IRubyObject sep = runtime.getGlobalVariables().get("$\\");
         if (!sep.isNil()) append(contextsep);
 
         return runtime.getNil();
     }
 
     @JRubyMethod(name = "print", rest = true, compat = .)
     public IRubyObject print19(ThreadContext contextIRubyObject[] args) {
         Ruby runtime = context.runtime;
         if (args.length != 0) {
             for (int i=0,j=args.length;i<j;i++) {
                 append(contextargs[i]);
             }
         } else {
             IRubyObject arg = runtime.getGlobalVariables().get("$_");
             append(contextarg.isNil() ? RubyString.newEmptyString(getRuntime()) : arg);
         }
         IRubyObject sep = runtime.getGlobalVariables().get("$\\");
         if (!sep.isNil()) append(contextsep);
 
         return runtime.getNil();
     }
 
     @JRubyMethod(name = "printf", required = 1, rest = true)
     public IRubyObject printf(ThreadContext contextIRubyObject[] args) {
         append(context, RubyKernel.sprintf(contextthisargs));
         return getRuntime().getNil();
     }
 
     @JRubyMethod(name = "putc", required = 1)
     public IRubyObject putc(IRubyObject obj) {
         checkWritable();
         byte c = RubyNumeric.num2chr(obj);
         checkFrozen();
 
         ..modify();
         ByteList bytes = ..getByteList();
         if (..isAppendable()) {
             . = bytes.length();
             bytes.append(c);
         } else {
             if (. >= bytes.length()) {
                 bytes.length((int). + 1);
             }
 
             bytes.set((int.c);
             .++;
         }
 
         return obj;
     }
 
     public static final ByteList NEWLINE = ByteList.create("\n");
 
     @JRubyMethod(name = "puts", rest = true)
     public IRubyObject puts(ThreadContext contextIRubyObject[] args) {
         checkWritable();
 
         // FIXME: the code below is a copy of RubyIO.puts,
         // and we should avoid copy-paste.
 
         if (args.length == 0) {
             callMethod(context"write", RubyString.newStringShared(getRuntime(), ));
             return getRuntime().getNil();
         }
 
         for (int i = 0; i < args.lengthi++) {
             RubyString line;
 
             if (args[i].isNil()) {
                 line = getRuntime().newString("nil");
             } else {
                 IRubyObject tmp = args[i].checkArrayType();
                 if (!tmp.isNil()) {
                     RubyArray arr = (RubyArraytmp;
                     if (getRuntime().isInspecting(arr)) {
                         line = getRuntime().newString("[...]");
                     } else {
                         inspectPuts(contextarr);
                         continue;
                     }
                 } else {
                     if (args[iinstanceof RubyString) {
                         line = (RubyString)args[i];
                     } else {
                         line = args[i].asString();
                     }
                 }
             }
 
             callMethod(context"write"line);
 
             if (!line.getByteList().endsWith()) {
                 callMethod(context"write", RubyString.newStringShared(getRuntime(), ));
             }
         }
         return getRuntime().getNil();
     }
 
     private IRubyObject inspectPuts(ThreadContext contextRubyArray array) {
         try {
             getRuntime().registerInspecting(array);
             return puts(contextarray.toJavaArray());
         } finally {
             getRuntime().unregisterInspecting(array);
         }
     }
     
     // Make string based on internal data encoding (which ironically is its
     // external encoding.  This seems messy and we should consider a more
     // uniform method for makeing strings (we have a slightly different variant
     // of this in RubyIO.
     private RubyString makeString(Ruby runtimeByteList buf) {
         if (runtime.is1_9()) buf.setEncoding(..getEncoding());
 
         RubyString str = RubyString.newString(runtimebuf);
         str.setTaint(true);
 
         return str;        
     }
 
     @SuppressWarnings("fallthrough")
     @JRubyMethod(name = "read", optional = 2)
     public IRubyObject read(IRubyObject[] args) {
         checkReadable();
 
         ByteList buf = null;
         int length = 0;
         int oldLength = 0;
         RubyString originalString = null;
 
         switch (args.length) {
         case 2:
             originalString = args[1].convertToString();
             // must let original string know we're modifying, so shared buffers aren't damaged
             originalString.modify();
             buf = originalString.getByteList();
         case 1:
             if (!args[0].isNil()) {
                 length = RubyNumeric.fix2int(args[0]);
                 oldLength = length;
 
                 if (length < 0) {
                     throw getRuntime().newArgumentError("negative length " + length + " given");
                 }
                 if (length > 0 && . >= ..getByteList().length()) {
                     . = true;
                     if (buf != nullbuf.setRealSize(0);
                     return getRuntime().getNil();
                 } else if (.) {
                     if (buf != nullbuf.setRealSize(0);
                     return getRuntime().getNil();
                 }
                 break;
             }
         case 0:
             oldLength = -1;
             length = ..getByteList().length();
 
             if (length <= .) {
                 . = true;
                 if (buf == null) {
                     buf = new ByteList();
                 } else {
                     buf.setRealSize(0);
                 }
 
                 return makeString(getRuntime(), buf);
             } else {
                 length -= .;
             }
             break;
         default:
             getRuntime().newArgumentError(args.length, 0);
         }
 
         if (buf == null) {
             int internalLength = ..getByteList().length();
 
             if (internalLength > 0) {
                 if (internalLength >= . + length) {
                     buf = new ByteList(..getByteList(), (int.length);
                 } else {
                     int rest = (int) (..getByteList().length() - .);
 
                     if (length > restlength = rest;
                     buf = new ByteList(..getByteList(), (int.length);
                 }
             }
         } else {
             int rest = (int) (..getByteList().length() - .);
 
             if (length > restlength = rest;
 
             // Yow...this is still ugly
             byte[] target = buf.getUnsafeBytes();
             if (target.length > length) {
                 System.arraycopy(..getByteList().getUnsafeBytes(), (int.target, 0, length);
                 buf.setBegin(0);
                 buf.setRealSize(length);
             } else {
                 target = new byte[length];
                 System.arraycopy(..getByteList().getUnsafeBytes(), (int.target, 0, length);
                 buf.setBegin(0);
                 buf.setRealSize(length);
                 buf.setUnsafeBytes(target);
             }
         }
 
         if (buf == null) {
             if (!.buf = new ByteList();
             length = 0;
         } else {
             length = buf.length();
             . += length;
         }
 
         if (oldLength < 0 || oldLength > length. = true;
 
         return originalString != null ? originalString : makeString(getRuntime(), buf);
     }
 
     @JRubyMethod(name="read_nonblock", compat = ., required = 1, optional = 1)
     public IRubyObject read_nonblock(ThreadContext contetIRubyObject[] args) {
         return sysreadCommon(args);
     }

    
readpartial(length, [buffer])
 
     @JRubyMethod(name ="readpartial", compat = ., required = 1, optional = 1)
     public IRubyObject readpartial(ThreadContext contextIRubyObject[] args) {
         return sysreadCommon(args);
     }
 
     @JRubyMethod(name = {"readchar""readbyte"})
     public IRubyObject readchar() {
         IRubyObject c = getc();
 
         if (c.isNil()) throw getRuntime().newEOFError();
 
         return c;
     }
 
     @JRubyMethod(name = "readchar", compat = .)
     public IRubyObject readchar19(ThreadContext context) {
         IRubyObject c = getc19(context);
 
         if (c.isNil()) throw getRuntime().newEOFError();
 
         return c;
     }
 
     @JRubyMethod(name = "readline", optional = 1, writes = .)
     public IRubyObject readline(ThreadContext contextIRubyObject[] args) {
         IRubyObject line = gets(contextargs);
 
         if (line.isNil()) throw getRuntime().newEOFError();
 
         return line;
     }
 
     @JRubyMethod(name = "readlines", optional = 1)
     public IRubyObject readlines(ThreadContext contextIRubyObject[] arg) {
         checkReadable();
 
         List<IRubyObjectlns = new ArrayList<IRubyObject>();
         while (!(isEOF())) {
             IRubyObject line = internalGets(contextarg);
             if (line.isNil()) {
                 break;
             }
             lns.add(line);
         }
 
         return getRuntime().newArray(lns);
     }
 
     @JRubyMethod(name = "reopen", required = 0, optional = 2)
     public IRubyObject reopen(IRubyObject[] args) {
         if (args.length == 1 && !(args[0] instanceof RubyString)) {
             return initialize_copy(args[0]);
         }
 
         // reset the state
         doRewind();
         . = false;
         . = false;
         return initialize(args.);
     }
 
     @JRubyMethod(name = "rewind")
     public IRubyObject rewind() {
         doRewind();
         return RubyFixnum.zero(getRuntime());
     }
 
     private void doRewind() {
         this.. = 0L;
         this.. = false;
         this.. = 0;
     }
 
     @JRubyMethod(required = 1, optional = 1)
     public IRubyObject seek(IRubyObject[] args) {
         checkOpen();
         checkFinalized();
         long amount = RubyNumeric.num2long(args[0]);
         int whence = .;
         long newPosition = .;
 
         if (args.length > 1 && !args[0].isNil()) whence = RubyNumeric.fix2int(args[1]);
 
         if (whence == .) {
             newPosition += amount;
         } else if (whence == .) {
             newPosition = ..getByteList().length() + amount;
         } else if (whence == .) {
             newPosition = amount;
         } else {
             throw getRuntime().newErrnoEINVALError("invalid whence");
         }
 
         if (newPosition < 0) throw getRuntime().newErrnoEINVALError("invalid seek value");
 
         . = newPosition;
         . = false;
 
         return RubyFixnum.zero(getRuntime());
     }
 
     @JRubyMethod(name = "string=", required = 1)
     public IRubyObject set_string(IRubyObject arg) {
         return reopen(new IRubyObject[] { arg.convertToString() });
     }
 
     @JRubyMethod(name = "sync=", required = 1)
     public IRubyObject set_sync(IRubyObject args) {
         return args;
     }
 
     @JRubyMethod(name = "string")
     public IRubyObject string() {
         if (. == null) {
             return getRuntime().getNil();
         } else {
             return .;
         }
     }
 
     @JRubyMethod(name = "sync")
     public IRubyObject sync() {
         return getRuntime().getTrue();
     }
 
     @JRubyMethod(name = "sysread", optional = 2)
     public IRubyObject sysread(IRubyObject[] args) {
         return sysreadCommon(args);
     }
     
 
     private IRubyObject sysreadCommon(IRubyObject[] args) {
         IRubyObject obj = read(args);
 
         if (isEOF() && obj.isNil()) throw getRuntime().newEOFError();
 
         return obj;        
     }
 
     @JRubyMethod(name = "truncate", required = 1)
     public IRubyObject truncate(IRubyObject arg) {
         checkWritable();
 
         int len = RubyFixnum.fix2int(arg);
         if (len < 0) {
             throw getRuntime().newErrnoEINVALError("negative legnth");
         }
 
         ..modify();
         ByteList buf = ..getByteList();
         if (len < buf.length()) {
             Arrays.fill(buf.getUnsafeBytes(), lenbuf.length(), (byte) 0);
         }
         buf.length(len);
         return arg;
     }
 
     @JRubyMethod(name = "ungetc", required = 1)
     public IRubyObject ungetc(IRubyObject arg) {
         checkReadable();
 
         int c = RubyNumeric.num2int(arg);
         if (. == 0) return getRuntime().getNil();
         ungetcCommon(c);
         return getRuntime().getNil();
     }
 
     @JRubyMethod(name = "ungetc", compat = .)
     public IRubyObject ungetc19(ThreadContext contextIRubyObject arg) {
         checkReadable();
 
         if (!arg.isNil()) {
             int c;
             if (arg instanceof RubyFixnum) {
                 c = RubyNumeric.fix2int(arg);
        &nb