aboutsummaryrefslogtreecommitdiff
path: root/libjava
diff options
context:
space:
mode:
authorTom Tromey <tromey@cygnus.com>2000-04-21 01:18:16 +0000
committerTom Tromey <tromey@gcc.gnu.org>2000-04-21 01:18:16 +0000
commitd3474943bf309f085d515d7b20cb80c1d50e14cd (patch)
treedec5c6d7c3d3c314853e857fd39856ceb50ec5db /libjava
parent21caf59006e2c7dd06bf9840a7fc3cea321282f7 (diff)
downloadgcc-d3474943bf309f085d515d7b20cb80c1d50e14cd.zip
gcc-d3474943bf309f085d515d7b20cb80c1d50e14cd.tar.gz
gcc-d3474943bf309f085d515d7b20cb80c1d50e14cd.tar.bz2
Fix for PR java.io/204:
* java/io/PipedInputStream.java, java/io/PipedReader.java, java/io/PipedOutputStream.java, java/io/PipedWriter.java: Imported from Classpath. From-SVN: r33300
Diffstat (limited to 'libjava')
-rw-r--r--libjava/ChangeLog5
-rw-r--r--libjava/java/io/PipedInputStream.java732
-rw-r--r--libjava/java/io/PipedOutputStream.java280
-rw-r--r--libjava/java/io/PipedReader.java703
-rw-r--r--libjava/java/io/PipedWriter.java279
5 files changed, 1431 insertions, 568 deletions
diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index 212e9aa..d5e1688 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -1,5 +1,10 @@
2000-04-20 Tom Tromey <tromey@cygnus.com>
+ Fix for PR java.io/204:
+ * java/io/PipedInputStream.java, java/io/PipedReader.java,
+ java/io/PipedOutputStream.java, java/io/PipedWriter.java: Imported
+ from Classpath.
+
Fix for PR libgcj/212:
* gcj/javaprims.h (_Jv_word, _Jv_word2): Removed definitions.
* include/jvm.h (_Jv_word, _Jv_word2): Define.
diff --git a/libjava/java/io/PipedInputStream.java b/libjava/java/io/PipedInputStream.java
index d2dbecb..d1081a2 100644
--- a/libjava/java/io/PipedInputStream.java
+++ b/libjava/java/io/PipedInputStream.java
@@ -1,242 +1,550 @@
-/* Copyright (C) 1998, 1999 Free Software Foundation
+/* PipedInputStream.java -- Input stream that reads from an output stream
+ Copyright (C) 1998, 1999 Free Software Foundation, Inc.
- This file is part of libgcj.
+This file is part of GNU Classpath.
-This software is copyrighted work licensed under the terms of the
-Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
-details. */
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+As a special exception, if you link this library with other files to
+produce an executable, this library does not by itself cause the
+resulting executable to be covered by the GNU General Public License.
+This exception does not however invalidate any other reasons why the
+executable file might be covered by the GNU General Public License. */
+
+
package java.io;
/**
- * @author Warren Levy <warrenl@cygnus.com>
- * @date October 29, 1998.
+ * This class is an input stream that reads its bytes from an output stream
+ * to which it is connected.
+ * <p>
+ * Data is read and written to an internal buffer. It is highly recommended
+ * that the <code>PipedInputStream</code> and connected <code>PipedOutputStream</code>
+ * be part of different threads. If they are not, there is a possibility
+ * that the read and write operations could deadlock their thread.
+ *
+ * @version 0.0
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class PipedInputStream extends InputStream
+{
+
+/*************************************************************************/
+
+/*
+ * Class Variables
*/
-/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
- * "The Java Language Specification", ISBN 0-201-63451-1
- * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
- * Status: Believed complete and correct.
+
+/**
+ * The size of the internal buffer used for input/output. Note that this
+ * can be overriden by setting the system property
+ * <code>gnu.java.io.PipedInputStream.pipe_size</code> to the desired size shown
+ * in bytes. This is not a standard part of the class library. Note that
+ * since this variable is <code>final</code>, it cannot be changed to refect
+ * the size specified in the property.
+ * <p>
+ * The value for this variable is 2048.
+ */
+protected static final int PIPE_SIZE = 2048;
+
+/**
+ * This is the real pipe size. It defaults to PIPE_SIZE, unless overridden
+ * by use of the system property <code>gnu.java.io.PipedInputStream.pipe_size</code>.
+ */
+private static int pipe_size;
+
+/**
+ * This variable indicates whether or not the <code>read()</code> method will attempt
+ * return a short count if this will possibly keep the stream from blocking.
+ * The default for this is <code>false</code> because that is what what the JDK seems
+ * to imply in its javadocs. We set this to <code>false</code> if the system
+ * property <code>gnu.java.io.try_not_to_block</code> is set.
+ */
+private static boolean try_not_to_block = false;
+
+static
+{
+ pipe_size = Integer.getInteger("gnu.java.io.PipedInputStream.pipe_size",
+ PIPE_SIZE).intValue();
+
+ String block_prop = System.getProperty("gnu.java.io.try_not_to_block");
+ if (block_prop != null)
+ try_not_to_block = true;
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
*/
-
-public class PipedInputStream extends InputStream
+
+/**
+ * This is the internal circular buffer used for storing bytes written
+ * to the pipe and from which bytes are read by this stream
+ */
+protected byte[] buffer = new byte[pipe_size];
+
+/**
+ * The index into buffer where the bytes written byte the connected
+ * <code>PipedOutputStream</code> will be written. If this variables is less
+ * than 0, then the buffer is empty. If this variable is equal to
+ * <code>out</code>, then the buffer is full
+ */
+protected int in = -1;
+
+/**
+ * This index into the buffer where bytes will be read from.
+ */
+protected int out = 0;
+
+/**
+ * This variable is <code>true</code> if this object has ever been connected
+ * to a <code>PipedOutputStream</code>, and <code>false</code> otherwise. It is used
+ * to detect an attempt to connect an already connected stream or to
+ * otherwise use the stream before it is connected.
+ */
+private boolean ever_connected = false;
+
+/**
+ * This variable is set to <code>true</code> if the <code>close()</code> method is
+ * called. This value is checked prevents a caller from re-opening the
+ * stream.
+ */
+private boolean closed = false;
+
+/**
+ * This variable is the PipedOutputStream to which this stream is connected.
+ */
+PipedOutputStream src;
+
+/**
+ * Used by <code>read()</code> to call an overloaded method
+ */
+private byte[] read_buf = new byte[1];
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * This constructor creates a new <code>PipedInputStream</code> that is not
+ * connected to a <code>PipedOutputStream</code>. It must be connected before
+ * bytes can be read from this stream.
+ */
+public
+PipedInputStream()
{
- /* The size of the pipe's circular input buffer. */
- protected static final int PIPE_SIZE = 1024;
+ return;
+}
- /* The circular buffer into which incoming data is placed. */
- protected byte[] buffer;
+/*************************************************************************/
- /* The index in the buffer at which the next byte of data will be stored. */
- protected int in = -1;
+/**
+ * This constructor creates a new <code>PipedInputStream</code> and connects
+ * it to the passed in <code>PipedOutputStream</code>. The stream is then read
+ * for reading.
+ *
+ * @param src The <code>PipedOutputStream</code> to connect this stream to
+ *
+ * @exception IOException If an error occurs
+ */
+public
+PipedInputStream(PipedOutputStream src) throws IOException
+{
+ connect(src);
+}
- /* The index in the buffer at which the next byte of data will be read. */
- protected int out = 0;
+/*************************************************************************/
- /* The output stream this is connected to; used to check for errors. */
- private PipedOutputStream po = null;
+/*
+ * Instance Variables
+ */
- /* Flag to indicate that the output stream was closed. */
- private boolean outClosed = false;
+/**
+ * This method connects this stream to the passed in <code>PipedOutputStream</code>.
+ * This stream is then ready for reading. If this stream is already
+ * connected or has been previously closed, then an exception is thrown
+ *
+ * @param src The <code>PipedOutputStream</code> to connect this stream to
+ *
+ * @exception IOException If an error occurs
+ */
+public synchronized void
+connect(PipedOutputStream src) throws IOException
+{
+ if (src == this.src)
+ return;
- public PipedInputStream(PipedOutputStream src) throws IOException
- {
- buffer = new byte[PIPE_SIZE];
- connect(src);
- }
+ if (ever_connected)
+ throw new IOException("Already connected");
- public PipedInputStream()
- {
- buffer = new byte[PIPE_SIZE];
- }
+ if (closed)
+ throw new IOException("Stream is closed and cannot be reopened");
- public synchronized int available() throws IOException
- {
- if (in < 0)
- return 0;
+ src.connect(this);
- if (in > out)
- return in - out;
+ ever_connected = true;
+}
- // Buffer has wrapped around.
- return buffer.length - out + in;
- }
+/*************************************************************************/
- public void close() throws IOException
- {
- buffer = null;
- po = null;
+/**
+ * This methods closes the stream so that no more data can be read
+ * from it.
+ *
+ * @exception IOException If an error occurs
+ */
+public synchronized void
+close() throws IOException
+{
+ closed = true;
+ notifyAll();
+}
- // Mark as empty for available method.
- in = -1;
- }
+/*************************************************************************/
- public void connect(PipedOutputStream src) throws IOException
- {
- if (buffer == null)
- throw new IOException("pipe closed");
+/**
+ * This method returns the number of bytes that can be read from this stream
+ * before blocking could occur. This is the number of bytes that are
+ * currently unread in the internal circular buffer. Note that once this
+ * many additional bytes are read, the stream may block on a subsequent
+ * read, but it not guaranteed to block.
+ *
+ * @return The number of bytes that can be read before blocking might occur
+ *
+ * @exception IOException If an error occurs
+ */
+public synchronized int
+available() throws IOException
+{
+ if (in == -1)
+ return(0);
+ else if (in > out)
+ return(in - out);
+ else
+ return(in + (pipe_size - out));
+}
- if (po != null)
- if (po == src)
- return;
- else
- throw new IOException("pipe already connected");
+/*************************************************************************/
+
+/**
+ * Reads the next byte from the stream. The byte read is returned as
+ * and int in the range of 0-255. If a byte cannot be read because of an
+ * end of stream condition, -1 is returned. If the stream is already
+ * closed, an IOException will be thrown.
+ * <code>
+ * This method will block if no bytes are available to be read.
+ *
+ * @return The byte read or -1 if end of stream.
+ *
+ * @exception IOException If an error occurs
+ */
+public synchronized int
+read() throws IOException
+{
+ // Method operates by calling the multibyte overloaded read method
+ // Note that read_buf is an internal instance variable. I allocate it
+ // there to avoid constant reallocation overhead for applications that
+ // call this method in a loop at the cost of some unneeded overhead
+ // if this method is never called.
+
+ int bytes_read = read(read_buf, 0, read_buf.length);
+
+ if (bytes_read == -1)
+ return(-1);
+ else
+ return((read_buf[0] & 0xFF));
+}
+
+/*************************************************************************/
- po = src;
- try
+/**
+ * This method reads bytes from the stream into a caller supplied buffer.
+ * It starts storing bytes at position <code>offset</code> into the buffer and
+ * reads a maximum of <cod>>len</code> bytes. Note that this method can actually
+ * read fewer than <code>len</code> bytes. The actual number of bytes read is
+ * returned. A -1 is returned to indicated that no bytes can be read
+ * because the end of the stream was reached. If the stream is already
+ * closed, a -1 will again be returned to indicate the end of the stream.
+ * <p>
+ * This method will block if no bytes are available to be read.
+ *
+ * @param buf The buffer into which bytes will be stored
+ * @param offset The index into the buffer at which to start writing.
+ * @param len The maximum number of bytes to read.
+ */
+public synchronized int
+read(byte[] buf, int offset, int len) throws IOException
+{
+ if (!ever_connected)
+ throw new IOException("Not connected");
+
+ int bytes_read = 0;
+ for (;;)
{
- src.connect(this);
- }
- catch (IOException ex)
+ // If there are bytes, take them
+ if (in != -1)
+ {
+ int desired_bytes = len - bytes_read;
+
+ // We are in a "wrap" condition
+ if (out > in)
+ {
+ if (desired_bytes > (pipe_size - out))
+ {
+ if (in == 0)
+ desired_bytes = (pipe_size - out) - 1;
+ else
+ desired_bytes = pipe_size - out;
+
+ System.arraycopy(buffer, out, buf, offset + bytes_read,
+ desired_bytes);
+
+ bytes_read += desired_bytes;
+ out += desired_bytes;
+ desired_bytes = len - bytes_read;
+
+ if (out == pipe_size)
+ out = 0;
+
+ notifyAll();
+ }
+ else
+ {
+ if ((out + desired_bytes) == in)
+ --desired_bytes;
+
+ if (((out + desired_bytes) == pipe_size) && (in == 0))
+ desired_bytes = (pipe_size - out) - 1;
+
+ System.arraycopy(buffer, out, buf, offset + bytes_read,
+ desired_bytes);
+
+ bytes_read += desired_bytes;
+ out += desired_bytes;
+ desired_bytes = len - bytes_read;
+
+ if (out == pipe_size)
+ out = 0;
+
+ notifyAll();
+ }
+ }
+
+ // We are in a "no wrap" or condition (can also be fall through
+ // from above
+ if (in > out)
+ {
+ if (desired_bytes >= ((in - out) - 1))
+ desired_bytes = (in - out) - 1;
+
+ System.arraycopy(buffer, out, buf, offset + bytes_read,
+ desired_bytes);
+
+ bytes_read += desired_bytes;
+ out += desired_bytes;
+ desired_bytes = len - bytes_read;
+
+ if (out == pipe_size)
+ out = 0;
+
+ notifyAll();
+ }
+ }
+
+ // If we are done, return
+ if (bytes_read == len)
+ return(bytes_read);
+
+ // Return a short count if necessary
+ if (bytes_read < len)
+ if (try_not_to_block)
+ return(bytes_read);
+
+ // Handle the case where the end of stream was encountered.
+ if (closed)
+ {
+ // We never let in == out so there might be one last byte
+ // available that we have not copied yet.
+ if (in != -1)
+ {
+ buf[offset + bytes_read] = buffer[out];
+ in = -1;
+ ++out;
+ ++bytes_read;
+ }
+
+ if (bytes_read != 0)
+ return(bytes_read);
+ else
+ return(-1);
+ }
+
+ // Wait for a byte to be read
+ try
+ {
+ wait();
+ }
+ catch(InterruptedException e) { ; }
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * This method receives a byte of input from the source PipedOutputStream.
+ * If there is no data ready to be written, or if the internal circular
+ * buffer is full, this method blocks.
+ *
+ * *****What is this method really supposed to do *********
+ */
+protected synchronized void
+receive(int byte_received) throws IOException
+{
+ int orig_in = in;
+
+ for (;;)
{
- po = null;
- throw ex;
+ // Wait for something to happen
+ try
+ {
+ wait();
+ }
+ catch(InterruptedException e) { ; }
+
+ // See if we woke up because the stream was closed on us
+ if (closed)
+ throw new IOException("Stream closed before receiving byte");
+
+ // See if a byte of data was received
+ if (in != orig_in)
+ return;
}
- }
-
- public synchronized int read() throws IOException
- {
- // TBD: Spec says to throw IOException if thread writing to output stream
- // died. What does this really mean? Theoretically, multiple threads
- // could be writing to this object. Do you track the first, last, or
- // all of them?
- if (po == null)
- if (buffer == null)
- throw new IOException("pipe closed");
- else
- throw new IOException("pipe unconnected");
+}
- // Block until there's something to read or output stream was closed.
- while (in < 0)
- try
- {
- if (outClosed)
- return -1;
- wait();
- }
- catch (InterruptedException ex)
- {
- throw new InterruptedIOException();
- }
-
- // Let other threads know there's room to write now.
- notifyAll();
-
- int retval = buffer[out++] & 0xFF;
-
- // Wrap back around if at end of the array.
- if (out >= buffer.length)
- out = 0;
-
- // When the last byte available is read, mark the buffer as empty.
- if (out == in)
- {
- in = -1;
- out = 0;
- }
-
- return retval;
- }
-
- public synchronized int read(byte[] b, int off, int len) throws IOException
- {
- if (off < 0 || len < 0 || off + len > b.length)
- throw new ArrayIndexOutOfBoundsException();
-
- // TBD: Spec says to throw IOException if thread writing to output stream
- // died. What does this really mean? Theoretically, multiple threads
- // could be writing to this object. Do you track the first, last, or
- // all of them?
- if (po == null)
- if (buffer == null)
- throw new IOException("pipe closed");
- else
- throw new IOException("pipe unconnected");
+/*************************************************************************/
- // Block until there's something to read or output stream was closed.
- while (in < 0)
- try
- {
- if (outClosed)
- return -1;
- wait();
- }
- catch (InterruptedException ex)
- {
- throw new InterruptedIOException();
- }
-
- // Let other threads know there's room to write now.
- notifyAll();
-
- int numRead;
- len = Math.min(len, available());
- if (in <= out && len >= (numRead = buffer.length - out))
- {
- // Buffer has wrapped around; need to copy in 2 steps.
- // Copy to the end of the buffer first; second copy may be of zero
- // bytes but that is ok. Doing it that way saves having to check
- // later if 'out' has grown to buffer.length.
- System.arraycopy(buffer, out, b, off, numRead);
- len -= numRead;
- off += numRead;
- out = 0;
- }
- else
- numRead = 0;
-
- System.arraycopy(buffer, out, b, off, len);
- numRead += len;
- out += len;
-
- // When the last byte available is read, mark the buffer as empty.
- if (out == in)
- {
- in = -1;
- out = 0;
- }
-
- return numRead;
- }
-
- protected synchronized void receive(int b) throws IOException
- {
- if (buffer == null)
- throw new IOException("pipe closed");
-
- // TBD: Spec says to throw IOException if thread reading from input stream
- // died. What does this really mean? Theoretically, multiple threads
- // could be reading to this object (why else would 'read' be synchronized?).
- // Do you track the first, last, or all of them?
-
- if (b < 0)
- {
- outClosed = true;
- notifyAll(); // In case someone was blocked in a read.
- return;
- }
-
- // Block until there's room in the pipe.
- while (in == out)
- try
- {
- wait();
- }
- catch (InterruptedException ex)
- {
- throw new InterruptedIOException();
- }
-
- // Check if buffer is empty.
- if (in < 0)
- in = 0;
-
- buffer[in++] = (byte) b;
-
- // Wrap back around if at end of the array.
- if (in >= buffer.length)
- in = 0;
-
- // Let other threads know there's something to read when this returns.
- notifyAll();
- }
+/**
+ * This method is used by the connected <code>PipedOutputStream</code> to
+ * write bytes into the buffer. It uses this method instead of directly
+ * writing the bytes in order to obtain ownership of the object's monitor
+ * for the purposes of calling <code>notify</code>.
+ *
+ * @param buf The array containing bytes to write to this stream
+ * @param offset The offset into the array to start writing from
+ * @param len The number of bytes to write.
+ *
+ * @exception IOException If an error occurs
+ */
+synchronized void
+write(byte[] buf, int offset, int len) throws IOException
+{
+ if (len <= 0)
+ return;
+
+ int total_written = 0;
+ while (total_written < len)
+ {
+ // If we are not at the end of the buffer with out = 0
+ if (!((in == (buffer.length - 1)) && (out == 0)))
+ {
+ // This is the "no wrap" situation
+ if ((in - 1) >= out)
+ {
+ int bytes_written = 0;
+ if ((buffer.length - in) > (len - total_written))
+ bytes_written = (len - total_written);
+ else if (out == 0)
+ bytes_written = (buffer.length - in) - 1;
+ else
+ bytes_written = (buffer.length - in);
+
+ if (bytes_written > 0)
+ System.arraycopy(buf, offset + total_written, buffer, in,
+ bytes_written);
+ total_written += bytes_written;
+ in += bytes_written;
+
+ if (in == buffer.length)
+ in = 0;
+
+ notifyAll();
+ }
+ // This is the "wrap" situtation
+ if ((out > in) && (total_written != len))
+ {
+ int bytes_written = 0;
+
+ // Do special processing if we are at the beginning
+ if (in == -1)
+ {
+ in = 0;
+
+ if (buffer.length > len)
+ bytes_written = len;
+ else
+ bytes_written = buffer.length - 1;
+ }
+ else if (((out - in) - 1) < (len - total_written))
+ {
+ bytes_written = (out - in) - 1;
+ }
+ else
+ {
+ bytes_written = len - total_written;
+ }
+
+ // If the buffer is full, wait for it to empty out
+ if ((out - 1) == in)
+ {
+ try
+ {
+ wait();
+ }
+ catch (InterruptedException e)
+ {
+ continue;
+ }
+ }
+
+ System.arraycopy(buf, offset + total_written, buffer, in,
+ bytes_written);
+ total_written += bytes_written;
+ in += bytes_written;
+
+ if (in == buffer.length)
+ in = 0;
+
+ notifyAll();
+ }
+ }
+ // Wait for some reads to occur before we write anything.
+ else
+ {
+ try
+ {
+ wait();
+ }
+ catch (InterruptedException e) { ; }
+ }
+ }
}
+
+} // class PipedInputStream
+
diff --git a/libjava/java/io/PipedOutputStream.java b/libjava/java/io/PipedOutputStream.java
index 901fb9e..6d10612 100644
--- a/libjava/java/io/PipedOutputStream.java
+++ b/libjava/java/io/PipedOutputStream.java
@@ -1,97 +1,209 @@
-// PipedOutputStream.java - Write bytes to a pipe.
+/* PipedOutputStream.java -- Write portion of piped streams.
+ Copyright (C) 1998 Free Software Foundation, Inc.
-/* Copyright (C) 1998, 1999, 2000 Free Software Foundation
+This file is part of GNU Classpath.
- This file is part of libgcj.
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+As a special exception, if you link this library with other files to
+produce an executable, this library does not by itself cause the
+resulting executable to be covered by the GNU General Public License.
+This exception does not however invalidate any other reasons why the
+executable file might be covered by the GNU General Public License. */
-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 24, 1998
+ * This class writes its bytes to a <code>PipedInputStream</code> to
+ * which it is connected.
+ * <p>
+ * It is highly recommended that a <code>PipedOutputStream</code> and its
+ * connected <code>PipedInputStream</code> be in different threads. If
+ * they are in the same thread, read and write operations could deadlock
+ * the thread.
+ *
+ * @version 0.0
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class PipedOutputStream extends OutputStream
+{
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
*/
-/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
- * "The Java Language Specification", ISBN 0-201-63451-1
- * Status: Believed complete and correct.
+/**
+ * This is the <code>PipedInputStream</code> to which this object
+ * is connected.
+ */
+private PipedInputStream snk;
+
+/**
+ * This flag indicates whether or not this stream has ever been
+ * connected to an input stream
+ */
+private boolean ever_connected;
+
+/**
+ * This flag indicates whether the <code>close</code> method has ever
+ * been called for this stream.
+ */
+private boolean closed;
+
+/*************************************************************************/
+
+/**
+ * This method initializes a new <code>PipedOutputStream</code> instance.
+ * This constructor creates an unconnected object. It must be connected
+ * to a <code>PipedInputStream</code> object using the <code>connect</code>
+ * method prior to writing any data or an exception will be thrown.
+ */
+public
+PipedOutputStream()
+{
+ ; // Do Nothing
+}
+
+/*************************************************************************/
+
+/**
+ * This method initializes a new <code>PipedOutputStream</code> instance
+ * to write to the specified <code>PipedInputStream</code>. This stream
+ * is then ready for writing.
+ *
+ * @param snk The <code>PipedInputStream</code> to connect this stream to.
+ *
+ * @exception IOException If an error occurs
+ */
+public
+PipedOutputStream(PipedInputStream snk) throws IOException
+{
+ connect(snk);
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Methods
*/
-public class PipedOutputStream extends OutputStream
+/**
+ * This method connects this object to the specified
+ * <code>PipedInputStream</code> object. This stream will then be ready
+ * for writing. If this stream is already connected or has been
+ * previously closed, then an exception is thrown.
+ *
+ * @param snk The <code>PipedInputStream</code> to connect this stream to
+ *
+ * @exception IOException If an error occurs
+ */
+public synchronized void
+connect(PipedInputStream snk) throws IOException
{
- public void close () throws IOException
- {
- closed = true;
-
- // Notify PipedInputStream that there is no more data to be had.
- destination.receive(-1);
- }
-
- public void connect (PipedInputStream dest) throws IOException
- {
- if (closed)
- throw new IOException("pipe closed");
-
- if (destination != null)
- if (destination == dest)
- return;
- else
- throw new IOException("pipe already connected");
-
- destination = dest;
- try
- {
- dest.connect(this);
- }
- catch (IOException ex)
- {
- destination = null;
- throw ex;
- }
- }
-
- public synchronized void flush () throws IOException
- {
- // There doesn't seem to be anything to do here.
-
- // TBD: Should this maybe do a notifyAll as a way for the user
- // to wake up the input stream to check for bytes to read? Shouldn't
- // be necessary but if there aren't any bytes, other threads will just
- // go blocak again anyway so it wouldn't hurt.
- }
-
- public PipedOutputStream ()
- {
- closed = false;
- }
-
- public PipedOutputStream (PipedInputStream dest) throws IOException
- {
- closed = false;
- connect (dest);
- }
-
- public void write (int oneByte) throws IOException
- {
- if (closed)
- throw new IOException ();
- destination.receive(oneByte);
- }
-
- public void write (byte[] buffer, int offset, int count) throws IOException
- {
- if (closed)
- throw new IOException ();
- if (offset < 0 || count < 0 || offset + count > buffer.length)
- throw new ArrayIndexOutOfBoundsException ();
- for (int i = 0; i < count; ++i)
- destination.receive (buffer[offset + i]);
- }
-
- // Instance variables.
- private PipedInputStream destination;
- private boolean closed;
+ if (snk == this.snk)
+ return;
+
+ if (ever_connected)
+ throw new IOException("Already connected");
+
+ if (closed)
+ throw new IOException("Stream is closed and cannot be reopened");
+
+ this.snk = snk;
+ ever_connected = true;
+ snk.src = this;
+
+ snk.connect(this);
+}
+
+/*************************************************************************/
+
+/**
+ * This method closes this stream so that no more data can be written
+ * to it. Any further attempts to write to this stream may throw an
+ * exception
+ *
+ * @exception IOException If an error occurs
+ */
+public synchronized void
+close() throws IOException
+{
+ closed = true;
+ snk.close();
+ notifyAll();
+}
+
+/*************************************************************************/
+
+/**
+ * This method writes a single byte of date to the stream. Note that
+ * this method will block if the <code>PipedInputStream</code> to which
+ * this object is connected has a full buffer.
+ *
+ * @param b The byte of data to be written, passed as an <code>int</code>.
+ *
+ * @exception IOException If an error occurs
+ */
+public synchronized void
+write(int b) throws IOException
+{
+ byte[] buf = new byte[1];
+ buf[0] = (byte)(b & 0xFF);
+
+ snk.write(buf, 0, buf.length);
}
+
+/*************************************************************************/
+
+/**
+ * This method writes <code>len</code> bytes of data from the byte array
+ * <code>buf</code> starting at index <code>offset</code> in the array
+ * to the stream. Note that this method will block if the
+ * <code>PipedInputStream</code> to which this object is connected has
+ * a buffer that cannot hold all of the bytes to be written.
+ *
+ * @param buf The array containing bytes to write to thes stream.
+ * @param offset The index into the array to start writing bytes from.
+ * @param len The number of bytes to write.
+ *
+ * @exception IOException If an error occurs
+ */
+public void
+write(byte[] buf, int offset, int len) throws IOException
+{
+ snk.write(buf, 0, len);
+}
+
+/*************************************************************************/
+
+/**
+ * This method flushes any unwritten bytes to the output and notifies
+ * any waiting readers that the pipe is ready to be read.
+ *
+ * @exception IOException If an error occurs.
+ */
+public void
+flush() throws IOException
+{
+ return;
+}
+
+} // class PipedOutputStream
+
diff --git a/libjava/java/io/PipedReader.java b/libjava/java/io/PipedReader.java
index faac986..72e516a 100644
--- a/libjava/java/io/PipedReader.java
+++ b/libjava/java/io/PipedReader.java
@@ -1,210 +1,519 @@
-// PipedReader.java - Piped character stream.
+/* PipedReader.java -- Input stream that reads from an output stream
+ Copyright (C) 1998, 1999 Free Software Foundation, Inc.
-/* Copyright (C) 1998, 1999 Free Software Foundation
+This file is part of GNU Classpath.
- This file is part of libgcj.
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+As a special exception, if you link this library with other files to
+produce an executable, this library does not by itself cause the
+resulting executable to be covered by the GNU General Public License.
+This exception does not however invalidate any other reasons why the
+executable file might be covered by the GNU General Public License. */
-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
+ * This class is an input stream that reads its chars from an output stream
+ * to which it is connected.
+ * <p>
+ * Data is read and written to an internal buffer. It is highly recommended
+ * that the <code>PipedReader</code> and connected <code>PipedWriter</code>
+ * be part of different threads. If they are not, there is a possibility
+ * that the read and write operations could deadlock their thread.
+ *
+ * @version 0.0
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class PipedReader extends Reader
+{
+
+/*************************************************************************/
+
+/*
+ * Class Variables
*/
-/* 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.
+/**
+ * The size of the internal buffer used for input/output. Note that this
+ * can be overriden by setting the system property
+ * <code>gnu.java.io.PipedReader.pipe_size</code> to the desired size shown
+ * in chars. This is not a standard part of the class library. Note that
+ * since this variable is <code>final</code>, it cannot be changed to refect
+ * the size specified in the property.
+ * <p>
+ * The value for this variable is 2048.
+ */
+private static final int PIPE_SIZE = 2048;
+
+/**
+ * This is the real pipe size. It defaults to PIPE_SIZE, unless overridden
+ * by use of the system property <code>gnu.java.io.PipedReader.pipe_size</code>.
+ */
+private static int pipe_size;
+
+/**
+ * This variable indicates whether or not the <code>read()</code> method will attempt
+ * return a short count if this will possibly keep the stream from blocking.
+ * The default for this is <code>false</code> because that is what what the JDK seems
+ * to imply in its javadocs. We set this to <code>false</code> if the system
+ * property <code>gnu.java.io.try_not_to_block</code> is set.
+ */
+private static boolean try_not_to_block = false;
+
+static
+{
+ pipe_size = Integer.getInteger("gnu.java.io.PipedReader.pipe_size",
+ PIPE_SIZE).intValue();
+
+ String block_prop = System.getProperty("gnu.java.io.try_not_to_block");
+ if (block_prop != null)
+ try_not_to_block = true;
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
*/
-public class PipedReader extends Reader
+/**
+ * This is the internal circular buffer used for storing chars written
+ * to the pipe and from which chars are read by this stream
+ */
+private char[] buffer = new char[pipe_size];
+
+/**
+ * The index into buffer where the chars written char the connected
+ * <code>PipedWriter</code> will be written. If this variables is less
+ * than 0, then the buffer is empty. If this variable is equal to
+ * <code>out</code>, then the buffer is full
+ */
+private int in = -1;
+
+/**
+ * This index into the buffer where chars will be read from.
+ */
+private int out = 0;
+
+/**
+ * This variable is <code>true</code> if this object has ever been connected
+ * to a <code>PipedWriter</code>, and <code>false</code> otherwise. It is used
+ * to detect an attempt to connect an already connected stream or to
+ * otherwise use the stream before it is connected.
+ */
+private boolean ever_connected = false;
+
+/**
+ * This variable is set to <code>true</code> if the <code>close()</code> method is
+ * called. This value is checked prevents a caller from re-opening the
+ * stream.
+ */
+private boolean closed = false;
+
+/**
+ * This variable is the PipedWriter to which this stream is connected.
+ */
+PipedWriter src;
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * This constructor creates a new <code>PipedReader</code> that is not
+ * connected to a <code>PipedWriter</code>. It must be connected before
+ * chars can be read from this stream.
+ */
+public
+PipedReader()
+{
+ return;
+}
+
+/*************************************************************************/
+
+/**
+ * This constructor creates a new <code>PipedReader</code> and connects
+ * it to the passed in <code>PipedWriter</code>. The stream is then read
+ * for reading.
+ *
+ * @param src The <code>PipedWriter</code> to connect this stream to
+ *
+ * @exception IOException If an error occurs
+ */
+public
+PipedReader(PipedWriter src) throws IOException
+{
+ connect(src);
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * This method connects this stream to the passed in <code>PipedWriter</code>.
+ * This stream is then ready for reading. If this stream is already
+ * connected or has been previously closed, then an exception is thrown
+ *
+ * @param src The <code>PipedWriter</code> to connect this stream to
+ *
+ * @exception IOException If an error occurs
+ */
+public void
+connect(PipedWriter src) throws IOException
+{
+ if (src == this.src)
+ return;
+
+ if (ever_connected)
+ throw new IOException("Already connected");
+
+ if (closed)
+ throw new IOException("Stream is closed and cannot be reopened");
+
+ synchronized (lock) {
+
+ src.connect(this);
+
+ ever_connected = true;
+
+ } // synchronized
+}
+
+/*************************************************************************/
+
+/**
+ * This methods closes the stream so that no more data can be read
+ * from it.
+ *
+ * @exception IOException If an error occurs
+ */
+public void
+close() throws IOException
+{
+ synchronized (lock) {
+
+ closed = true;
+ notifyAll();
+
+ } // synchronized
+}
+
+/*************************************************************************/
+
+/**
+ * This method determines whether or not this stream is ready to be read.
+ * If this metho returns <code>false</code> an attempt to read may (but is
+ * not guaranteed to) block.
+ *
+ * @return <code>true</code> if this stream is ready to be read, <code>false</code> otherwise
+ *
+ * @exception IOException If an error occurs
+ */
+public boolean
+ready() throws IOException
{
- 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;
+ if (in == -1)
+ return(false);
+
+ if (out == (in - 1))
+ return(false);
+
+ if ((out == pipe_size) && (in == 0))
+ return(false);
+
+ return(true);
}
+
+/*************************************************************************/
+
+/**
+ * This method reads a single char from the pipe and returns it as an
+ * <code>int</code>.
+ * <p>
+ * This method will block if no chars are available to be read.
+ *
+ * @return An char read from the pipe, or -1 if the end of stream is
+ * reached.
+ *
+ * @exception IOException If an error occurs.
+ */
+public int
+read() throws IOException
+{
+ char[] buf = new char[1];
+
+ return(read(buf, 0, buf.length));
+}
+
+/*************************************************************************/
+
+/**
+ * This method reads chars from the stream into a caller supplied buffer.
+ * It starts storing chars at position <code>offset</code> into the buffer and
+ * reads a maximum of <cod>>len</code> chars. Note that this method can actually
+ * read fewer than <code>len</code> chars. The actual number of chars read is
+ * returned. A -1 is returned to indicated that no chars can be read
+ * because the end of the stream was reached. If the stream is already
+ * closed, a -1 will again be returned to indicate the end of the stream.
+ * <p>
+ * This method will block if no chars are available to be read.
+ *
+ * @param buf The buffer into which chars will be stored
+ * @param offset The index into the buffer at which to start writing.
+ * @param len The maximum number of chars to read.
+ */
+public int
+read(char[] buf, int offset, int len) throws IOException
+{
+ if (!ever_connected)
+ throw new IOException("Not connected");
+
+ synchronized (lock) {
+
+ int chars_read = 0;
+ for (;;)
+ {
+ // If there are chars, take them
+ if (in != -1)
+ {
+ int desired_chars = len - chars_read;
+
+ // We are in a "wrap" condition
+ if (out > in)
+ {
+ if (desired_chars > (pipe_size - out))
+ {
+ if (in == 0)
+ desired_chars = (pipe_size - out) - 1;
+ else
+ desired_chars = pipe_size - out;
+
+ System.arraycopy(buffer, out, buf, offset + chars_read,
+ desired_chars);
+
+ chars_read += desired_chars;
+ out += desired_chars;
+ desired_chars = len - chars_read;
+
+ if (out == pipe_size)
+ out = 0;
+
+ notifyAll();
+ }
+ else
+ {
+ if ((out + desired_chars) == in)
+ --desired_chars;
+
+ if (((out + desired_chars) == pipe_size) && (in == 0))
+ desired_chars = (pipe_size - out) - 1;
+
+ System.arraycopy(buffer, out, buf, offset + chars_read,
+ desired_chars);
+
+ chars_read += desired_chars;
+ out += desired_chars;
+ desired_chars = len - chars_read;
+
+ if (out == pipe_size)
+ out = 0;
+
+ notifyAll();
+ }
+ }
+
+ // We are in a "no wrap" or condition (can also be fall through
+ // from above
+ if (in > out)
+ {
+ if (desired_chars >= ((in - out) - 1))
+ desired_chars = (in - out) - 1;
+
+ System.arraycopy(buffer, out, buf, offset + chars_read,
+ desired_chars);
+
+ chars_read += desired_chars;
+ out += desired_chars;
+ desired_chars = len - chars_read;
+
+ if (out == pipe_size)
+ out = 0;
+
+ notifyAll();
+ }
+ }
+
+ // If we are done, return
+ if (chars_read == len)
+ return(chars_read);
+
+ // Return a short count if necessary
+ if (chars_read < len)
+ if (try_not_to_block)
+ return(chars_read);
+
+ // Handle the case where the end of stream was encountered.
+ if (closed)
+ {
+ // We never let in == out so there might be one last char
+ // available that we have not copied yet.
+ if (in != -1)
+ {
+ buf[offset + chars_read] = buffer[out];
+ in = -1;
+ ++out;
+ ++chars_read;
+ }
+
+ if (chars_read != 0)
+ return(chars_read);
+ else
+ return(-1);
+ }
+
+ // Wait for a char to be read
+ try
+ {
+ wait();
+ }
+ catch(InterruptedException e) { ; }
+ }
+
+ } // synchronized
+}
+
+/*************************************************************************/
+
+/**
+ * This method is used by the connected <code>PipedWriter</code> to
+ * write chars into the buffer. It uses this method instead of directly
+ * writing the chars in order to obtain ownership of the object's monitor
+ * for the purposes of calling <code>notify</code>.
+ *
+ * @param buf The array containing chars to write to this stream
+ * @param offset The offset into the array to start writing from
+ * @param len The number of chars to write.
+ *
+ * @exception IOException If an error occurs
+ */
+void
+write(char[] buf, int offset, int len) throws IOException
+{
+ if (len <= 0)
+ return;
+
+ synchronized (lock) {
+
+ int total_written = 0;
+ while (total_written < len)
+ {
+ // If we are not at the end of the buffer with out = 0
+ if (!((in == (buffer.length - 1)) && (out == 0)))
+ {
+ // This is the "no wrap" situation
+ if ((in - 1) >= out)
+ {
+ int chars_written = 0;
+ if ((buffer.length - in) > (len - total_written))
+ chars_written = (len - total_written);
+ else if (out == 0)
+ chars_written = (buffer.length - in) - 1;
+ else
+ chars_written = (buffer.length - in);
+
+ if (chars_written > 0)
+ System.arraycopy(buf, offset + total_written, buffer, in,
+ chars_written);
+ total_written += chars_written;
+ in += chars_written;
+
+ if (in == buffer.length)
+ in = 0;
+
+ notifyAll();
+ }
+ // This is the "wrap" situtation
+ if ((out > in) && (total_written != len))
+ {
+ int chars_written = 0;
+
+ // Do special processing if we are at the beginning
+ if (in == -1)
+ {
+ in = 0;
+
+ if (buffer.length > len)
+ chars_written = len;
+ else
+ chars_written = buffer.length - 1;
+ }
+ else if (((out - in) - 1) < (len - total_written))
+ {
+ chars_written = (out - in) - 1;
+ }
+ else
+ {
+ chars_written = len - total_written;
+ }
+
+ // If the buffer is full, wait for it to empty out
+ if ((out - 1) == in)
+ {
+ try
+ {
+ wait();
+ }
+ catch (InterruptedException e)
+ {
+ continue;
+ }
+ }
+
+ System.arraycopy(buf, offset + total_written, buffer, in,
+ chars_written);
+ total_written += chars_written;
+ in += chars_written;
+
+ if (in == buffer.length)
+ in = 0;
+
+ notifyAll();
+ }
+ }
+ // Wait for some reads to occur before we write anything.
+ else
+ {
+ try
+ {
+ wait();
+ }
+ catch (InterruptedException e) { ; }
+ }
+ }
+ } // synchronized
+}
+
+} // class PipedReader
+
diff --git a/libjava/java/io/PipedWriter.java b/libjava/java/io/PipedWriter.java
index 7efed39..cc36acd 100644
--- a/libjava/java/io/PipedWriter.java
+++ b/libjava/java/io/PipedWriter.java
@@ -1,88 +1,217 @@
-// PipedWriter.java - Piped character stream.
+/* PipedWriter.java -- Write portion of piped streams.
+ Copyright (C) 1998 Free Software Foundation, Inc.
-/* Copyright (C) 1998, 1999 Free Software Foundation
+This file is part of GNU Classpath.
- This file is part of libgcj.
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+As a special exception, if you link this library with other files to
+produce an executable, this library does not by itself cause the
+resulting executable to be covered by the GNU General Public License.
+This exception does not however invalidate any other reasons why the
+executable file might be covered by the GNU General Public License. */
-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
+ * This class writes its chars to a <code>PipedReader</code> to
+ * which it is connected.
+ * <p>
+ * It is highly recommended that a <code>PipedWriter</code> and its
+ * connected <code>PipedReader</code> be in different threads. If
+ * they are in the same thread, read and write operations could deadlock
+ * the thread.
+ *
+ * @version 0.0
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class PipedWriter extends Writer
+{
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
*/
-/* 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.
+/**
+ * This is the <code>PipedReader</code> to which this object
+ * is connected.
+ */
+private PipedReader snk;
+
+/**
+ * This flag indicates whether or not this stream has ever been
+ * connected to an input stream
+ */
+private boolean ever_connected;
+
+/**
+ * This flag indicates whether the <code>close</code> method has ever
+ * been called for this stream.
+ */
+private boolean closed;
+
+/*************************************************************************/
+
+/**
+ * This method initializes a new <code>PipedWriter</code> instance.
+ * This constructor creates an unconnected object. It must be connected
+ * to a <code>PipedReader</code> object using the <code>connect</code>
+ * method prior to writing any data or an exception will be thrown.
+ */
+public
+PipedWriter()
+{
+ ; // Do Nothing
+}
+
+/*************************************************************************/
+
+/**
+ * This method initializes a new <code>PipedWriter</code> instance
+ * to write to the specified <code>PipedReader</code>. This stream
+ * is then ready for writing.
+ *
+ * @param snk The <code>PipedReader</code> to connect this stream to.
+ *
+ * @exception IOException If an error occurs
+ */
+public
+PipedWriter(PipedReader snk) throws IOException
+{
+ connect(snk);
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Methods
*/
-public class PipedWriter extends Writer
+/**
+ * This method connects this object to the specified
+ * <code>PipedReader</code> object. This stream will then be ready
+ * for writing. If this stream is already connected or has been
+ * previously closed, then an exception is thrown.
+ *
+ * @param snk The <code>PipedReader</code> to connect this stream to
+ *
+ * @exception IOException If an error occurs
+ */
+public void
+connect(PipedReader snk) throws IOException
+{
+ if (snk == this.snk)
+ return;
+
+ if (ever_connected)
+ throw new IOException("Already connected");
+
+ if (closed)
+ throw new IOException("Stream is closed and cannot be reopened");
+
+ synchronized (lock) {
+
+ this.snk = snk;
+ ever_connected = true;
+ snk.src = this;
+
+ snk.connect(this);
+
+ } // synchronized
+}
+
+/*************************************************************************/
+
+/**
+ * This method closes this stream so that no more data can be written
+ * to it. Any further attempts to write to this stream may throw an
+ * exception
+ *
+ * @exception IOException If an error occurs
+ */
+public void
+close() throws IOException
{
- public void close () throws IOException
- {
- closed = true;
- }
-
- public void connect (PipedReader sink) throws IOException
- {
- if (closed)
- throw new IOException ("already closed");
- if (reader != null)
- {
- if (reader == sink)
- return;
- throw new IOException ("already connected");
- }
- try
- {
- reader = sink;
- reader.connect(this);
- }
- catch (IOException e)
- {
- reader = null;
- throw e;
- }
- }
-
- public void flush () throws IOException
- {
- // We'll throw an exception if we're closed, but there's nothing
- // else to do here.
- if (closed)
- throw new IOException ("closed");
- }
-
- public PipedWriter ()
- {
- super ();
- closed = false;
- }
-
- public PipedWriter (PipedReader sink) throws IOException
- {
- super ();
- closed = false;
- connect (sink);
- }
-
- public void write (char buffer[], int offset, int count) throws IOException
- {
- if (closed)
- throw new IOException ("closed");
- reader.receive(buffer, offset, count);
- }
-
- boolean isClosed ()
- {
- return closed;
- }
-
- // The associated reader.
- private PipedReader reader;
- private boolean closed;
+ synchronized (lock) {
+
+ closed = true;
+ snk.close();
+ notifyAll();
+
+ } // synchronized
}
+
+/*************************************************************************/
+
+/**
+ * This methods writes a single byte of data to the pipe. This call may
+ * block if the pipe is full.
+ *
+ * @param c The <code>char</code> to write, passed as an <code>int</code>.
+ *
+ * @exception IOException If an error occurs.
+ */
+public void
+write(int c) throws IOException
+{
+ char[] buf = new char[1];
+ buf[0] = (char)c;
+
+ write(buf, 0, buf.length);
+}
+
+/*************************************************************************/
+
+/**
+ * This method writes <code>len</code> chars of data from the char array
+ * <code>buf</code> starting at index <code>offset</code> in the array
+ * to the stream. Note that this method will block if the
+ * <code>PipedReader</code> to which this object is connected has
+ * a buffer that cannot hold all of the chars to be written.
+ *
+ * @param buf The array containing chars to write to thes stream.
+ * @param offset The index into the array to start writing chars from.
+ * @param len The number of chars to write.
+ *
+ * @exception IOException If an error occurs
+ */
+public void
+write(char[] buf, int offset, int len) throws IOException
+{
+ snk.write(buf, 0, len);
+}
+
+/*************************************************************************/
+
+/**
+ * This method flushes any unwritten chars to the underlying output
+ * sink. This method does nothing in this class because this class does
+ * not buffer any chars.
+ *
+ * @exception IOException If an error occurs
+ */
+public void
+flush() throws IOException
+{
+ ; // Do Nothing
+}
+
+} // class PipedWriter
+