| // PipedReader.java - Piped character stream. |
| |
| /* Copyright (C) 1998, 1999 Cygnus Solutions |
| |
| This file is part of libgcj. |
| |
| This software is copyrighted work licensed under the terms of the |
| Libgcj License. Please consult the file "LIBGCJ_LICENSE" for |
| details. */ |
| |
| package java.io; |
| |
| /** |
| * @author Tom Tromey <tromey@cygnus.com> |
| * @date September 25, 1998 |
| */ |
| |
| /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 |
| * "The Java Language Specification", ISBN 0-201-63451-1 |
| * Status: Complete to 1.1. |
| */ |
| |
| public class PipedReader extends Reader |
| { |
| public void close () throws IOException |
| { |
| closed = true; |
| } |
| |
| public void connect (PipedWriter src) throws IOException |
| { |
| if (closed) |
| throw new IOException ("already closed"); |
| if (writer != null) |
| { |
| if (writer == src) |
| return; |
| throw new IOException ("already connected"); |
| } |
| try |
| { |
| writer = src; |
| writer.connect(this); |
| } |
| catch (IOException e) |
| { |
| writer = null; |
| throw e; |
| } |
| } |
| |
| public PipedReader () |
| { |
| super (); |
| writer = null; |
| closed = false; |
| in = -1; |
| out = 0; |
| pipeBuffer = new char[1024]; |
| } |
| |
| public PipedReader (PipedWriter src) throws IOException |
| { |
| super (); |
| closed = false; |
| in = -1; |
| out = 0; |
| pipeBuffer = new char[1024]; |
| connect (src); |
| } |
| |
| public int read (char buf[], int offset, int count) throws IOException |
| { |
| if (closed) |
| throw new IOException ("closed"); |
| if (count < 0) |
| throw new ArrayIndexOutOfBoundsException (); |
| int toCopy = count; |
| synchronized (lock) |
| { |
| while (toCopy > 0) |
| { |
| // Wait for data in the pipe. If the writer is closed and |
| // no data has been copied into the output buffer, return |
| // the magic EOF number. |
| while (in == -1) |
| { |
| if (writer.isClosed()) |
| { |
| if (toCopy < count) |
| return count - toCopy; |
| return -1; |
| } |
| |
| // Note that JCL doesn't say this is the right thing |
| // to do. Still, it feels right, and we must deal |
| // with an interrupt somehow. |
| try |
| { |
| lock.wait(); |
| } |
| catch (InterruptedException e) |
| { |
| InterruptedIOException io |
| = new InterruptedIOException (e.getMessage()); |
| io.bytesTransferred = count - toCopy; |
| throw io; |
| } |
| } |
| // Now copy some data from pipe into user buffer. |
| int len; |
| if (in < out) |
| len = pipeBuffer.length - out; |
| else |
| len = in - out; |
| len = len > toCopy ? toCopy : len; |
| System.arraycopy(pipeBuffer, out, buf, offset, len); |
| out += len; |
| if (out == pipeBuffer.length) |
| out = 0; |
| toCopy -= len; |
| offset += len; |
| // If we've read all the data, then reset so that we know |
| // there is nothing left to be read. |
| if (in == out) |
| in = -1; |
| // Tell anybody waiting for space in the buffer. |
| lock.notifyAll(); |
| } |
| } |
| return count; |
| } |
| |
| void receive (char buf[], int offset, int count) throws IOException |
| { |
| if (count < 0) |
| throw new ArrayIndexOutOfBoundsException (); |
| int original = count; |
| synchronized (lock) |
| { |
| while (count > 0) |
| { |
| // Wait until there is some space in the buffer. |
| while (in == out) |
| { |
| try |
| { |
| lock.wait(); |
| } |
| catch (InterruptedException e) |
| { |
| // Turn interrupts into IO interrupts. |
| InterruptedIOException io |
| = new InterruptedIOException (e.getMessage()); |
| io.bytesTransferred = original - count; |
| throw io; |
| } |
| } |
| |
| // Compute destination in the pipe. |
| int base, len; |
| if (in == -1) |
| { |
| base = 0; |
| len = pipeBuffer.length; |
| } |
| else if (in < out) |
| { |
| base = in; |
| len = out - in; |
| } |
| else |
| { |
| base = in; |
| len = pipeBuffer.length - in; |
| } |
| int copyLen = len > count ? count : len; |
| // Copy data and update local state. |
| System.arraycopy(buf, offset, pipeBuffer, base, copyLen); |
| in = base + copyLen; |
| if (in == pipeBuffer.length) |
| in = 0; |
| count -= copyLen; |
| offset += copyLen; |
| // Tell anybody waiting for data. |
| lock.notifyAll(); |
| } |
| } |
| } |
| |
| |
| boolean isClosed () |
| { |
| return closed; |
| } |
| |
| // The associated writer. |
| private PipedWriter writer; |
| // True if this reader has been closed. |
| boolean closed; |
| |
| // Index of next character to overwrite when receive() is called. |
| // If -1, then that means the buffer is empty. |
| private int in; |
| // Index of next character to return from read(). |
| private int out; |
| |
| // The pipe buffer itself. |
| private char[] pipeBuffer; |
| } |