211 lines
4.5 KiB
Java
211 lines
4.5 KiB
Java
|
// 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;
|
||
|
}
|