Index: src/org/jruby/RubyIO.java =================================================================== --- src/org/jruby/RubyIO.java (revision 3741) +++ src/org/jruby/RubyIO.java (working copy) @@ -990,7 +990,7 @@ ThreadContext context = getRuntime().getCurrentContext(); if (args.length == 0) { - callMethod(context, "write", getRuntime().newString("\n")); + callMethod(context, "write", getRuntime().newString(handler.getNewline())); return getRuntime().getNil(); } @@ -1005,7 +1005,7 @@ line = args[i].toString(); } callMethod(getRuntime().getCurrentContext(), "write", getRuntime().newString(line+ - (line.endsWith("\n") ? "" : "\n"))); + (line.endsWith("\n") ? "" : handler.getNewline()))); } return getRuntime().getNil(); } Index: src/org/jruby/util/IOHandlerSeekable.java =================================================================== --- src/org/jruby/util/IOHandlerSeekable.java (revision 3741) +++ src/org/jruby/util/IOHandlerSeekable.java (working copy) @@ -44,6 +44,7 @@ import org.jruby.Ruby; import org.jruby.RubyIO; +import org.jruby.util.IOHandler.BadDescriptorException; /** *
This file implements a seekable IO file.
@@ -60,6 +61,9 @@ protected boolean reading; // are we reading or writing? protected FileChannel channel; + private String fileNewline; + private LineBreak lineBreak; + public IOHandlerSeekable(Ruby runtime, String path, IOModes modes) throws IOException, InvalidValueException { super(runtime); @@ -82,6 +86,18 @@ javaMode += "w"; } + final String ls = System.getProperty("line.separator"); + if (!modes.isBinary() && !"\n".equals(ls)) { + if ("\r".equals(ls)) { + lineBreak = new MacLineBreak(this); + } else { + lineBreak = new WindowsLineBreak(this); + } + } else { + lineBreak = new UnixLineBreak(this); + } + fileNewline = ls; + // We always open this rw since we can only open it r or rw. file = new RandomAccessFile(theFile, javaMode); if (modes.shouldTruncate()) { @@ -101,7 +117,81 @@ // we have a problem opening a file. fileno = RubyIO.getNewFileno(); } + + public String getNewline() { + return fileNewline; + } + static private abstract class LineBreak { + IOHandlerSeekable io; + + public LineBreak(IOHandlerSeekable io) { + this.io = io; + } + + public void ensureRead() throws IOException { + io.ensureRead(); + } + + public int sysread() throws IOException { + ensureRead(); + if (!io.buffer.hasRemaining()) { + io.buffer.clear(); + int read = io.channel.read(io.buffer); + io.buffer.flip(); + if (read == -1) return -1; + } + return _sysread(); + } + + abstract protected int _sysread() throws IOException; + } + + static private class UnixLineBreak extends LineBreak { + public UnixLineBreak(IOHandlerSeekable io) { + super(io); + } + + protected int _sysread() throws IOException { + return io.buffer.get(); + } + } + + static private class WindowsLineBreak extends LineBreak { + public WindowsLineBreak(IOHandlerSeekable io) { + super(io); + } + + protected int _sysread() throws IOException { + final int curr = io.buffer.get(); + if (curr != '\r') { + return curr; + } + final int pos = io.buffer.position(); + final int next = io.buffer.get(); + if (next == '\n') { + return next; + } else { + io.buffer.position(pos); + return curr; + } + } + } + + static private class MacLineBreak extends LineBreak { + public MacLineBreak(IOHandlerSeekable io) { + super(io); + } + + protected int _sysread() throws IOException { + final int curr = io.buffer.get(); + if (curr != '\r') { + return curr; + } + return '\n'; + } + } + private void reopen() throws IOException { long pos = pos(); @@ -365,15 +455,7 @@ * @see org.jruby.util.IOHandler#sysread() */ public int sysread() throws IOException { - ensureRead(); - - if (!buffer.hasRemaining()) { - buffer.clear(); - int read = channel.read(buffer); - buffer.flip(); - if (read == -1) return -1; - } - return buffer.get(); + return lineBreak.sysread(); } /** Index: src/org/jruby/util/IOHandler.java =================================================================== --- src/org/jruby/util/IOHandler.java (revision 3741) +++ src/org/jruby/util/IOHandler.java (working copy) @@ -205,6 +205,10 @@ public abstract void seek(long offset, int type) throws IOException, PipeException, InvalidValueException; public abstract void truncate(long newLength) throws IOException, PipeException; + public String getNewline() { + return "\n"; + } + public boolean hasPendingBuffered() { return false; }