aboutsummaryrefslogtreecommitdiff
path: root/libjava/java/io
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/java/io')
-rw-r--r--libjava/java/io/BufferedInputStream.java168
-rw-r--r--libjava/java/io/BufferedOutputStream.java76
-rw-r--r--libjava/java/io/BufferedReader.java373
-rw-r--r--libjava/java/io/BufferedWriter.java129
-rw-r--r--libjava/java/io/ByteArrayInputStream.java113
-rw-r--r--libjava/java/io/ByteArrayOutputStream.java108
-rw-r--r--libjava/java/io/CharArrayReader.java152
-rw-r--r--libjava/java/io/CharArrayWriter.java122
-rw-r--r--libjava/java/io/CharConversionException.java34
-rw-r--r--libjava/java/io/DataInput.java41
-rw-r--r--libjava/java/io/DataInputStream.java249
-rw-r--r--libjava/java/io/DataOutput.java44
-rw-r--r--libjava/java/io/DataOutputStream.java165
-rw-r--r--libjava/java/io/EOFException.java34
-rw-r--r--libjava/java/io/File.java288
-rw-r--r--libjava/java/io/FileDescriptor.java87
-rw-r--r--libjava/java/io/FileInputStream.java96
-rw-r--r--libjava/java/io/FileNotFoundException.java34
-rw-r--r--libjava/java/io/FileOutputStream.java93
-rw-r--r--libjava/java/io/FileReader.java35
-rw-r--r--libjava/java/io/FileWriter.java44
-rw-r--r--libjava/java/io/FilenameFilter.java26
-rw-r--r--libjava/java/io/FilterInputStream.java75
-rw-r--r--libjava/java/io/FilterOutputStream.java61
-rw-r--r--libjava/java/io/FilterReader.java72
-rw-r--r--libjava/java/io/FilterWriter.java59
-rw-r--r--libjava/java/io/IOException.java34
-rw-r--r--libjava/java/io/InputStream.java104
-rw-r--r--libjava/java/io/InputStreamReader.java151
-rw-r--r--libjava/java/io/InterruptedIOException.java36
-rw-r--r--libjava/java/io/LineNumberInputStream.java143
-rw-r--r--libjava/java/io/LineNumberReader.java245
-rw-r--r--libjava/java/io/OutputStream.java48
-rw-r--r--libjava/java/io/OutputStreamWriter.java155
-rw-r--r--libjava/java/io/PipedInputStream.java242
-rw-r--r--libjava/java/io/PipedOutputStream.java94
-rw-r--r--libjava/java/io/PipedReader.java210
-rw-r--r--libjava/java/io/PipedWriter.java88
-rw-r--r--libjava/java/io/PrintStream.java236
-rw-r--r--libjava/java/io/PrintWriter.java286
-rw-r--r--libjava/java/io/PushbackInputStream.java124
-rw-r--r--libjava/java/io/PushbackReader.java136
-rw-r--r--libjava/java/io/RandomAccessFile.java249
-rw-r--r--libjava/java/io/Reader.java87
-rw-r--r--libjava/java/io/SequenceInputStream.java112
-rw-r--r--libjava/java/io/Serializable.java21
-rw-r--r--libjava/java/io/StreamTokenizer.java433
-rw-r--r--libjava/java/io/StringBufferInputStream.java83
-rw-r--r--libjava/java/io/StringReader.java139
-rw-r--r--libjava/java/io/StringWriter.java80
-rw-r--r--libjava/java/io/SyncFailedException.java34
-rw-r--r--libjava/java/io/UTFDataFormatException.java34
-rw-r--r--libjava/java/io/UnsupportedEncodingException.java32
-rw-r--r--libjava/java/io/Writer.java67
-rw-r--r--libjava/java/io/natFile.cc273
-rw-r--r--libjava/java/io/natFileDescriptorEcos.cc132
-rw-r--r--libjava/java/io/natFileDescriptorPosix.cc264
57 files changed, 7150 insertions, 0 deletions
diff --git a/libjava/java/io/BufferedInputStream.java b/libjava/java/io/BufferedInputStream.java
new file mode 100644
index 0000000..698abf6
--- /dev/null
+++ b/libjava/java/io/BufferedInputStream.java
@@ -0,0 +1,168 @@
+/* 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 Warren Levy <warrenl@cygnus.com>
+ * @date October 8, 1998.
+ */
+/* 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.
+ */
+
+public class BufferedInputStream extends FilterInputStream
+{
+ /* Internal buffer array for data. */
+ protected byte[] buf;
+
+ /* Index one greater than the last valid byte in the buffer. */
+ protected int count = 0;
+
+ /* The current position in the buffer. */
+ protected int pos = 0;
+
+ /* The value of pos the last time mark() was called. */
+ protected int markpos = -1;
+
+ /* The maximum read-ahead allowed before calls to reset() fail. */
+ protected int marklimit = 0;
+
+ public BufferedInputStream(InputStream in)
+ {
+ this(in, 2048);
+ }
+
+ public BufferedInputStream(InputStream in, int size)
+ {
+ super(in);
+ if (size <= 0)
+ throw new IllegalArgumentException();
+ buf = new byte[size];
+ }
+
+ public synchronized int available() throws IOException
+ {
+ return count - pos + super.available();
+ }
+
+ public void close() throws IOException
+ {
+ // Free up the array memory.
+ buf = null;
+ super.close();
+ }
+
+ public synchronized void mark(int readlimit)
+ {
+ marklimit = readlimit;
+ markpos = pos;
+ }
+
+ public boolean markSupported()
+ {
+ return true;
+ }
+
+ public synchronized int read() throws IOException
+ {
+ if (pos >= count && !refill())
+ return -1; // EOF
+
+ if (markpos >= 0 && pos - markpos > marklimit)
+ markpos = -1;
+
+ return ((int) buf[pos++]) & 0xFF;
+ }
+
+ public synchronized int read(byte[] b, int off, int len) throws IOException
+ {
+ if (off < 0 || len < 0 || off + len > b.length)
+ throw new ArrayIndexOutOfBoundsException();
+
+ if (pos >= count && !refill())
+ return -1; // No bytes were read before EOF.
+
+ int remain = Math.min(count - pos, len);
+ System.arraycopy(buf, pos, b, off, remain);
+ pos += remain;
+
+ if (markpos >= 0 && pos - markpos > marklimit)
+ markpos = -1;
+
+ return remain;
+ }
+
+ public synchronized void reset() throws IOException
+ {
+ if (markpos < 0)
+ throw new IOException();
+
+ pos = markpos;
+ }
+
+ public synchronized long skip(long n) throws IOException
+ {
+ final long origN = n;
+
+ while (n > 0L)
+ {
+ if (pos >= count && !refill())
+ if (n < origN)
+ break;
+ else
+ return -1; // No bytes were read before EOF.
+
+ int numread = (int) Math.min((long) (count - pos), n);
+ pos += numread;
+ n -= numread;
+
+ if (markpos >= 0 && pos - markpos > marklimit)
+ markpos = -1;
+ }
+
+ return origN - n;
+ }
+
+ private boolean refill() throws IOException
+ {
+ if (markpos < 0)
+ count = pos = 0;
+ else if (markpos > 0)
+ {
+ // Shift the marked bytes (if any) to the beginning of the array
+ // but don't grow it. This saves space in case a reset is done
+ // before we reach the max capacity of this array.
+ System.arraycopy(buf, markpos, buf, 0, count - markpos);
+ count -= markpos;
+ pos -= markpos;
+ markpos = 0;
+ }
+ else if (marklimit >= buf.length) // BTW, markpos == 0
+ {
+ // Need to grow the buffer now to have room for marklimit bytes.
+ // Note that the new buffer is one greater than marklimit.
+ // This is so that there will be one byte past marklimit to be read
+ // before having to call refill again, thus allowing marklimit to be
+ // invalidated. That way refill doesn't have to check marklimit.
+ byte[] newbuf = new byte[marklimit + 1];
+ System.arraycopy(buf, 0, newbuf, 0, count);
+ buf = newbuf;
+ }
+
+ int numread = super.read(buf, count, buf.length - count);
+
+ if (numread < 0) // EOF
+ return false;
+
+ count += numread;
+ return true;
+ }
+}
diff --git a/libjava/java/io/BufferedOutputStream.java b/libjava/java/io/BufferedOutputStream.java
new file mode 100644
index 0000000..d37ed5d
--- /dev/null
+++ b/libjava/java/io/BufferedOutputStream.java
@@ -0,0 +1,76 @@
+// BufferedOutputStream.java - A buffered 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 24, 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 version 1.1.
+ */
+
+public class BufferedOutputStream extends FilterOutputStream
+{
+ public BufferedOutputStream (OutputStream ox)
+ {
+ this (ox, 512);
+ }
+
+ public BufferedOutputStream (OutputStream ox, int size)
+ {
+ super (ox);
+ buf = new byte[size];
+ }
+
+ public synchronized void flush () throws IOException
+ {
+ out.write(buf, 0, count);
+ count = 0;
+ out.flush();
+ }
+
+ public synchronized void write (int b) throws IOException
+ {
+ if (count < buf.length)
+ buf[count++] = (byte) b;
+ else
+ {
+ out.write(buf, 0, count);
+ count = 0;
+ out.write(b);
+ }
+ }
+
+ public synchronized void write (byte[] b, int off, int len)
+ throws IOException, NullPointerException, IndexOutOfBoundsException
+ {
+ // If LEN < 0 then the downstream write will fail for us.
+ if (len >= 0 && count + len < buf.length)
+ {
+ System.arraycopy(b, off, buf, count, len);
+ count += len;
+ }
+ else
+ {
+ out.write(buf, 0, count);
+ count = 0;
+ out.write(b, off, len);
+ }
+ }
+
+ // The buffer.
+ protected byte[] buf;
+ // Number of valid bytes in BUF.
+ protected int count;
+}
diff --git a/libjava/java/io/BufferedReader.java b/libjava/java/io/BufferedReader.java
new file mode 100644
index 0000000..19e371a
--- /dev/null
+++ b/libjava/java/io/BufferedReader.java
@@ -0,0 +1,373 @@
+/* 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 Per Bothner <bothner@cygnus.com>
+ * @date April 22, 1998.
+ */
+/* Written using "Java Class Libraries", 2nd edition, plus online
+ * API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct.
+ */
+
+public class BufferedReader extends Reader
+{
+ Reader in;
+ char[] buffer;
+ /* Index of current read position. Must be >= 0 and <= limit. */
+ /* There is a special case where pos may be equal to limit+1; this
+ * is used as an indicator that a readLine was done with a '\r' was
+ * the very last char in the buffer. Since we don't want to read-ahead
+ * and potentially block, we set pos this way to indicate the situation
+ * and deal with it later. Doing it this way rather than having a
+ * separate boolean field to indicate the condition has the advantage
+ * that it is self-clearing on things like mark/reset.
+ */
+ int pos;
+ /* Limit of valid data in buffer. Must be >= pos and <= buffer.length. */
+ /* This can be < pos in the one special case described above. */
+ int limit;
+
+ /* The value -1 means there is no mark, or the mark has been invalidated.
+ Otherwise, markPos is the index in the buffer of the marked position.
+ Must be >= 0 and <= pos.
+ Note we do not explicitly store the read-limit.
+ The implicit read-limit is (buffer.length - markPos), which is
+ guaranteed to be >= the read-limit requested in the call to mark. */
+ int markPos = -1;
+
+ public BufferedReader(Reader in)
+ {
+ this(in, 8192);
+ }
+
+ public BufferedReader(Reader in, int size)
+ {
+ super(in.lock);
+ this.in = in;
+ buffer = new char[size];
+ }
+
+ public void close() throws IOException
+ {
+ synchronized (lock)
+ {
+ if (in != null)
+ in.close();
+ in = null;
+ buffer = null;
+ }
+ }
+
+ public boolean markSupported()
+ {
+ return true;
+ }
+
+ public void mark(int readLimit) throws IOException
+ {
+ synchronized (lock)
+ {
+ // In this method we need to be aware of the special case where
+ // pos + 1 == limit. This indicates that a '\r' was the last char
+ // in the buffer during a readLine. We'll want to maintain that
+ // condition after we shift things around and if a larger buffer is
+ // needed to track readLimit, we'll have to make it one element
+ // larger to ensure we don't invalidate the mark too early, if the
+ // char following the '\r' is NOT a '\n'. This is ok because, per
+ // the spec, we are not required to invalidate when passing readLimit.
+ //
+ // Note that if 'pos > limit', then doing 'limit -= pos' will cause
+ // limit to be negative. This is the only way limit will be < 0.
+
+ if (pos + readLimit > limit)
+ {
+ char[] old_buffer = buffer;
+ int extraBuffSpace = 0;
+ if (pos > limit)
+ extraBuffSpace = 1;
+ if (readLimit + extraBuffSpace > limit)
+ buffer = new char[readLimit + extraBuffSpace];
+ limit -= pos;
+ if (limit >= 0)
+ {
+ System.arraycopy(old_buffer, pos, buffer, 0, limit);
+ pos = 0;
+ }
+ }
+
+ if (limit < 0)
+ {
+ // Maintain the relationship of 'pos > limit'.
+ pos = 1;
+ limit = markPos = 0;
+ }
+ else
+ markPos = pos;
+ // Now pos + readLimit <= buffer.length. thus if we need to read
+ // beyond buffer.length, then we are allowed to invalidate markPos.
+ }
+ }
+
+ public void reset() throws IOException
+ {
+ synchronized (lock)
+ {
+ if (markPos < 0)
+ throw new IOException("mark never set or invalidated");
+
+ // Need to handle the extremely unlikely case where a readLine was
+ // done with a '\r' as the last char in the buffer; which was then
+ // immediately followed by a mark and a reset with NO intervening
+ // read of any sort. In that case, setting pos to markPos would
+ // lose that info and a subsequent read would thus not skip a '\n'
+ // (if one exists). The value of limit in this rare case is zero.
+ // We can assume that if limit is zero for other reasons, then
+ // pos is already set to zero and doesn't need to be readjusted.
+ if (limit > 0)
+ pos = markPos;
+ }
+ }
+
+ public boolean ready() throws IOException
+ {
+ synchronized (lock)
+ {
+ return pos < limit || in.ready();
+ }
+ }
+
+ public int read(char[] buf, int offset, int count) throws IOException
+ {
+ synchronized (lock)
+ {
+ // Once again, we need to handle the special case of a readLine
+ // that has a '\r' at the end of the buffer. In this case, we'll
+ // need to skip a '\n' if it is the next char to be read.
+ // This special case is indicated by 'pos > limit'.
+ boolean retAtEndOfBuffer = false;
+
+ int avail = limit - pos;
+ if (count > avail)
+ {
+ if (avail > 0)
+ count = avail;
+ else // pos >= limit
+ {
+ if (limit == buffer.length)
+ markPos = -1; // read too far - invalidate the mark.
+ if (pos > limit)
+ {
+ // Set a boolean and make pos == limit to simplify things.
+ retAtEndOfBuffer = true;
+ --pos;
+ }
+ if (markPos < 0)
+ {
+ // Optimization: can read directly into buf.
+ if (count >= buffer.length && !retAtEndOfBuffer)
+ return in.read(buf, offset, count);
+ pos = limit = 0;
+ }
+ avail = in.read(buffer, limit, buffer.length - limit);
+ if (retAtEndOfBuffer && avail > 0 && buffer[limit] == '\n')
+ {
+ --avail;
+ limit++;
+ }
+ if (avail < count)
+ {
+ if (avail <= 0)
+ return avail;
+ count = avail;
+ }
+ limit += avail;
+ }
+ }
+ System.arraycopy(buffer, pos, buf, offset, count);
+ pos += count;
+ return count;
+ }
+ }
+
+ /* Read more data into the buffer. Update pos and limit appropriatly.
+ Assumes pos==limit initially. May invalidate the mark if read too much.
+ Return number of chars read (never 0), or -1 on eof. */
+ private int fill() throws IOException
+ {
+ // Handle the special case of a readLine that has a '\r' at the end of
+ // the buffer. In this case, we'll need to skip a '\n' if it is the
+ // next char to be read. This special case is indicated by 'pos > limit'.
+ boolean retAtEndOfBuffer = false;
+ if (pos > limit)
+ {
+ retAtEndOfBuffer = true;
+ --pos;
+ }
+
+ if (markPos >= 0 && limit == buffer.length)
+ markPos = -1;
+ if (markPos <= 0)
+ pos = limit = 0;
+ int count = in.read(buffer, limit, buffer.length - limit);
+ if (count > 0)
+ limit += count;
+
+ if (retAtEndOfBuffer && buffer[pos] == '\n')
+ {
+ --count;
+ pos++;
+ }
+
+ return count;
+ }
+
+ public int read() throws IOException
+ {
+ synchronized (lock)
+ {
+ if (pos >= limit && fill () <= 0)
+ return -1;
+ return buffer[pos++];
+ }
+ }
+
+ /* Return the end of the line starting at this.pos and ending at limit.
+ * The index returns is *before* any line terminators, or limit
+ * if no line terminators were found.
+ */
+ private int lineEnd(int limit)
+ {
+ int i = pos;
+ for (; i < limit; i++)
+ {
+ char ch = buffer[i];
+ if (ch == '\n' || ch == '\r')
+ break;
+ }
+ return i;
+ }
+
+ public String readLine() throws IOException
+ {
+ // Handle the special case where a previous readLine (with no intervening
+ // reads/skips) had a '\r' at the end of the buffer.
+ // In this case, we'll need to skip a '\n' if it's the next char to be read.
+ // This special case is indicated by 'pos > limit'.
+ if (pos > limit)
+ {
+ int ch = read();
+ if (ch < 0)
+ return null;
+ if (ch != '\n')
+ --pos;
+ }
+ int i = lineEnd(limit);
+ if (i < limit)
+ {
+ String str = new String(buffer, pos, i - pos);
+ pos = i + 1;
+ // If the last char in the buffer is a '\r', we must remember
+ // to check if the next char to be read after the buffer is refilled
+ // is a '\n'. If so, skip it. To indicate this condition, we set pos
+ // to be limit + 1, which normally is never possible.
+ if (buffer[i] == '\r')
+ if (pos == limit || buffer[pos] == '\n')
+ pos++;
+ return str;
+ }
+ StringBuffer sbuf = new StringBuffer(200);
+ sbuf.append(buffer, pos, i - pos);
+ pos = i;
+ // We only want to return null when no characters were read before
+ // EOF. So we must keep track of this separately. Otherwise we
+ // would treat an empty `sbuf' as an EOF condition, which is wrong
+ // when there is just a newline.
+ boolean eof = false;
+ for (;;)
+ {
+ int ch = read();
+ if (ch < 0)
+ {
+ eof = true;
+ break;
+ }
+ if (ch == '\n' || ch == '\r')
+ {
+ // Check here if a '\r' was the last char in the buffer; if so,
+ // mark it as in the comment above to indicate future reads
+ // should skip a newline that is the next char read after
+ // refilling the buffer.
+ if (ch == '\r')
+ if (pos == limit || buffer[pos] == '\n')
+ pos++;
+ break;
+ }
+ i = lineEnd(limit);
+ sbuf.append(buffer, pos - 1, i - (pos - 1));
+ pos = i;
+ }
+ return (sbuf.length() == 0 && eof) ? null : sbuf.toString();
+ }
+
+ public long skip(long count) throws IOException
+ {
+ if (count <= 0)
+ return 0;
+ synchronized (lock)
+ {
+ // Yet again, we need to handle the special case of a readLine
+ // that has a '\r' at the end of the buffer. In this case, we need
+ // to ignore a '\n' if it is the next char to be read.
+ // This special case is indicated by 'pos > limit' (i.e. avail < 0).
+ // To simplify things, if we're dealing with the special case for
+ // readLine, just read the next char (since the fill method will
+ // skip the '\n' for us). By doing this, we'll have to back up pos.
+ // That's easier than trying to keep track of whether we've skipped
+ // one element or not.
+ int ch;
+ if (pos > limit)
+ if ((ch = read()) < 0)
+ return 0;
+ else
+ --pos;
+
+ int avail = limit - pos;
+
+ if (count < avail)
+ {
+ pos += count;
+ return count;
+ }
+
+ pos = limit;
+ long todo = count - avail;
+ if (todo > buffer.length)
+ {
+ markPos = -1;
+ todo -= in.skip(todo);
+ }
+ else
+ {
+ while (todo > 0)
+ {
+ avail = fill();
+ if (avail <= 0)
+ break;
+ if (avail > todo)
+ avail = (int) todo;
+ pos += avail;
+ todo -= avail;
+ }
+ }
+ return count - todo;
+ }
+ }
+}
diff --git a/libjava/java/io/BufferedWriter.java b/libjava/java/io/BufferedWriter.java
new file mode 100644
index 0000000..85aceed
--- /dev/null
+++ b/libjava/java/io/BufferedWriter.java
@@ -0,0 +1,129 @@
+// BufferedWriter.java - Filtered character output 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 version 1.1.
+ */
+
+// Why not extend FilterWriter?
+public class BufferedWriter extends Writer
+{
+ public BufferedWriter (Writer out)
+ {
+ this (out, 8192);
+ }
+
+ public BufferedWriter (Writer ox, int size)
+ {
+ super (ox);
+ out = ox;
+ buffer = new char[size];
+ count = 0;
+ }
+
+ public void close () throws IOException
+ {
+ localFlush ();
+ out.close();
+ }
+
+ public void flush () throws IOException
+ {
+ localFlush ();
+ out.flush();
+ }
+
+ public void newLine () throws IOException
+ {
+ write (System.getProperty("line.separator"));
+ }
+
+ public void write (int oneChar) throws IOException
+ {
+ synchronized (lock)
+ {
+ buffer[count++] = (char) oneChar;
+ if (count == buffer.length)
+ localFlush ();
+ }
+ }
+
+ public void write (char[] buf, int offset, int len) throws IOException
+ {
+ if (offset < 0 || len < 0 || offset + len > buf.length)
+ throw new ArrayIndexOutOfBoundsException ();
+
+ synchronized (lock)
+ {
+ // Bypass buffering if there is too much incoming data.
+ if (count + len > buffer.length)
+ {
+ localFlush ();
+ out.write(buf, offset, len);
+ }
+ else
+ {
+ System.arraycopy(buf, offset, buffer, count, len);
+ count += len;
+ if (count == buffer.length)
+ localFlush ();
+ }
+ }
+ }
+
+ public void write (String str, int offset, int len) throws IOException
+ {
+ if (offset < 0 || len < 0 || offset + len < str.length())
+ throw new ArrayIndexOutOfBoundsException ();
+
+ synchronized (lock)
+ {
+ if (count + len > buffer.length)
+ {
+ localFlush ();
+ out.write(str, offset, len);
+ }
+ else
+ {
+ str.getChars(offset, offset + len, buffer, count);
+ count += len;
+ if (count == buffer.length)
+ localFlush ();
+ }
+ }
+ }
+
+ private final void localFlush () throws IOException
+ {
+ if (count > 0)
+ {
+ synchronized (lock)
+ {
+ out.write(buffer, 0, count);
+ count = 0;
+ }
+ }
+ }
+
+ // The downstream writer.
+ private Writer out;
+ // The character buffer.
+ char[] buffer;
+ // Number of valid chars in buffer.
+ int count;
+}
diff --git a/libjava/java/io/ByteArrayInputStream.java b/libjava/java/io/ByteArrayInputStream.java
new file mode 100644
index 0000000..9b9bf96
--- /dev/null
+++ b/libjava/java/io/ByteArrayInputStream.java
@@ -0,0 +1,113 @@
+/* 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 Warren Levy <warrenl@cygnus.com>
+ * @date October 7, 1998.
+ */
+
+/* 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
+ */
+
+public class ByteArrayInputStream extends InputStream
+{
+ /* An array of bytes provided by the creator of the stream. */
+ protected byte[] buf;
+
+ /* Position of the next byte in buf to be read. */
+ protected int pos;
+
+ /* The currently marked position in the stream. */
+ protected int mark;
+
+ /* The index in buf one greater than the last valid character. */
+ protected int count;
+
+ public ByteArrayInputStream(byte[] buffer)
+ {
+ this(buffer, 0, buffer.length);
+ }
+
+ public ByteArrayInputStream(byte[] buffer, int offset, int length)
+ {
+ buf = buffer;
+
+ count = offset + length;
+ if (count > buf.length)
+ count = buf.length;
+
+ pos = offset;
+ // TBD: What should we do if pos is neg. or > count? E.g. throw exc. or:
+ // if (pos < 0 || pos > count)
+ // pos = 0;
+
+ mark = pos;
+ }
+
+ public synchronized int available()
+ {
+ return count - pos;
+ }
+
+ public synchronized void mark(int readAheadLimit)
+ {
+ // readAheadLimit is ignored per Java Class Lib. book, p.220.
+ mark = pos;
+ }
+
+ public boolean markSupported()
+ {
+ return true;
+ }
+
+ public synchronized int read()
+ {
+ if (pos < 0)
+ throw new ArrayIndexOutOfBoundsException(pos);
+
+ if (pos < count)
+ return ((int) buf[pos++]) & 0xFF;
+ return -1;
+ }
+
+ public synchronized int read(byte[] b, int off, int len)
+ {
+ /* Don't need to check pos value, arraycopy will check it. */
+ if (off < 0 || len < 0 || off + len > b.length)
+ throw new ArrayIndexOutOfBoundsException();
+
+ if (pos >= count)
+ return -1;
+
+ int numBytes = Math.min(count - pos, len);
+ System.arraycopy(buf, pos, b, off, numBytes);
+ pos += numBytes;
+ return numBytes;
+ }
+
+ public synchronized void reset()
+ {
+ pos = mark;
+ }
+
+ public synchronized long skip(long n)
+ {
+ // Even though the var numBytes is a long, in reality it can never
+ // be larger than an int since the result of subtracting 2 positive
+ // ints will always fit in an int. Since we have to return a long
+ // anyway, numBytes might as well just be a long.
+ long numBytes = Math.min((long) (count - pos), n < 0 ? 0L : n);
+ pos += numBytes;
+ return numBytes;
+ }
+}
diff --git a/libjava/java/io/ByteArrayOutputStream.java b/libjava/java/io/ByteArrayOutputStream.java
new file mode 100644
index 0000000..4d5f224
--- /dev/null
+++ b/libjava/java/io/ByteArrayOutputStream.java
@@ -0,0 +1,108 @@
+// ByteArrayOutputStream.java - Write bytes to an array.
+
+/* 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 24, 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 version 1.1.
+ */
+
+public class ByteArrayOutputStream extends OutputStream
+{
+ public ByteArrayOutputStream ()
+ {
+ this (32);
+ }
+
+ public ByteArrayOutputStream (int size)
+ {
+ buf = new byte[size];
+ count = 0;
+ }
+
+ public synchronized void reset ()
+ {
+ count = 0;
+ }
+
+ public int size ()
+ {
+ return count;
+ }
+
+ public synchronized byte[] toByteArray ()
+ {
+ byte[] ret = new byte[count];
+ System.arraycopy(buf, 0, ret, 0, count);
+ return ret;
+ }
+
+ public String toString ()
+ {
+ return new String (buf, 0, count);
+ }
+
+ public String toString (String enc) throws UnsupportedEncodingException
+ {
+ return new String (buf, 0, count, enc);
+ }
+
+ // This is deprecated in the JCL book.
+ public String toString (int hibyte)
+ {
+ return new String (buf, 0, count, hibyte);
+ }
+
+ // Resize buffer to accomodate new bytes.
+ private void resize (int add)
+ {
+ if (count + add >= buf.length)
+ {
+ int newlen = buf.length * 2;
+ if (count + add > newlen)
+ newlen = count + add;
+ byte[] newbuf = new byte[newlen];
+ System.arraycopy(buf, 0, newbuf, 0, count);
+ buf = newbuf;
+ }
+ }
+
+ public synchronized void write (int oneByte)
+ {
+ resize (1);
+ buf[count++] = (byte) oneByte;
+ }
+
+ public synchronized void write (byte[] buffer, int offset, int add)
+ {
+ // If ADD < 0 then arraycopy will throw the appropriate error for
+ // us.
+ if (add >= 0)
+ resize (add);
+ System.arraycopy(buffer, offset, buf, count, add);
+ count += add;
+ }
+
+ public synchronized void writeTo (OutputStream out) throws IOException
+ {
+ out.write(buf, 0, count);
+ }
+
+ // The byte buffer.
+ protected byte[] buf;
+ // Number of valid bytes in buffer.
+ protected int count;
+}
diff --git a/libjava/java/io/CharArrayReader.java b/libjava/java/io/CharArrayReader.java
new file mode 100644
index 0000000..a43e8da
--- /dev/null
+++ b/libjava/java/io/CharArrayReader.java
@@ -0,0 +1,152 @@
+/* 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 Warren Levy <warrenl@cygnus.com>
+ * @date October 16, 1998.
+ */
+
+/* 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
+ */
+
+public class CharArrayReader extends Reader
+{
+ /* An array of chars provided by the creator of the stream. */
+ protected char[] buf;
+
+ /* Position of the next char in buf to be read. */
+ protected int pos;
+
+ /* The currently marked position in the stream. */
+ protected int markedPos;
+
+ /* The index in buf one greater than the last valid character. */
+ protected int count;
+
+ public CharArrayReader(char[] buffer)
+ {
+ this(buffer, 0, buffer.length);
+ }
+
+ public CharArrayReader(char[] buffer, int offset, int length)
+ {
+ super();
+ buf = buffer;
+
+ count = offset + length;
+ if (count > buf.length)
+ count = buf.length;
+
+ pos = offset;
+ // TBD: What should we do if pos is neg. or > count? E.g. throw exc. or:
+ // if (pos < 0 || pos > count)
+ // pos = 0;
+
+ markedPos = pos;
+ }
+
+ public void close()
+ {
+ synchronized (lock)
+ {
+ buf = null;
+ }
+ }
+
+ public void mark(int readAheadLimit)
+ {
+ synchronized (lock)
+ {
+ // readAheadLimit is ignored per Java Class Lib. book, p. 318.
+ markedPos = pos;
+ }
+ }
+
+ public boolean markSupported()
+ {
+ return true;
+ }
+
+ public int read() throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException();
+
+ if (pos < 0)
+ throw new ArrayIndexOutOfBoundsException(pos);
+
+ if (pos < count)
+ return ((int) buf[pos++]) & 0xFFFF;
+ return -1;
+ }
+ }
+
+ public int read(char[] b, int off, int len) throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException();
+
+ /* Don't need to check pos value, arraycopy will check it. */
+ if (off < 0 || len < 0 || off + len > b.length)
+ throw new ArrayIndexOutOfBoundsException();
+
+ if (pos >= count)
+ return -1;
+
+ int numChars = Math.min(count - pos, len);
+ System.arraycopy(buf, pos, b, off, numChars);
+ pos += numChars;
+ return numChars;
+ }
+ }
+
+ public boolean ready() throws IOException
+ {
+ if (buf == null)
+ throw new IOException();
+
+ return true;
+ }
+
+ public void reset() throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException();
+
+ pos = markedPos;
+ }
+ }
+
+ public long skip(long n) throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException();
+
+ // Even though the var numChars is a long, in reality it can never
+ // be larger than an int since the result of subtracting 2 positive
+ // ints will always fit in an int. Since we have to return a long
+ // anyway, numChars might as well just be a long.
+ long numChars = Math.min((long) (count - pos), n < 0 ? 0L : n);
+ pos += numChars;
+ return numChars;
+ }
+ }
+}
diff --git a/libjava/java/io/CharArrayWriter.java b/libjava/java/io/CharArrayWriter.java
new file mode 100644
index 0000000..3e1e4a4
--- /dev/null
+++ b/libjava/java/io/CharArrayWriter.java
@@ -0,0 +1,122 @@
+// CharArrayWriter.java - Character array output 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 CharArrayWriter extends Writer
+{
+ public CharArrayWriter ()
+ {
+ this (32);
+ }
+
+ public CharArrayWriter (int size)
+ {
+ super ();
+ buf = new char[size];
+ }
+
+ public void close ()
+ {
+ // JCL says this does nothing. This seems to violate the Writer
+ // contract, in that other methods should still throw and
+ // IOException after a close. Still, we just follow JCL.
+ }
+
+ public void flush ()
+ {
+ }
+
+ public synchronized void reset ()
+ {
+ count = 0;
+ }
+
+ public int size ()
+ {
+ return count;
+ }
+
+ public char[] toCharArray ()
+ {
+ char[] nc = new char[count];
+ System.arraycopy(buf, 0, nc, 0, count);
+ return nc;
+ }
+
+ public String toString ()
+ {
+ return new String (buf, 0, count);
+ }
+
+ public void write (int oneChar)
+ {
+ synchronized (lock)
+ {
+ resize (1);
+ buf[count++] = (char) oneChar;
+ }
+ }
+
+ public void write (char[] buffer, int offset, int len)
+ {
+ synchronized (lock)
+ {
+ if (len >= 0)
+ resize (len);
+ System.arraycopy(buffer, offset, buf, count, len);
+ count += len;
+ }
+ }
+
+ public void write (String str, int offset, int len)
+ {
+ synchronized (lock)
+ {
+ if (len >= 0)
+ resize (len);
+ str.getChars(offset, offset + len, buf, count);
+ count += len;
+ }
+ }
+
+ public void writeTo (Writer out) throws IOException
+ {
+ out.write(buf, 0, count);
+ }
+
+ private final void resize (int len)
+ {
+ if (count + len >= buf.length)
+ {
+ int newlen = buf.length * 2;
+ if (count + len > newlen)
+ newlen = count + len;
+ char[] newbuf = new char[newlen];
+ System.arraycopy(buf, 0, newbuf, 0, count);
+ buf = newbuf;
+ }
+ }
+
+ // The character buffer.
+ protected char[] buf;
+ // Number of valid characters in buffer.
+ protected int count;
+}
diff --git a/libjava/java/io/CharConversionException.java b/libjava/java/io/CharConversionException.java
new file mode 100644
index 0000000..039578e
--- /dev/null
+++ b/libjava/java/io/CharConversionException.java
@@ -0,0 +1,34 @@
+// CharConversionException.java - Problem converting char to byte encoding.
+
+/* 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 CharConversionException extends IOException
+{
+ public CharConversionException ()
+ {
+ super ();
+ }
+
+ public CharConversionException (String s)
+ {
+ super (s);
+ }
+}
diff --git a/libjava/java/io/DataInput.java b/libjava/java/io/DataInput.java
new file mode 100644
index 0000000..2c6f988
--- /dev/null
+++ b/libjava/java/io/DataInput.java
@@ -0,0 +1,41 @@
+/* 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 Warren Levy <warrenl@cygnus.com>
+ * @date October 2, 1998.
+ */
+
+/* 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.
+ */
+
+public interface DataInput
+{
+ public boolean readBoolean() throws IOException;
+ public byte readByte() throws IOException;
+ public char readChar() throws IOException;
+ public double readDouble() throws IOException;
+ public float readFloat() throws IOException;
+ public void readFully(byte[] b)
+ throws IOException, NullPointerException;
+ public void readFully(byte[] b, int off, int len)
+ throws IOException, NullPointerException, IndexOutOfBoundsException;
+ public int readInt() throws IOException;
+ public String readLine() throws IOException;
+ public long readLong() throws IOException;
+ public short readShort() throws IOException;
+ public int readUnsignedByte() throws IOException;
+ public int readUnsignedShort() throws IOException;
+ public String readUTF() throws IOException;
+ public int skipBytes(int n) throws IOException;
+}
diff --git a/libjava/java/io/DataInputStream.java b/libjava/java/io/DataInputStream.java
new file mode 100644
index 0000000..7c90008
--- /dev/null
+++ b/libjava/java/io/DataInputStream.java
@@ -0,0 +1,249 @@
+/* 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 Warren Levy <warrenl@cygnus.com>
+ * @date October 20, 1998.
+ */
+
+/* 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.
+ */
+
+public class DataInputStream extends FilterInputStream implements DataInput
+{
+ public DataInputStream(InputStream in)
+ {
+ super(in);
+ }
+
+ public final int read(byte[] b) throws IOException
+ {
+ return super.read(b, 0, b.length);
+ }
+
+ public final int read(byte[] b, int off, int len) throws IOException
+ {
+ if (off < 0 || len < 0 || off + len > b.length)
+ throw new ArrayIndexOutOfBoundsException();
+
+ return super.read(b, off, len);
+ }
+
+ public final boolean readBoolean() throws IOException
+ {
+ return (readByte() != 0);
+ }
+
+ public final byte readByte() throws IOException
+ {
+ int i = read();
+ if (i < 0)
+ throw new EOFException();
+
+ return (byte) i;
+ }
+
+ public final char readChar() throws IOException
+ {
+ return (char) ((readByte() << 8) | readUnsignedByte());
+ }
+
+ public final double readDouble() throws IOException
+ {
+ return Double.longBitsToDouble(readLong());
+ }
+
+ public final float readFloat() throws IOException
+ {
+ return Float.intBitsToFloat(readInt());
+ }
+
+ public final void readFully(byte[] b) throws IOException
+ {
+ readFully(b, 0, b.length);
+ }
+
+ public final void readFully(byte[] b, int off, int len) throws IOException
+ {
+ if (off < 0 || len < 0 || off + len > b.length)
+ throw new ArrayIndexOutOfBoundsException();
+
+ while (len > 0)
+ {
+ // super.read will block until some data is available.
+ int numread = super.read(b, off, len);
+ if (numread < 0)
+ throw new EOFException();
+ len -= numread;
+ off += numread;
+ }
+ }
+
+ public final int readInt() throws IOException
+ {
+ int retval = 0;
+ for (int i = 0; i < 4; i++)
+ retval |= readUnsignedByte() << (24 - i * 8);
+
+ return retval;
+ }
+
+ // Deprecated as of JDK 1.1
+ public final String readLine() throws IOException
+ {
+ StringBuffer strb = new StringBuffer();
+
+ while (true)
+ {
+ char ch = (char) read();
+ if (ch < 0 || (ch &= 0xFF) == '\n')
+ break;
+ if (ch == '\r')
+ {
+ // FIXME: The following code tries to adjust the stream back one
+ // character if the next char read is '\n'. As a last resort,
+ // it tries to mark the position before reading but the bottom
+ // line is that it is possible that this method will not properly
+ // deal with a '\r' '\n' combination thus not fulfilling the
+ // DataInput contract for readLine. It's not a particularly
+ // safe approach threadwise since it is unsynchronized and
+ // since it might mark an input stream behind the users back.
+ // Along the same vein it could try the same thing for
+ // ByteArrayInputStream and PushbackInputStream, but that is
+ // probably overkill since this is deprecated & BufferedInputStream
+ // is the most likely type of input stream.
+ //
+ // The alternative is to somehow push back the next byte if it
+ // isn't a '\n' or to have the reading methods of this class
+ // keep track of whether the last byte read was '\r' by readLine
+ // and then skip the very next byte if it is '\n'. Either way,
+ // this would increase the complexity of the non-deprecated methods
+ // and since it is undesirable to make non-deprecated methods
+ // less efficient, the following seems like the most reasonable
+ // approach.
+ if (in instanceof BufferedInputStream && (read() & 0xFF) != '\n')
+ {
+ BufferedInputStream bin = (BufferedInputStream) in;
+ if (bin.pos > 0)
+ bin.pos--;
+ }
+ else if (markSupported())
+ {
+ mark(1);
+ if ((read() & 0xFF) != '\n')
+ reset();
+ }
+ break;
+ }
+ strb.append(ch);
+ }
+
+ return strb.length() > 0 ? strb.toString() : null;
+ }
+
+ public final long readLong() throws IOException
+ {
+ long retval = 0L;
+ for (int i = 0; i < 8; i++)
+ retval |= (long) readUnsignedByte() << (56 - i * 8);
+
+ return retval;
+ }
+
+ public final short readShort() throws IOException
+ {
+ return (short) ((readByte() << 8) | readUnsignedByte());
+ }
+
+ public final int readUnsignedByte() throws IOException
+ {
+ int i = read();
+ if (i < 0)
+ throw new EOFException();
+
+ return (i & 0xFF);
+ }
+
+ public final int readUnsignedShort() throws IOException
+ {
+ return (readUnsignedByte() << 8) | readUnsignedByte();
+ }
+
+ public final String readUTF() throws IOException
+ {
+ return readUTF(this);
+ }
+
+ public final static String readUTF(DataInput in) throws IOException
+ {
+ final int UTFlen = in.readUnsignedShort();
+ byte[] buf = new byte[UTFlen];
+ StringBuffer strbuf = new StringBuffer();
+
+ // This blocks until the entire string is available rather than
+ // doing partial processing on the bytes that are available and then
+ // blocking. An advantage of the latter is that Exceptions
+ // could be thrown earlier. The former is a bit cleaner.
+ in.readFully(buf, 0, UTFlen);
+ for (int i = 0; i < UTFlen; )
+ {
+ if ((buf[i] & 0x80) == 0) // bit pattern 0xxxxxxx
+ strbuf.append((char) (buf[i++] & 0xFF));
+ else if ((buf[i] & 0xE0) == 0xC0) // bit pattern 110xxxxx
+ {
+ if (i + 1 >= UTFlen || (buf[i+1] & 0xC0) != 0x80)
+ throw new UTFDataFormatException();
+
+ strbuf.append((char) (((buf[i++] & 0x1F) << 6) |
+ (buf[i++] & 0x3F)));
+ }
+ else if ((buf[i] & 0xF0) == 0xE0) // bit pattern 1110xxxx
+ {
+ if (i + 2 >= UTFlen ||
+ (buf[i+1] & 0xC0) != 0x80 || (buf[i+2] & 0xC0) != 0x80)
+ throw new UTFDataFormatException();
+
+ strbuf.append((char) (((buf[i++] & 0x0F) << 12) |
+ ((buf[i++] & 0x3F) << 6) |
+ (buf[i++] & 0x3F)));
+ }
+ else // must be ((buf[i] & 0xF0) == 0xF0 || (buf[i] & 0xC0) == 0x80)
+ throw new UTFDataFormatException(); // bit patterns 1111xxxx or
+ // 10xxxxxx
+ }
+
+ return strbuf.toString();
+ }
+
+ public final int skipBytes(int n) throws IOException
+ {
+ // The contract in the Java Lang. Spec. says that this never
+ // throws an EOFException and infers that it doesn't block (since
+ // it may skip less than the requested number of bytes).
+ // BUT, the JCL book specifically says that this method blocks
+ // and can throw an EOFException. Finally, the Java 1.2 online
+ // doc simply refers to the general contract. As such, we will
+ // stick to the contract and assume for now that the JCL book
+ // is incorrect.
+
+ // Since we're only skipping at most an int number of bytes, the cast
+ // of return value to an int is fine.
+ if (n > 0)
+ {
+ n = Math.min(n, available());
+ return (int) super.skip((long) n);
+ }
+
+ return 0;
+ }
+}
diff --git a/libjava/java/io/DataOutput.java b/libjava/java/io/DataOutput.java
new file mode 100644
index 0000000..c3fd366
--- /dev/null
+++ b/libjava/java/io/DataOutput.java
@@ -0,0 +1,44 @@
+// DataOutput.java - Interface for data output conversions.
+
+/* 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 24, 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 version 1.1.
+ */
+
+public interface DataOutput
+{
+ public abstract void write (int b) throws IOException;
+ public abstract void write (byte[] b)
+ throws IOException, NullPointerException;
+ public abstract void write (byte[] b, int off, int len)
+ throws IOException, NullPointerException, IndexOutOfBoundsException;
+ public abstract void writeBoolean (boolean v) throws IOException;
+ public abstract void writeByte (int v) throws IOException;
+ public abstract void writeShort (int v) throws IOException;
+ public abstract void writeChar (int v) throws IOException;
+ public abstract void writeInt (int v) throws IOException;
+ public abstract void writeLong (long v) throws IOException;
+ public abstract void writeFloat (float v) throws IOException;
+ public abstract void writeDouble (double v) throws IOException;
+ public abstract void writeBytes (String s)
+ throws IOException, NullPointerException;
+ public abstract void writeChars (String s)
+ throws IOException, NullPointerException;
+ public abstract void writeUTF (String s)
+ throws IOException, NullPointerException;
+}
diff --git a/libjava/java/io/DataOutputStream.java b/libjava/java/io/DataOutputStream.java
new file mode 100644
index 0000000..2ef4cf0
--- /dev/null
+++ b/libjava/java/io/DataOutputStream.java
@@ -0,0 +1,165 @@
+// DataOutputStream.java - Output filter that implements DataOutput
+
+/* 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 24, 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 version 1.1.
+ */
+
+public class DataOutputStream extends FilterOutputStream implements DataOutput
+{
+ public DataOutputStream (OutputStream out)
+ {
+ super (out);
+ written = 0;
+ }
+
+ public void flush () throws IOException
+ {
+ out.flush();
+ }
+
+ public final int size ()
+ {
+ return written;
+ }
+
+ public synchronized void write (int b) throws IOException
+ {
+ out.write(b);
+ ++written;
+ }
+
+ public synchronized void write (byte[] b, int off, int len)
+ throws IOException, NullPointerException, IndexOutOfBoundsException
+ {
+ out.write(b, off, len);
+ written += len - off;
+ }
+
+ public final void writeBoolean (boolean v) throws IOException
+ {
+ write (v ? 1 : 0);
+ }
+
+ public final void writeByte (int v) throws IOException
+ {
+ write (v & 0xff);
+ }
+
+ public final void writeShort (int v) throws IOException
+ {
+ write ((byte) (0xff & (v >> 8)));
+ write ((byte) (0xff & v));
+ }
+
+ public final void writeChar (int v) throws IOException
+ {
+ write ((byte) (0xff & (v >> 8)));
+ write ((byte) (0xff & v));
+ }
+
+ public final void writeInt (int v) throws IOException
+ {
+ write ((byte) (0xff & (v >> 24)));
+ write ((byte) (0xff & (v >> 16)));
+ write ((byte) (0xff & (v >> 8)));
+ write ((byte) (0xff & v));
+ }
+
+ public final void writeLong (long v) throws IOException
+ {
+ write ((byte) (0xff & (v >> 56)));
+ write ((byte) (0xff & (v >> 48)));
+ write ((byte) (0xff & (v >> 40)));
+ write ((byte) (0xff & (v >> 32)));
+ write ((byte) (0xff & (v >> 24)));
+ write ((byte) (0xff & (v >> 16)));
+ write ((byte) (0xff & (v >> 8)));
+ write ((byte) (0xff & v));
+ }
+
+ public final void writeFloat (float v) throws IOException
+ {
+ writeInt (Float.floatToIntBits(v));
+ }
+
+ public final void writeDouble (double v) throws IOException
+ {
+ writeLong (Double.doubleToLongBits(v));
+ }
+
+ public final void writeBytes (String s) throws IOException
+ {
+ int len = s.length();
+ for (int i = 0; i < len; ++i)
+ writeByte (s.charAt(i));
+ }
+
+ public final void writeChars (String s) throws IOException
+ {
+ int len = s.length();
+ for (int i = 0; i < len; ++i)
+ writeChar (s.charAt(i));
+ }
+
+ public final void writeUTF (String s) throws IOException
+ {
+ int len = s.length();
+ int sum = 0;
+
+ for (int i = 0; i < len && sum <= 65535; ++i)
+ {
+ char c = s.charAt(i);
+ if (c >= '\u0001' && c <= '\u007f')
+ sum += 1;
+ else if (c == '\u0000' || (c >= '\u0080' && c <= '\u07ff'))
+ sum += 2;
+ else
+ sum += 3;
+ }
+
+ if (sum > 65535)
+ throw new UTFDataFormatException ();
+
+ writeShort (sum);
+
+ for (int i = 0; i < len; ++i)
+ {
+ char c = s.charAt(i);
+ if (c >= '\u0001' && c <= '\u007f')
+ write (c);
+ else if (c == '\u0000' || (c >= '\u0080' && c <= '\u07ff'))
+ {
+ write (0xc0 | (0x1f & (c >> 6)));
+ write (0x80 | (0x3f & c));
+ }
+ else
+ {
+ // JSL says the first byte should be or'd with 0xc0, but
+ // that is a typo. Unicode says 0xe0, and that is what is
+ // consistent with DataInputStream.
+ write (0xe0 | (0x0f & (c >> 12)));
+ write (0x80 | (0x3f & (c >> 6)));
+ write (0x80 | (0x3f & c));
+ }
+ }
+ }
+
+ // Number of bytes written so far.
+ protected int written;
+}
diff --git a/libjava/java/io/EOFException.java b/libjava/java/io/EOFException.java
new file mode 100644
index 0000000..d890a0f
--- /dev/null
+++ b/libjava/java/io/EOFException.java
@@ -0,0 +1,34 @@
+// EOFException.java - End of file exception
+
+/* 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 24, 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 EOFException extends IOException
+{
+ public EOFException ()
+ {
+ super ();
+ }
+
+ public EOFException (String s)
+ {
+ super (s);
+ }
+}
diff --git a/libjava/java/io/File.java b/libjava/java/io/File.java
new file mode 100644
index 0000000..30d9887
--- /dev/null
+++ b/libjava/java/io/File.java
@@ -0,0 +1,288 @@
+// File.java - File name
+
+/* 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 24, 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 version 1.1; 1.2 functionality missing.
+ * A known bug: most calls to the security manager can generate
+ * IOException since we use the canonical path.
+ */
+
+public class File implements Serializable
+{
+ public boolean canRead ()
+ {
+ return access (checkRead (), READ);
+ }
+
+ public boolean canWrite ()
+ {
+ SecurityManager s = System.getSecurityManager();
+ String p = safeCanonicalPath ();
+ // FIXME: it isn't entirely clear what to do if we can't find the
+ // canonical path.
+ if (p == null)
+ return false;
+ if (s != null)
+ s.checkWrite(p);
+ return access (p, WRITE);
+ }
+
+ private final native boolean performDelete (String canon);
+ public boolean delete ()
+ {
+ SecurityManager s = System.getSecurityManager();
+ String p = safeCanonicalPath ();
+ // FIXME: what is right?
+ if (p == null)
+ return false;
+ if (s != null)
+ s.checkDelete(p);
+ return performDelete (p);
+ }
+
+ public boolean equals (Object obj)
+ {
+ if (! (obj instanceof File))
+ return false;
+ File other = (File) obj;
+ return path.compareTo(other.path) == 0;
+ }
+
+ public boolean exists ()
+ {
+ return access (checkRead (), EXISTS);
+ }
+
+ public File (String p)
+ {
+ if (p == null)
+ throw new NullPointerException ();
+ path = p;
+ }
+
+ public File (String dirPath, String name)
+ {
+ if (name == null)
+ throw new NullPointerException ();
+ if (dirPath != null)
+ {
+ // Try to be smart about the number of separator characters.
+ if (dirPath.charAt(dirPath.length() - 1) == separatorChar)
+ path = dirPath + name;
+ else
+ path = dirPath + separatorChar + name;
+ }
+ else
+ path = name;
+ }
+
+ public File (File dir, String name)
+ {
+ this (dir == null ? null : dir.path, name);
+ }
+
+ public String getAbsolutePath ()
+ {
+ if (isAbsolute ())
+ return path;
+ return System.getProperty("user.dir") + separatorChar + path;
+ }
+
+ public native String getCanonicalPath () throws IOException;
+
+ public String getName ()
+ {
+ int last = path.lastIndexOf(separatorChar);
+ if (last == -1)
+ last = 0;
+ return path.substring(last);
+ }
+
+ public String getParent ()
+ {
+ int last = path.lastIndexOf(separatorChar);
+ if (last == -1)
+ return null;
+ return path.substring(0, last);
+ }
+
+ public String getPath ()
+ {
+ return path;
+ }
+
+ public int hashCode ()
+ {
+ // FIXME: test.
+ return path.hashCode();
+ }
+
+ public native boolean isAbsolute ();
+
+ public boolean isDirectory ()
+ {
+ return stat (checkRead (), DIRECTORY);
+ }
+
+ public boolean isFile ()
+ {
+ return stat (checkRead (), ISFILE);
+ }
+
+ public long lastModified ()
+ {
+ return attr (checkRead (), MODIFIED);
+ }
+
+ public long length ()
+ {
+ return attr (checkRead (), LENGTH);
+ }
+
+ private final native String[] performList (String canon,
+ FilenameFilter filter);
+ public String[] list (FilenameFilter filter)
+ {
+ return performList (checkRead (), filter);
+ }
+
+ public String[] list ()
+ {
+ return performList (checkRead (), null);
+ }
+
+ public String toString ()
+ {
+ return path;
+ }
+
+ private final native boolean performMkdir ();
+ public boolean mkdir ()
+ {
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ {
+ // NOTE: in theory we should use the canonical path. In
+ // practice, we can't compute the canonical path until we've
+ // made this completely. Lame.
+ s.checkWrite(path);
+ }
+ return performMkdir ();
+ }
+
+ private static boolean mkdirs (File x)
+ {
+ if (x.isDirectory())
+ return true;
+ String p = x.getPath();
+ x.setPath(x.getParent());
+ if (! mkdirs (x))
+ return false;
+ x.setPath(p);
+ return x.mkdir();
+ }
+
+ public boolean mkdirs ()
+ {
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ {
+ // NOTE: in theory we should use the canonical path. In
+ // practice, we can't compute the canonical path until we've
+ // made this completely. Lame.
+ s.checkWrite(path);
+ }
+
+ if (isDirectory ())
+ return false;
+ return mkdirs (new File (path));
+ }
+
+ private final native boolean performRenameTo (File dest);
+ public boolean renameTo (File dest)
+ {
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ {
+ // FIXME: JCL doesn't specify which path to check. We check the
+ // source since we can canonicalize it.
+ s.checkWrite(safeCanonicalPath());
+ }
+ return performRenameTo (dest);
+ }
+
+ public static final String pathSeparator
+ = System.getProperty("path.separator");
+ public static final char pathSeparatorChar = pathSeparator.charAt(0);
+ public static final String separator = System.getProperty("file.separator");
+ public static final char separatorChar = separator.charAt(0);
+
+
+ // The path.
+ private String path;
+
+ // mkdirs() uses this to avoid repeated allocations.
+ private final void setPath (String n)
+ {
+ path = n;
+ }
+
+
+ private final String checkRead ()
+ {
+ SecurityManager s = System.getSecurityManager();
+ String p = safeCanonicalPath ();
+ if (p == null)
+ return null;
+ if (s != null)
+ s.checkRead(p);
+ return p;
+ }
+
+ // Return canonical path, or null.
+ private final String safeCanonicalPath ()
+ {
+ String p = null;
+ try
+ {
+ p = getCanonicalPath ();
+ }
+ catch (IOException x)
+ {
+ // Nothing.
+ }
+ return p;
+ }
+
+ // QUERY arguments to access function.
+ private final static int READ = 0;
+ private final static int WRITE = 1;
+ private final static int EXISTS = 2;
+
+ // QUERY arguments to stat function.
+ private final static int DIRECTORY = 0;
+ private final static int ISFILE = 1;
+
+ // QUERY arguments to attr function.
+ private final static int MODIFIED = 0;
+ private final static int LENGTH = 1;
+
+ private final native long attr (String p, int query);
+ private final native boolean access (String p, int query);
+ private final native boolean stat (String p, int query);
+}
diff --git a/libjava/java/io/FileDescriptor.java b/libjava/java/io/FileDescriptor.java
new file mode 100644
index 0000000..0782b0c
--- /dev/null
+++ b/libjava/java/io/FileDescriptor.java
@@ -0,0 +1,87 @@
+// FileDescriptor.java - Open file or device
+
+/* 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 24, 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
+ */
+
+// For now we assume a POSIXy file system. This can be changed later
+// if need be.
+public final class FileDescriptor
+{
+ public static final FileDescriptor in = new FileDescriptor (0);
+ public static final FileDescriptor out = new FileDescriptor (1);
+ public static final FileDescriptor err = new FileDescriptor (2);
+
+ public native void sync () throws SyncFailedException;
+ public native boolean valid ();
+
+
+ // These are mode values for open().
+ static final int READ = 1;
+ static final int WRITE = 2;
+ static final int APPEND = 4;
+
+ // These are WHENCE values for seek.
+ static final int SET = 0;
+ static final int CUR = 1;
+
+ // Open a file. MODE is a combination of the above mode flags.
+ FileDescriptor (String path, int mode) throws IOException
+ {
+ fd = open (path, mode);
+ }
+
+ public FileDescriptor ()
+ {
+ fd = -1;
+ }
+
+ native int open (String path, int mode) throws IOException;
+ native void write (int b) throws IOException;
+ native void write (byte[] b, int offset, int len)
+ throws IOException, NullPointerException, IndexOutOfBoundsException;
+ native void close () throws IOException;
+ native int seek (long pos, int whence) throws IOException;
+ native long length () throws IOException;
+ native long getFilePointer () throws IOException;
+ native int read () throws IOException;
+ native int read (byte[] bytes, int offset, int len) throws IOException;
+ native int available () throws IOException;
+
+
+ // When collected, close.
+ protected void finalize () throws IOException
+ {
+ if (valid ())
+ close ();
+ }
+
+ // Attach to an already-opened file. This is not private because we
+ // need access to it from other packages, for instance java.net.
+ // Ordinarily that wouldn't work, either, but in our case we know
+ // the access comes from C++, where "package private" is translated
+ // into "public". Eww.
+ FileDescriptor (int desc)
+ {
+ fd = desc;
+ }
+
+ // System's notion of file descriptor.
+ private int fd;
+}
diff --git a/libjava/java/io/FileInputStream.java b/libjava/java/io/FileInputStream.java
new file mode 100644
index 0000000..4f44dae
--- /dev/null
+++ b/libjava/java/io/FileInputStream.java
@@ -0,0 +1,96 @@
+/* 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 Warren Levy <warrenl@cygnus.com>
+ * @date October 28, 1998.
+ */
+/* 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.
+ */
+
+public class FileInputStream extends InputStream
+{
+ /* Contains the file descriptor for referencing the actual file. */
+ private FileDescriptor fd;
+
+ public FileInputStream(String name) throws FileNotFoundException, IOException
+ {
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ s.checkRead(name);
+ fd = new FileDescriptor(name, FileDescriptor.READ);
+ }
+
+ public FileInputStream(File file) throws FileNotFoundException, IOException
+ {
+ this(file.getPath());
+ }
+
+ public FileInputStream(FileDescriptor fdObj)
+ {
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ s.checkRead(fdObj);
+ fd = fdObj;
+ }
+
+ public int available() throws IOException
+ {
+ return fd.available();
+ }
+
+ public void close() throws IOException
+ {
+ if (fd == null)
+ return;
+
+ fd.close();
+ fd = null;
+ }
+
+ protected void finalize() throws IOException
+ {
+ if (fd != null)
+ fd.finalize();
+ }
+
+ public final FileDescriptor getFD() throws IOException
+ {
+ if (!fd.valid())
+ throw new IOException();
+ return fd;
+ }
+
+ public int read() throws IOException
+ {
+ return fd.read();
+ }
+
+ public int read(byte[] b) throws IOException
+ {
+ return fd.read(b, 0, b.length);
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException
+ {
+ if (off < 0 || len < 0 || off + len > b.length)
+ throw new ArrayIndexOutOfBoundsException();
+
+ return fd.read(b, off, len);
+ }
+
+ public long skip(long n) throws IOException
+ {
+ return fd.seek(n, FileDescriptor.CUR);
+ }
+}
diff --git a/libjava/java/io/FileNotFoundException.java b/libjava/java/io/FileNotFoundException.java
new file mode 100644
index 0000000..07ff9bf
--- /dev/null
+++ b/libjava/java/io/FileNotFoundException.java
@@ -0,0 +1,34 @@
+// FileNotFoundException.java
+
+/* 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 24, 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 FileNotFoundException extends IOException
+{
+ public FileNotFoundException ()
+ {
+ super ();
+ }
+
+ public FileNotFoundException (String s)
+ {
+ super (s);
+ }
+}
diff --git a/libjava/java/io/FileOutputStream.java b/libjava/java/io/FileOutputStream.java
new file mode 100644
index 0000000..3e6e972
--- /dev/null
+++ b/libjava/java/io/FileOutputStream.java
@@ -0,0 +1,93 @@
+// FileOutputStream.java - Write bytes to a file.
+
+/* 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 24, 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 version 1.1.
+ */
+
+public class FileOutputStream extends OutputStream
+{
+ public FileOutputStream (String path, boolean append)
+ throws SecurityException, IOException
+ {
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ s.checkWrite(path);
+ fd = new FileDescriptor (path, (append
+ ? FileDescriptor.APPEND
+ : FileDescriptor.WRITE));
+ }
+
+ public FileOutputStream (String path) throws SecurityException, IOException
+ {
+ this (path, false);
+ }
+
+ public FileOutputStream (File file) throws SecurityException, IOException
+ {
+ this (file.getPath(), false);
+ }
+
+ public FileOutputStream (FileDescriptor fdObj) throws SecurityException
+ {
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ s.checkWrite(fdObj);
+ fd = fdObj;
+ }
+
+ protected void finalize () throws IOException
+ {
+ // We don't actually need this, but we include it because it is
+ // mentioned in the JCL.
+ }
+
+ public final FileDescriptor getFD () throws IOException
+ {
+ if (! fd.valid())
+ throw new IOException ();
+ return fd;
+ }
+
+ public void write (int b) throws IOException
+ {
+ fd.write (b);
+ }
+
+ public void write (byte[] b) throws IOException, NullPointerException
+ {
+ fd.write (b, 0, b.length);
+ }
+
+ public void write (byte[] b, int off, int len)
+ throws IOException, NullPointerException, IndexOutOfBoundsException
+ {
+ if (off < 0 || len < 0 || off + len > b.length)
+ throw new ArrayIndexOutOfBoundsException ();
+ fd.write (b, off, len);
+ }
+
+ public void close () throws IOException
+ {
+ if (fd.valid())
+ fd.close();
+ }
+
+ // Instance variables.
+ private FileDescriptor fd;
+}
diff --git a/libjava/java/io/FileReader.java b/libjava/java/io/FileReader.java
new file mode 100644
index 0000000..259526c
--- /dev/null
+++ b/libjava/java/io/FileReader.java
@@ -0,0 +1,35 @@
+/* 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 Per Bothner <bothner@cygnus.com>
+ * @date April 22, 1998.
+ */
+/* Written using "Java Class Libraries", 2nd edition.
+ * Status: Believed complete and correct.
+ */
+
+public class FileReader extends InputStreamReader
+{
+ public FileReader(String filename) throws IOException
+ {
+ super(new FileInputStream(filename));
+ }
+
+ public FileReader(File file) throws IOException
+ {
+ super(new FileInputStream(file));
+ }
+
+ public FileReader(FileDescriptor fd)
+ {
+ super(new FileInputStream(fd));
+ }
+}
diff --git a/libjava/java/io/FileWriter.java b/libjava/java/io/FileWriter.java
new file mode 100644
index 0000000..8c3f9a9
--- /dev/null
+++ b/libjava/java/io/FileWriter.java
@@ -0,0 +1,44 @@
+// FileWriter.java - Character output to a file.
+
+/* 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 version 1.1.
+ */
+
+public class FileWriter extends OutputStreamWriter
+{
+ public FileWriter (String fileName) throws IOException
+ {
+ super (new FileOutputStream (fileName));
+ }
+
+ public FileWriter (String fileName, boolean append) throws IOException
+ {
+ super (new FileOutputStream (fileName, append));
+ }
+
+ public FileWriter (File file) throws IOException
+ {
+ super (new FileOutputStream (file));
+ }
+
+ public FileWriter (FileDescriptor fd)
+ {
+ super (new FileOutputStream (fd));
+ }
+}
diff --git a/libjava/java/io/FilenameFilter.java b/libjava/java/io/FilenameFilter.java
new file mode 100644
index 0000000..682efed
--- /dev/null
+++ b/libjava/java/io/FilenameFilter.java
@@ -0,0 +1,26 @@
+// FilenameFilter.java - Compute subset of list of file names
+
+/* 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 24, 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 interface FilenameFilter
+{
+ public abstract boolean accept (File dir, String name);
+}
diff --git a/libjava/java/io/FilterInputStream.java b/libjava/java/io/FilterInputStream.java
new file mode 100644
index 0000000..918948b
--- /dev/null
+++ b/libjava/java/io/FilterInputStream.java
@@ -0,0 +1,75 @@
+/* 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 Warren Levy <warrenl@cygnus.com>
+ * @date October 8, 1998.
+ */
+/* 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.
+ */
+
+public class FilterInputStream extends InputStream
+{
+ /* The input stream to be filtered. */
+ protected InputStream in;
+
+ protected FilterInputStream(InputStream in)
+ {
+ this.in = in;
+ }
+
+ public int available() throws IOException
+ {
+ return in.available();
+ }
+
+ public void close() throws IOException
+ {
+ in.close();
+ }
+
+ public synchronized void mark(int readlimit)
+ {
+ in.mark(readlimit);
+ }
+
+ public boolean markSupported()
+ {
+ return in.markSupported();
+ }
+
+ public int read() throws IOException
+ {
+ return in.read();
+ }
+
+ public int read(byte[] b) throws IOException
+ {
+ return read(b, 0, b.length);
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException
+ {
+ return in.read(b, off, len);
+ }
+
+ public synchronized void reset() throws IOException
+ {
+ in.reset();
+ }
+
+ public long skip(long n) throws IOException
+ {
+ return in.skip(n);
+ }
+}
diff --git a/libjava/java/io/FilterOutputStream.java b/libjava/java/io/FilterOutputStream.java
new file mode 100644
index 0000000..45d6fd0
--- /dev/null
+++ b/libjava/java/io/FilterOutputStream.java
@@ -0,0 +1,61 @@
+// FilterOutputStream.java - A filtered 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 24, 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 version 1.1.
+ */
+
+public class FilterOutputStream extends OutputStream
+{
+ public void close () throws IOException
+ {
+ flush ();
+ out.close();
+ }
+
+ public FilterOutputStream (OutputStream ox)
+ {
+ out = ox;
+ }
+
+ public void flush () throws IOException
+ {
+ out.flush();
+ }
+
+ public void write (int b) throws IOException
+ {
+ out.write(b);
+ }
+
+ public void write (byte[] b) throws IOException, NullPointerException
+ {
+ // Don't do checking here, per Java Lang Spec.
+ out.write (b);
+ }
+
+ public void write (byte[] b, int off, int len)
+ throws IOException, NullPointerException, IndexOutOfBoundsException
+ {
+ // Don't do checking here, per Java Lang Spec.
+ out.write(b, off, len);
+ }
+
+ // The output stream.
+ protected OutputStream out;
+}
diff --git a/libjava/java/io/FilterReader.java b/libjava/java/io/FilterReader.java
new file mode 100644
index 0000000..1fe2014
--- /dev/null
+++ b/libjava/java/io/FilterReader.java
@@ -0,0 +1,72 @@
+/* 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 Warren Levy <warrenl@cygnus.com>
+ * @date October 15, 1998.
+ */
+/* 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.
+ */
+
+public abstract class FilterReader extends Reader
+{
+ /* The input stream to be filtered. */
+ protected Reader in;
+
+ protected FilterReader(Reader in)
+ {
+ super(in.lock);
+ this.in = in;
+ }
+
+ public void close() throws IOException
+ {
+ in.close();
+ in = null;
+ }
+
+ public synchronized void mark(int readlimit) throws IOException
+ {
+ in.mark(readlimit);
+ }
+
+ public boolean markSupported()
+ {
+ return in.markSupported();
+ }
+
+ public int read() throws IOException
+ {
+ return in.read();
+ }
+
+ public int read(char[] b, int off, int len) throws IOException
+ {
+ return in.read(b, off, len);
+ }
+
+ public boolean ready() throws IOException
+ {
+ return in.ready();
+ }
+
+ public synchronized void reset() throws IOException
+ {
+ in.reset();
+ }
+
+ public long skip(long n) throws IOException
+ {
+ return in.skip(n);
+ }
+}
diff --git a/libjava/java/io/FilterWriter.java b/libjava/java/io/FilterWriter.java
new file mode 100644
index 0000000..385cc7e
--- /dev/null
+++ b/libjava/java/io/FilterWriter.java
@@ -0,0 +1,59 @@
+// FilterWriter.java - Filtered character output 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 version 1.1.
+ */
+
+public abstract class FilterWriter extends Writer
+{
+ public void close () throws IOException
+ {
+ out.close();
+ }
+
+ protected FilterWriter (Writer ox)
+ {
+ // FIXME: should we really share locks like this?
+ super (ox);
+ out = ox;
+ }
+
+ public void flush () throws IOException
+ {
+ out.flush();
+ }
+
+ public void write (int oneChar) throws IOException
+ {
+ out.write(oneChar);
+ }
+
+ public void write (char[] buffer, int offset, int count) throws IOException
+ {
+ out.write(buffer, offset, count);
+ }
+
+ public void write (String str, int offset, int count) throws IOException
+ {
+ out.write(str, offset, count);
+ }
+
+ // Where our writes should go.
+ protected Writer out;
+}
diff --git a/libjava/java/io/IOException.java b/libjava/java/io/IOException.java
new file mode 100644
index 0000000..15a14ff
--- /dev/null
+++ b/libjava/java/io/IOException.java
@@ -0,0 +1,34 @@
+// IOException.java - Base class for I/O Exceptions
+
+/* 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 24, 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 IOException extends Exception
+{
+ public IOException ()
+ {
+ super ();
+ }
+
+ public IOException (String s)
+ {
+ super (s);
+ }
+}
diff --git a/libjava/java/io/InputStream.java b/libjava/java/io/InputStream.java
new file mode 100644
index 0000000..cc86efd
--- /dev/null
+++ b/libjava/java/io/InputStream.java
@@ -0,0 +1,104 @@
+/* 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 Warren Levy <warrenl@cygnus.com>
+ * @date October 2, 1998.
+ */
+/* 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.
+ */
+
+public abstract class InputStream
+{
+ public InputStream()
+ {
+ }
+
+ public int available() throws IOException
+ {
+ return 0;
+ }
+
+ public void close() throws IOException
+ {
+ // Do nothing
+ }
+
+ public void mark(int readlimit)
+ {
+ // Do nothing
+ }
+
+ public boolean markSupported()
+ {
+ return false;
+ }
+
+ public abstract int read() throws IOException;
+
+ public int read(byte[] b) throws IOException
+ {
+ return read(b, 0, b.length);
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException
+ {
+ if (off < 0 || len < 0 || off + len > b.length)
+ throw new IndexOutOfBoundsException();
+ if (b.length == 0)
+ return 0;
+
+ int i, ch;
+
+ for (i = 0; i < len; ++i)
+ try
+ {
+ if ((ch = read()) < 0)
+ return i == 0 ? -1 : i; // EOF
+ b[off + i] = (byte) ch;
+ }
+ catch (IOException ex)
+ {
+ // Only reading the first byte should cause an IOException.
+ if (i == 0)
+ throw ex;
+ return i;
+ }
+
+ return i;
+ }
+
+ public void reset() throws IOException
+ {
+ throw new IOException("mark/reset not supported");
+ }
+
+ public long skip(long n) throws IOException
+ {
+ // Throw away n bytes by reading them into a temp byte[].
+ // Limit the temp array to 2Kb so we don't grab too much memory.
+ final int buflen = n > 2048 ? 2048 : (int) n;
+ byte[] tmpbuf = new byte[buflen];
+ final long origN = n;
+
+ while (n > 0L)
+ {
+ int numread = read(tmpbuf, 0, n > buflen ? buflen : (int) n);
+ if (numread <= 0)
+ break;
+ n -= numread;
+ }
+
+ return origN - n;
+ }
+}
diff --git a/libjava/java/io/InputStreamReader.java b/libjava/java/io/InputStreamReader.java
new file mode 100644
index 0000000..ee44f91
--- /dev/null
+++ b/libjava/java/io/InputStreamReader.java
@@ -0,0 +1,151 @@
+/* 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;
+import gnu.gcj.convert.*;
+
+/**
+ * @author Per Bothner <bothner@cygnus.com>
+ * @date April 22, 1998.
+ */
+/* Written using "Java Class Libraries", 2nd edition, plus online
+ * API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct, but only supports 8859_1.
+ */
+
+public class InputStreamReader extends Reader
+{
+ BufferedInputStream in;
+
+ // Buffer of chars read from in and converted but not consumed.
+ char[] work;
+ // Next available character (in work buffer) to read.
+ int wpos;
+ // Last available character (in work buffer) to read.
+ int wcount;
+
+ BytesToUnicode converter;
+
+ public InputStreamReader(InputStream in)
+ {
+ this(in, BytesToUnicode.getDefaultDecoder());
+ }
+
+ public InputStreamReader(InputStream in, String enc)
+ throws UnsupportedEncodingException
+ {
+ this(in, BytesToUnicode.getDecoder(enc));
+ }
+
+ private InputStreamReader(InputStream in, BytesToUnicode decoder)
+ {
+ super(in);
+ this.in = in instanceof BufferedInputStream ? (BufferedInputStream) in
+ : new BufferedInputStream(in, 250);
+ converter = decoder;
+ converter.setInput(this.in.buf, 0, 0);
+ }
+
+ public void close() throws IOException
+ {
+ synchronized (lock)
+ {
+ if (in != null)
+ in.close();
+ in = null;
+ work = null;
+ wpos = wcount = 0;
+ }
+ }
+
+ public String getEncoding() { return converter.getName(); }
+
+ public boolean ready() throws IOException
+ {
+ synchronized (lock)
+ {
+ if (wpos < wcount)
+ return true;
+ if (work == null)
+ {
+ work = new char[100];
+ wpos = 0;
+ wcount = 0;
+ }
+ for (;;)
+ {
+ if (in.available() <= 0)
+ return false;
+ in.mark(1);
+ int b = in.read();
+ if (b < 0)
+ return true;
+ in.reset();
+ converter.setInput(in.buf, in.pos, in.count);
+ wpos = 0;
+ wcount = converter.read(work, 0, work.length);
+ in.skip(converter.inpos - in.pos);
+ if (wcount > 0)
+ return true;
+ }
+ }
+ }
+
+ public int read(char buf[], int offset, int length) throws IOException
+ {
+ synchronized (lock)
+ {
+ int wavail = wcount - wpos;
+ if (wavail > 0)
+ {
+ if (length > wavail)
+ length = wavail;
+ System.arraycopy(work, wpos, buf, offset, length);
+ wpos += length;
+ return length;
+ }
+ else
+ {
+ for (;;)
+ {
+ in.mark(1);
+ int b = in.read();
+ if (b < 0)
+ return -1;
+ in.reset();
+ converter.setInput(in.buf, in.pos, in.count);
+ int count = converter.read (buf, offset, length);
+ in.skip(converter.inpos - in.pos);
+ if (count > 0)
+ return count;
+ }
+ }
+ }
+ }
+
+ public int read() throws IOException
+ {
+ synchronized (lock)
+ {
+ int wavail = wcount - wpos;
+ if (wavail > 0)
+ return work[wpos++];
+ if (work == null)
+ {
+ work = new char[100];
+ wpos = 0;
+ wcount = 0;
+ }
+ int count = read(work, wpos, work.length-wpos);
+ if (count <= 0)
+ return -1;
+ wcount = wpos + count;
+ return work[wpos++];
+ }
+ }
+}
diff --git a/libjava/java/io/InterruptedIOException.java b/libjava/java/io/InterruptedIOException.java
new file mode 100644
index 0000000..11d922b
--- /dev/null
+++ b/libjava/java/io/InterruptedIOException.java
@@ -0,0 +1,36 @@
+// InterruptedIOException.java
+
+/* 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 24, 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 InterruptedIOException extends IOException
+{
+ public InterruptedIOException ()
+ {
+ super ();
+ }
+
+ public InterruptedIOException (String s)
+ {
+ super (s);
+ }
+
+ public int bytesTransferred = 0;
+}
diff --git a/libjava/java/io/LineNumberInputStream.java b/libjava/java/io/LineNumberInputStream.java
new file mode 100644
index 0000000..1b96da9
--- /dev/null
+++ b/libjava/java/io/LineNumberInputStream.java
@@ -0,0 +1,143 @@
+/* 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 Warren Levy <warrenl@cygnus.com>
+ * @date November 11, 1998.
+ * @deprecated
+ */
+/* 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. Deprecated in JDK 1.1.
+ */
+
+public class LineNumberInputStream extends FilterInputStream
+{
+ /* The current line number. */
+ private int lineNumber = 0;
+
+ /* The line number when the stream was marked. */
+ private int markLineNumber = 0;
+
+ /* Flag to indicate a '\r' was just read so that an immediately subsequent
+ * '\n' can be ignored. */
+ private boolean justReadReturnChar = false;
+
+ public LineNumberInputStream(InputStream in)
+ {
+ super(in);
+ }
+
+ public int available() throws IOException
+ {
+ // We can only guarantee half the characters that might be available
+ // without blocking because "\r\n" is treated as a single character.
+ return in.available() / 2;
+ }
+
+ public int getLineNumber()
+ {
+ return lineNumber;
+ }
+
+ public void mark(int readlimit)
+ {
+ in.mark(readlimit);
+ markLineNumber = lineNumber;
+ }
+
+ public int read() throws IOException
+ {
+ // Treat "\r\n" as a single character. A '\r' may have been read by
+ // a previous call to read so we keep an internal flag to avoid having
+ // to read ahead.
+
+ int ch = in.read();
+
+ if (ch == '\n')
+ if (justReadReturnChar)
+ {
+ ch = in.read();
+ justReadReturnChar = false;
+ }
+ else
+ lineNumber++;
+ else if (ch == '\r')
+ {
+ ch = '\n';
+ justReadReturnChar = true;
+ lineNumber++;
+ }
+ else
+ justReadReturnChar = false;
+
+ return ch;
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException
+ {
+ if (off < 0 || len < 0 || off + len > b.length)
+ throw new ArrayIndexOutOfBoundsException();
+
+ // This case always succeeds.
+ if (len == 0)
+ return 0;
+
+ // The simplest, though not necessarily the most time efficient thing
+ // to do is simply call read(void) len times. Since this is a deprecated
+ // class, that should be ok.
+ final int origOff = off;
+ while (len-- > 0)
+ {
+ int ch = read();
+ if (ch < 0)
+ break;
+
+ b[off++] = (byte) ch;
+ }
+
+ // This is safe since we already know that some bytes were
+ // actually requested.
+ return off == origOff ? -1 : off - origOff;
+ }
+
+ public void reset() throws IOException
+ {
+ in.reset();
+ lineNumber = markLineNumber;
+ justReadReturnChar = false;
+ }
+
+ public void setLineNumber(int lineNumber)
+ {
+ this.lineNumber = lineNumber;
+ }
+
+ public long skip(long n) throws IOException
+ {
+ if (n <= 0)
+ return 0L;
+
+ final long origN = n;
+
+ do
+ {
+ int ch = read();
+ if (ch < 0)
+ break;
+ if (ch == '\n' || ch == '\r')
+ lineNumber++;
+ }
+ while (--n > 0);
+
+ return origN - n;
+ }
+}
diff --git a/libjava/java/io/LineNumberReader.java b/libjava/java/io/LineNumberReader.java
new file mode 100644
index 0000000..c709a7a
--- /dev/null
+++ b/libjava/java/io/LineNumberReader.java
@@ -0,0 +1,245 @@
+/* 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 Per Bothner <bothner@cygnus.com>
+ * @date April 22, 1998.
+ */
+/* Written using "Java Class Libraries", 2nd edition, plus online
+ * API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct.
+ *
+ * This implementation has the feature that if '\r' is read, it
+ * does not look for a '\n', but immediately returns '\n'.
+ * On the next read(), if a '\n' is read, it is skipped.
+ * This has the advantage that we do not read (and hang) unnecessarily.
+ *
+ * This implementation is also minimal in the number of fields it uses.
+ */
+
+public class LineNumberReader extends BufferedReader
+{
+ /** The current line number. */
+ int lineNumber;
+
+ public LineNumberReader(Reader in)
+ {
+ super(in, 8192);
+ }
+
+ public LineNumberReader(Reader in, int size)
+ {
+ super(in, size);
+ }
+
+ public int getLineNumber()
+ {
+ return lineNumber;
+ }
+
+ public void setLineNumber(int lineNumber)
+ {
+ this.lineNumber = lineNumber;
+ }
+
+ private static int countLines (char[] buffer, int off, int len)
+ {
+ int count = 0;
+ char prev = '\0';
+ for (int i = 0; i < len; i++)
+ {
+ char ch = buffer[i+off];
+ if ((ch == '\n' && prev != '\r') || ch == '\r')
+ count++;
+ prev = ch;
+ }
+ return count;
+ }
+
+ public void mark(int readLimit) throws IOException
+ {
+ synchronized (lock)
+ {
+ // This is basically the same as BufferedReader.mark.
+ // However, if the previous character was a '\r', we need to
+ // save that 'r', in case the next character is a '\n'.
+ if (pos + readLimit > limit)
+ {
+ int saveCR = (pos > 0 && buffer[pos-1] == '\r') ? 1 : 0;
+ char[] old_buffer = buffer;
+ if (readLimit > limit)
+ buffer = new char[saveCR + readLimit];
+ int copy_start = pos - saveCR;
+ limit -= copy_start;
+ System.arraycopy(old_buffer, copy_start, buffer, 0, limit);
+ pos = saveCR;
+ }
+ markPos = pos;
+ }
+ }
+
+ public void reset() throws IOException
+ {
+ synchronized (lock)
+ {
+ if (markPos < 0)
+ throw new IOException("mark never set or invalidated");
+ if (markPos > 0 && pos > markPos && buffer[markPos-1] == '\r'
+ && buffer[markPos] == '\n')
+ lineNumber--;
+ lineNumber -= countLines(buffer, pos, markPos);
+ pos = markPos;
+ }
+ }
+
+ public int read() throws IOException
+ {
+ synchronized (lock)
+ {
+ skipRedundantLF();
+ if (pos >= limit)
+ {
+ if (markPos >= 0 && limit == buffer.length)
+ markPos = -1;
+ if (markPos <= 0)
+ pos = limit = 0;
+ int count = in.read(buffer, limit, buffer.length - limit);
+ if (count <= 0)
+ return -1;
+ limit += count;
+ }
+ char ch = buffer[pos++];
+ if (ch == '\r' || ch == '\n')
+ {
+ lineNumber++;
+ return '\n';
+ }
+ return (int) ch;
+ }
+ }
+
+ public int read(char[] buf, int offset, int count) throws IOException
+ {
+ if (count <= 0)
+ {
+ if (count < 0)
+ throw new IndexOutOfBoundsException();
+ return 0;
+ }
+ synchronized (lock)
+ {
+ int first = read();
+ if (first < 0)
+ return -1;
+ int start_offset = offset;
+ buf[offset++] = (char) first;
+ if (buffer[pos-1] == '\r' && pos < limit && buffer[pos] == '\n')
+ pos++;
+ count--;
+ while (count-- > 0 && pos < limit)
+ {
+ char ch = buffer[pos++];
+ if (ch == '\r')
+ {
+ lineNumber++;
+ ch = '\n';
+ if (pos < limit && buffer[pos] == '\n')
+ pos++;
+ }
+ else if (ch == '\n')
+ lineNumber++;
+ buf[offset++] = ch;
+ }
+ return offset - start_offset;
+ }
+ }
+
+ private void skipRedundantLF() throws IOException
+ {
+ if (pos > 0 && buffer[pos-1] == '\r')
+ {
+ if (pos < limit)
+ { // fast case
+ if (buffer[pos] == '\n')
+ pos++;
+ }
+ else
+ { // use read() to deal with the general case.
+ // Set pos and limit to zero to avoid infinite recursion in read.
+ // May need to invalidate markPos if we've exceeded the buffer.
+ if (pos >= buffer.length)
+ markPos = -1;
+ pos = limit = 0;
+ int ch = read();
+ if (ch >= 0 && ch != '\n')
+ pos--;
+ }
+ }
+ }
+
+ public String readLine() throws IOException
+ {
+ // BufferedReader.readLine already does this. Shouldn't need to keep
+ // track of newlines (since the read method deals with this for us).
+ // But if the buffer is large, we may not call the read method at all
+ // and super.readLine can't increment lineNumber itself.
+ // Though it may seem kludgy, the safest thing to do is to save off
+ // lineNumber and increment it explicitly when we're done (iff we
+ // ended with a '\n' or '\r' as opposed to EOF).
+ //
+ // Also, we need to undo the special casing done by BufferedReader.readLine
+ // when a '\r' is the last char in the buffer. That situation is marked
+ // by 'pos > limit'.
+ int tmpLineNumber = lineNumber;
+ skipRedundantLF();
+ String str = super.readLine();
+ if (pos > limit)
+ --pos;
+
+ int ch;
+ if (pos > 0 && ((ch = buffer[pos - 1]) == '\n' || ch == '\r'))
+ lineNumber = tmpLineNumber + 1;
+
+ return str;
+ }
+
+ public long skip(long count) throws IOException
+ {
+ if (count <= 0)
+ return 0;
+ long to_do = count;
+ do
+ {
+ int ch = read();
+ if (ch < 0)
+ break;
+ to_do--;
+ if (ch == '\n' || ch == '\r')
+ lineNumber++;
+ else
+ {
+ long fence = pos + to_do;
+ if (limit < fence)
+ fence = limit;
+ int end = pos;
+ for (; end < fence; end++)
+ {
+ char endch = buffer[end];
+ if (endch == '\n' || endch == '\r')
+ break;
+ }
+ to_do -= end - pos;
+ pos = end;
+ }
+ }
+ while (to_do > 0);
+ return count - to_do;
+ }
+}
diff --git a/libjava/java/io/OutputStream.java b/libjava/java/io/OutputStream.java
new file mode 100644
index 0000000..5aae361
--- /dev/null
+++ b/libjava/java/io/OutputStream.java
@@ -0,0 +1,48 @@
+// OutputStream.java - Send output bytes to output sink.
+
+/* 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 24, 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 version 1.1.
+ */
+
+public abstract class OutputStream
+{
+ public abstract void write (int b) throws IOException;
+
+ public void write (byte[] b) throws IOException, NullPointerException
+ {
+ write (b, 0, b.length);
+ }
+
+ public void write (byte[] b, int off, int len)
+ throws IOException, NullPointerException, IndexOutOfBoundsException
+ {
+ if (off < 0 || len < 0 || off + len > b.length)
+ throw new ArrayIndexOutOfBoundsException ();
+ for (int i = 0; i < len; ++i)
+ write (b[off + i]);
+ }
+
+ public void flush () throws IOException
+ {
+ }
+
+ public void close () throws IOException
+ {
+ }
+}
diff --git a/libjava/java/io/OutputStreamWriter.java b/libjava/java/io/OutputStreamWriter.java
new file mode 100644
index 0000000..e529474
--- /dev/null
+++ b/libjava/java/io/OutputStreamWriter.java
@@ -0,0 +1,155 @@
+/* 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;
+import gnu.gcj.convert.UnicodeToBytes;
+
+/**
+ * @author Per Bothner <bothner@cygnus.com>
+ * @date April 17, 1998.
+ */
+/* Written using "Java Class Libraries", 2nd edition, plus online
+ * API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct, but only supports 8859_1.
+ */
+
+public class OutputStreamWriter extends Writer
+{
+ BufferedOutputStream out;
+
+ UnicodeToBytes converter;
+
+ /* Temporary buffer. */
+ private char[] work;
+ private int wcount;
+
+ public String getEncoding() { return converter.getName(); }
+
+ private OutputStreamWriter(OutputStream out, UnicodeToBytes encoder)
+ {
+ super(out);
+ this.out = out instanceof BufferedOutputStream ? (BufferedOutputStream) out
+ : new BufferedOutputStream(out, 2048);
+ this.converter = encoder;
+ }
+
+ public OutputStreamWriter(OutputStream out, String enc)
+ throws UnsupportedEncodingException
+ {
+ this(out, UnicodeToBytes.getEncoder(enc));
+ }
+
+ public OutputStreamWriter(OutputStream out)
+ {
+ this(out, UnicodeToBytes.getDefaultEncoder());
+ }
+
+ public void close() throws IOException
+ {
+ synchronized (lock)
+ {
+ flush();
+ if (out != null)
+ {
+ out.close();
+ out = null;
+ }
+ work = null;
+ }
+ }
+
+ public void flush() throws IOException
+ {
+ synchronized (lock)
+ {
+ if (wcount > 0)
+ {
+ writeChars(work, 0, wcount);
+ wcount = 0;
+ }
+ out.flush();
+ }
+ }
+
+ public void write(char[] buf, int offset, int count)
+ throws IOException
+ {
+ synchronized (lock)
+ {
+ if (wcount > 0)
+ {
+ writeChars(work, 0, wcount);
+ wcount = 0;
+ }
+ writeChars(buf, offset, count);
+ }
+ }
+
+ private void writeChars(char[] buf, int offset, int count)
+ throws IOException
+ {
+ while (count > 0)
+ {
+ if (out.count != 0)
+ {
+ out.flush();
+ if (out.count != 0)
+ throw new IOException("unable to flush output byte buffer");
+ }
+ converter.setOutput(out.buf, out.count);
+ int converted = converter.write(buf, offset, count);
+ offset += converted;
+ count -= converted;
+ out.count = converter.count;
+ }
+ }
+
+ public void write(String str, int offset, int count)
+ throws IOException
+ {
+ synchronized (lock)
+ {
+ if (work == null)
+ work = new char[100];
+ int wlength = work.length;
+ while (count > 0)
+ {
+ int size = count;
+ if (wcount + size > wlength)
+ {
+ if (2*wcount > wlength)
+ {
+ writeChars(work, 0, wcount);
+ wcount = 0;
+ }
+ if (wcount + size > wlength)
+ size = wlength - wcount;
+ }
+ str.getChars(offset, offset+size, work, wcount);
+ offset += size;
+ count -= size;
+ wcount += size;
+ }
+ }
+ }
+
+ public void write(int ch) throws IOException
+ {
+ synchronized (lock)
+ {
+ if (work == null)
+ work = new char[100];
+ if (wcount >= work.length)
+ {
+ writeChars(work, 0, wcount);
+ wcount = 0;
+ }
+ work[wcount++] = (char) ch;
+ }
+ }
+}
diff --git a/libjava/java/io/PipedInputStream.java b/libjava/java/io/PipedInputStream.java
new file mode 100644
index 0000000..d8a836c
--- /dev/null
+++ b/libjava/java/io/PipedInputStream.java
@@ -0,0 +1,242 @@
+/* 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 Warren Levy <warrenl@cygnus.com>
+ * @date October 29, 1998.
+ */
+/* 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.
+ */
+
+public class PipedInputStream extends InputStream
+{
+ /* The size of the pipe's circular input buffer. */
+ protected static final int PIPE_SIZE = 1024;
+
+ /* 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;
+
+ /* 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;
+
+ /* Flag to indicate that the output stream was closed. */
+ private boolean outClosed = false;
+
+ public PipedInputStream(PipedOutputStream src) throws IOException
+ {
+ buffer = new byte[PIPE_SIZE];
+ connect(src);
+ }
+
+ public PipedInputStream()
+ {
+ buffer = new byte[PIPE_SIZE];
+ }
+
+ public synchronized int available() throws IOException
+ {
+ if (in < 0)
+ return 0;
+
+ if (in > out)
+ return in - out;
+
+ // Buffer has wrapped around.
+ return buffer.length - out + in;
+ }
+
+ public void close() throws IOException
+ {
+ buffer = null;
+ po = null;
+
+ // Mark as empty for available method.
+ in = -1;
+ }
+
+ public void connect(PipedOutputStream src) throws IOException
+ {
+ if (buffer == null)
+ throw new IOException("pipe closed");
+
+ if (po != null)
+ if (po == src)
+ return;
+ else
+ throw new IOException("pipe already connected");
+
+ po = src;
+ try
+ {
+ src.connect(this);
+ }
+ catch (IOException ex)
+ {
+ po = null;
+ throw ex;
+ }
+ }
+
+ 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();
+ }
+}
diff --git a/libjava/java/io/PipedOutputStream.java b/libjava/java/io/PipedOutputStream.java
new file mode 100644
index 0000000..9b06994
--- /dev/null
+++ b/libjava/java/io/PipedOutputStream.java
@@ -0,0 +1,94 @@
+// PipedOutputStream.java - Write bytes to a pipe.
+
+/* 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 24, 1998
+ */
+
+/* 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.
+ */
+
+public class PipedOutputStream extends OutputStream
+{
+ 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);
+ }
+
+ // This is mentioned in the JCL book, but we don't really need it.
+ // If there were a corresponding receive() method on
+ // PipedInputStream then we could get better performance using
+ // this.
+ // public void write (byte[] buffer, int offset, int count)
+ // throws IOException;
+
+ // Instance variables.
+ private PipedInputStream destination;
+ private boolean closed;
+}
diff --git a/libjava/java/io/PipedReader.java b/libjava/java/io/PipedReader.java
new file mode 100644
index 0000000..f54c4f8
--- /dev/null
+++ b/libjava/java/io/PipedReader.java
@@ -0,0 +1,210 @@
+// 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;
+}
diff --git a/libjava/java/io/PipedWriter.java b/libjava/java/io/PipedWriter.java
new file mode 100644
index 0000000..c914cac
--- /dev/null
+++ b/libjava/java/io/PipedWriter.java
@@ -0,0 +1,88 @@
+// PipedWriter.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 PipedWriter extends Writer
+{
+ 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;
+}
diff --git a/libjava/java/io/PrintStream.java b/libjava/java/io/PrintStream.java
new file mode 100644
index 0000000..499e5eb
--- /dev/null
+++ b/libjava/java/io/PrintStream.java
@@ -0,0 +1,236 @@
+// PrintStream.java - Print string representations
+
+/* 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 24, 1998
+ */
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * Status: Not finished.
+ */
+
+public class PrintStream extends FilterOutputStream
+{
+ public boolean checkError ()
+ {
+ return error;
+ }
+
+ public void close ()
+ {
+ try
+ {
+ out.close();
+ }
+ catch (IOException e)
+ {
+ setError ();
+ }
+ }
+
+ public void flush ()
+ {
+ try
+ {
+ out.flush();
+ }
+ catch (IOException e)
+ {
+ setError ();
+ }
+ }
+
+ private final void print (String str, boolean check_term)
+ {
+ try
+ {
+ write(str.getBytes());
+ if (check_term
+ && auto_flush
+ && str.indexOf(line_separator) != -1)
+ flush ();
+ }
+ catch (IOException e)
+ {
+ setError ();
+ }
+ }
+
+ public void print (boolean bool)
+ {
+ print (String.valueOf(bool), false);
+ }
+
+ public void print (int inum)
+ {
+ print (String.valueOf(inum), false);
+ }
+
+ public void print (long lnum)
+ {
+ print (String.valueOf(lnum), false);
+ }
+
+ public void print (float fnum)
+ {
+ print (String.valueOf(fnum), false);
+ }
+
+ public void print (double dnum)
+ {
+ print (String.valueOf(dnum), false);
+ }
+
+ public void print (Object obj)
+ {
+ print (String.valueOf(obj), false);
+ }
+
+ public void print (String str)
+ {
+ print (str, true);
+ }
+
+ public void print (char ch)
+ {
+ print (String.valueOf(ch), true);
+ }
+
+ public void print (char[] charArray)
+ {
+ print (String.valueOf(charArray), true);
+ }
+
+ public void println ()
+ {
+ print (line_separator, false);
+ if (auto_flush)
+ flush ();
+ }
+
+ public void println (boolean bool)
+ {
+ print (String.valueOf(bool), false);
+ println ();
+ }
+
+ public void println (int inum)
+ {
+ print (String.valueOf(inum), false);
+ println ();
+ }
+
+ public void println (long lnum)
+ {
+ print (String.valueOf(lnum), false);
+ println ();
+ }
+
+ public void println (float fnum)
+ {
+ print (String.valueOf(fnum), false);
+ println ();
+ }
+
+ public void println (double dnum)
+ {
+ print (String.valueOf(dnum), false);
+ println ();
+ }
+
+ public void println (Object obj)
+ {
+ print (String.valueOf(obj), false);
+ println ();
+ }
+
+ public void println (String str)
+ {
+ print (str, false);
+ println ();
+ }
+
+ public void println (char ch)
+ {
+ print (String.valueOf(ch), false);
+ println ();
+ }
+
+ public void println (char[] charArray)
+ {
+ print (String.valueOf(charArray), false);
+ println ();
+ }
+
+ public PrintStream (OutputStream out)
+ {
+ super (out);
+ error = false;
+ auto_flush = false;
+ }
+
+ public PrintStream (OutputStream out, boolean af)
+ {
+ super (out);
+ error = false;
+ auto_flush = af;
+ }
+
+ protected void setError ()
+ {
+ error = true;
+ }
+
+ public void write (int oneByte)
+ {
+ try
+ {
+ out.write(oneByte);
+ // JCL says to do this. I think it is wrong. FIXME.
+ if (auto_flush && oneByte == '\n')
+ out.flush();
+ }
+ catch (IOException e)
+ {
+ setError ();
+ }
+ }
+
+ public void write (byte[] buffer, int offset, int count)
+ {
+ try
+ {
+ out.write(buffer, offset, count);
+ // FIXME: JCL says to flush. But elsewhere the JCL says to
+ // use write to write the stringified form of an object, and
+ // only to flush if that string contains the line separator.
+ // How to resolve the contradiction?
+ if (auto_flush)
+ out.flush();
+ }
+ catch (IOException e)
+ {
+ setError ();
+ }
+ }
+
+ // True if error occurred.
+ private boolean error;
+ // True if auto-flush.
+ private boolean auto_flush;
+
+ // Line separator string.
+ private static final String line_separator
+ = System.getProperty("line.separator");
+}
diff --git a/libjava/java/io/PrintWriter.java b/libjava/java/io/PrintWriter.java
new file mode 100644
index 0000000..2a6cb01
--- /dev/null
+++ b/libjava/java/io/PrintWriter.java
@@ -0,0 +1,286 @@
+/* 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 Per Bothner <bothner@cygnus.com>
+ * @date April 17, 1998.
+ */
+/* Written using "Java Class Libraries", 2nd edition, plus online
+ * API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct.
+ * However, should use native methods for conversion.
+ */
+
+public class PrintWriter extends Writer
+{
+ private boolean autoflush;
+ private boolean error;
+ Writer out;
+
+ public PrintWriter(Writer wr)
+ {
+ super(wr);
+ this.out = wr;
+ }
+
+ public PrintWriter(Writer wr, boolean autoflush)
+ {
+ super(wr);
+ this.out = wr;
+ this.autoflush = autoflush;
+ }
+
+ public PrintWriter(OutputStream out)
+ {
+ super();
+ this.out = new OutputStreamWriter(out);
+ this.lock = this.out;
+ }
+
+ public PrintWriter(OutputStream out, boolean autoflush)
+ {
+ this(out);
+ this.autoflush = autoflush;
+ }
+ protected void setError() { error = true; }
+
+ public boolean checkError()
+ {
+ flush();
+ return error;
+ }
+
+ public void flush()
+ {
+ try
+ {
+ out.flush();
+ }
+ catch (IOException ex)
+ {
+ error = true;
+ }
+ }
+
+ public void close()
+ {
+ try
+ {
+ out.close();
+ }
+ catch (IOException ex)
+ {
+ error = true;
+ }
+ }
+
+ public void print(String str)
+ {
+ try
+ {
+ out.write(str == null ? "null" : str);
+ }
+ catch (IOException ex)
+ {
+ error = true;
+ }
+ }
+
+ public void print(char ch)
+ {
+ write((int) ch);
+ }
+
+ public void print(char[] charArray)
+ {
+ write(charArray, 0, charArray.length);
+ }
+
+ public void print(boolean bool)
+ {
+ print(bool ? "true" : "false");
+ }
+
+ public void print(int inum)
+ {
+ print(Integer.toString(inum));
+ }
+
+ public void print(long lnum)
+ {
+ print(Long.toString(lnum));
+ }
+
+ public void print(float fnum)
+ {
+ print(Float.toString(fnum));
+ }
+
+ public void print(double dnum)
+ {
+ print(Double.toString(dnum));
+ }
+
+ public void print(Object obj)
+ {
+ print(obj == null ? "null" : obj.toString());
+ }
+
+ private static final char[] line_separator
+ = System.getProperty("line.separator").toCharArray();
+
+ public void println()
+ {
+ synchronized (lock)
+ {
+ printlnUnsynchronized();
+ }
+ }
+
+ private void printlnUnsynchronized()
+ {
+ try
+ {
+ write(line_separator, 0, line_separator.length);
+ if (autoflush)
+ out.flush();
+ }
+ catch (IOException ex)
+ {
+ error = true;
+ }
+ }
+
+ public void println(boolean bool)
+ {
+ synchronized (lock)
+ {
+ print(bool);
+ printlnUnsynchronized();
+ }
+ }
+ public void println(int inum)
+ {
+ synchronized (lock)
+ {
+ print(inum);
+ printlnUnsynchronized();
+ }
+ }
+
+ public void println(long lnum)
+ {
+ synchronized (lock)
+ {
+ print(lnum);
+ printlnUnsynchronized();
+ }
+ }
+
+ public void println(float fnum)
+ {
+ synchronized (lock)
+ {
+ print(fnum);
+ printlnUnsynchronized();
+ }
+ }
+
+ public void println(double dnum)
+ {
+ synchronized (lock)
+ {
+ print(dnum);
+ printlnUnsynchronized();
+ }
+ }
+
+ public void println(Object obj)
+ {
+ synchronized (lock)
+ {
+ print(obj);
+ printlnUnsynchronized();
+ }
+ }
+
+ public void println(String str)
+ {
+ synchronized (lock)
+ {
+ print(str);
+ printlnUnsynchronized();
+ }
+ }
+
+ public void println(char ch)
+ {
+ synchronized (lock)
+ {
+ print(ch);
+ printlnUnsynchronized();
+ }
+ }
+
+ public void println(char[] charArray)
+ {
+ synchronized (lock)
+ {
+ print(charArray);
+ printlnUnsynchronized();
+ }
+ }
+
+ public void write(int ch)
+ {
+ try
+ {
+ out.write(ch);
+ }
+ catch (IOException ex)
+ {
+ error = true;
+ }
+ }
+
+ public void write(char[] charArray, int offset, int count)
+ {
+ try
+ {
+ out.write(charArray, offset, count);
+ }
+ catch (IOException ex)
+ {
+ error = true;
+ }
+ }
+
+ public void write(String str, int offset, int count)
+ {
+ try
+ {
+ out.write(str, offset, count);
+ }
+ catch (IOException ex)
+ {
+ error = true;
+ }
+ }
+
+ public void write(char[] charArray)
+ {
+ write(charArray, 0, charArray.length);
+ }
+
+ public void write(String str)
+ {
+ write(str, 0, str.length());
+ }
+}
diff --git a/libjava/java/io/PushbackInputStream.java b/libjava/java/io/PushbackInputStream.java
new file mode 100644
index 0000000..58c8fe6
--- /dev/null
+++ b/libjava/java/io/PushbackInputStream.java
@@ -0,0 +1,124 @@
+/* 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 Warren Levy <warrenl@cygnus.com>
+ * @date October 15, 1998.
+ */
+/* 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.
+ */
+
+public class PushbackInputStream extends FilterInputStream
+{
+ /* Internal buffer array for data. */
+ protected byte[] buf;
+
+ /* The current position in the buffer. */
+ protected int pos;
+
+ public PushbackInputStream(InputStream in)
+ {
+ this(in, 1);
+ }
+
+ public PushbackInputStream(InputStream in, int size)
+ {
+ super(in);
+ if (size < 0)
+ throw new IllegalArgumentException();
+ buf = new byte[size];
+ pos = buf.length;
+ }
+
+ public int available() throws IOException
+ {
+ return pos + super.available();
+ }
+
+ public void close() throws IOException
+ {
+ buf = null;
+ super.close();
+ }
+
+ public boolean markSupported()
+ {
+ return false;
+ }
+
+ public int read() throws IOException
+ {
+ if (pos < buf.length)
+ return ((int) buf[pos++]) & 0xFF;
+
+ return super.read();
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException
+ {
+ if (off < 0 || len < 0 || off + len > b.length)
+ throw new ArrayIndexOutOfBoundsException();
+
+ int numBytes = Math.min(buf.length - pos, len);
+ for (int i = 0; i < numBytes; i++)
+ b[off++] = buf[pos++];
+
+ // `off' was just incremented to include `numBytes', so we can
+ // just pass ithere.
+ return numBytes + super.read(b, off, len - numBytes);
+ }
+
+ public void unread(int b) throws IOException
+ {
+ if (pos <= 0)
+ throw new IOException();
+
+ buf[--pos] = (byte) b;
+ }
+
+ public void unread(byte[] b) throws IOException
+ {
+ unread(b, 0, b.length);
+ }
+
+ public void unread(byte[] b, int off, int len) throws IOException
+ {
+ if (pos < len)
+ throw new IOException();
+
+ // Note the order that these bytes are being added is the opposite
+ // of what would be done if they were added to the buffer one at a time.
+ // See the Java Class Libraries book p. 1390.
+ System.arraycopy(b, off, buf, pos - len, len);
+
+ // Don't put this into the arraycopy above, an exception might be thrown
+ // and in that case we don't want to modify pos.
+ pos -= len;
+ }
+
+ // JDK1.2
+ public long skip(long n) throws IOException
+ {
+ final long origN = n;
+
+ if (n > 0L)
+ {
+ int numread = (int) Math.min((long) (buf.length - pos), n);
+ pos += numread;
+ n -= numread;
+ n -= super.skip(n);
+ }
+
+ return origN - n;
+ }
+}
diff --git a/libjava/java/io/PushbackReader.java b/libjava/java/io/PushbackReader.java
new file mode 100644
index 0000000..0cfd63c
--- /dev/null
+++ b/libjava/java/io/PushbackReader.java
@@ -0,0 +1,136 @@
+/* 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 Warren Levy <warrenl@cygnus.com>
+ * @date October 16, 1998.
+ */
+/* 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.
+ */
+
+public class PushbackReader extends FilterReader
+{
+ /* Internal buffer array for data. */
+ private char[] buf;
+
+ /* The current position in the buffer. */
+ private int pos;
+
+ public PushbackReader(Reader in)
+ {
+ this(in, 1);
+ }
+
+ public PushbackReader(Reader in, int size)
+ {
+ super(in);
+ if (size < 0)
+ throw new IllegalArgumentException();
+ buf = new char[size];
+ pos = buf.length;
+ }
+
+ public void close() throws IOException
+ {
+ synchronized (lock)
+ {
+ buf = null;
+ super.close();
+ }
+ }
+
+ public boolean markSupported()
+ {
+ return false;
+ }
+
+ public int read() throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException();
+
+ if (pos < buf.length)
+ return ((int) buf[pos++]) & 0xFFFF;
+
+ return super.read();
+ }
+ }
+
+ public int read(char[] b, int off, int len) throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException();
+
+ if (off < 0 || len < 0 || off + len > b.length)
+ throw new ArrayIndexOutOfBoundsException();
+
+ int numBytes = Math.min(buf.length - pos, len);
+ for (int i = 0; i < numBytes; i++)
+ b[off++] = buf[pos++];
+
+ return numBytes + super.read(b, off, len - numBytes);
+ }
+ }
+
+ public boolean ready() throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException();
+
+ if (buf.length - pos > 0)
+ return true;
+
+ return super.ready();
+ }
+ }
+
+ public void unread(int b) throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null || pos <= 0)
+ throw new IOException();
+
+ buf[--pos] = (char) b;
+ }
+ }
+
+ public void unread(char[] b) throws IOException
+ {
+ unread(b, 0, b.length);
+ }
+
+ public void unread(char[] b, int off, int len) throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null || pos < len)
+ throw new IOException();
+
+ // Note the order that these chars are being added is the opposite
+ // of what would be done if they were added to the buffer one at a time.
+ // See the Java Class Libraries book p. 1397.
+ System.arraycopy(b, off, buf, pos - len, len);
+
+ // Don't put this into the arraycopy above, an exception might be thrown
+ // and in that case we don't want to modify pos.
+ pos -= len;
+ }
+ }
+}
diff --git a/libjava/java/io/RandomAccessFile.java b/libjava/java/io/RandomAccessFile.java
new file mode 100644
index 0000000..d240e0d
--- /dev/null
+++ b/libjava/java/io/RandomAccessFile.java
@@ -0,0 +1,249 @@
+// RandomAccessFile.java
+
+/* 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: not finished
+ */
+
+public class RandomAccessFile implements DataOutput, DataInput
+{
+ public void close () throws IOException
+ {
+ fd.close();
+ }
+
+ public final FileDescriptor getFD () throws IOException
+ {
+ if (! fd.valid())
+ throw new IOException ();
+ return fd;
+ }
+
+ public long getFilePointer () throws IOException
+ {
+ return fd.getFilePointer();
+ }
+
+ public long length () throws IOException
+ {
+ return fd.length();
+ }
+
+ public RandomAccessFile (String fileName, String mode) throws IOException
+ {
+ int fdmode;
+ if (mode.compareTo ("r") == 0)
+ fdmode = FileDescriptor.READ;
+ else if (mode.compareTo ("rw") == 0)
+ fdmode = FileDescriptor.READ | FileDescriptor.WRITE;
+ else
+ throw new IllegalArgumentException ("invalid mode: " + mode);
+
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ {
+ s.checkRead(fileName);
+ if ((fdmode & FileDescriptor.WRITE) != 0)
+ s.checkWrite(fileName);
+ }
+
+ fd = new FileDescriptor (fileName, fdmode);
+ // FIXME: read-only mode.
+ out = new DataOutputStream (new FileOutputStream (fd));
+ in = new DataInputStream (new FileInputStream (fd));
+ }
+
+ public RandomAccessFile (File file, String mode) throws IOException
+ {
+ this (file.getPath(), mode);
+ }
+
+ public int read () throws IOException
+ {
+ return in.read();
+ }
+
+ public int read (byte[] buffer) throws IOException
+ {
+ return in.read(buffer);
+ }
+
+ public int read (byte[] buffer, int offset, int count) throws IOException
+ {
+ return in.read(buffer, offset, count);
+ }
+
+ public final boolean readBoolean () throws IOException
+ {
+ return in.readBoolean();
+ }
+
+ public final byte readByte () throws IOException
+ {
+ return in.readByte();
+ }
+
+ public final char readChar () throws IOException
+ {
+ return in.readChar();
+ }
+
+ public final double readDouble () throws IOException
+ {
+ return in.readDouble();
+ }
+
+ public final float readFloat () throws IOException
+ {
+ return in.readFloat();
+ }
+
+ public final void readFully (byte[] buffer) throws IOException
+ {
+ // FIXME.
+ }
+
+ public final void readFully (byte[] buffer, int offset, int count)
+ throws IOException
+ {
+ // FIXME.
+ }
+
+ public final int readInt () throws IOException
+ {
+ return in.readInt();
+ }
+
+ public final String readLine () throws IOException
+ {
+ // FIXME?
+ return in.readLine();
+ }
+
+ public final long readLong () throws IOException
+ {
+ return in.readLong();
+ }
+
+ public final short readShort () throws IOException
+ {
+ return in.readShort();
+ }
+
+ public final int readUnsignedByte () throws IOException
+ {
+ return in.readUnsignedByte();
+ }
+
+ public final int readUnsignedShort () throws IOException
+ {
+ return in.readUnsignedShort();
+ }
+
+ public final String readUTF () throws IOException
+ {
+ return in.readUTF();
+ }
+
+ public void seek (long pos) throws IOException
+ {
+ fd.seek(pos, FileDescriptor.SET);
+ }
+
+ public int skipBytes (int count) throws IOException
+ {
+ return fd.seek(count, FileDescriptor.CUR);
+ }
+
+ public void write (int oneByte) throws IOException
+ {
+ out.write(oneByte);
+ }
+
+ public void write (byte[] buffer) throws IOException
+ {
+ out.write(buffer);
+ }
+
+ public void write (byte[] buffer, int offset, int count) throws IOException
+ {
+ out.write(buffer, offset, count);
+ }
+
+ public final void writeBoolean (boolean val) throws IOException
+ {
+ out.writeBoolean(val);
+ }
+
+ public final void writeByte (int v) throws IOException
+ {
+ out.writeByte(v);
+ }
+
+ public final void writeShort (int v) throws IOException
+ {
+ out.writeShort(v);
+ }
+
+ public final void writeChar (int v) throws IOException
+ {
+ out.writeChar(v);
+ }
+
+ public final void writeInt (int v) throws IOException
+ {
+ out.writeInt(v);
+ }
+
+ public final void writeLong (long v) throws IOException
+ {
+ out.writeLong(v);
+ }
+
+ public final void writeFloat (float v) throws IOException
+ {
+ out.writeFloat(v);
+ }
+
+ public final void writeDouble (double v) throws IOException
+ {
+ out.writeDouble(v);
+ }
+
+ public final void writeBytes (String s) throws IOException
+ {
+ out.writeBytes(s);
+ }
+
+ public final void writeChars (String s) throws IOException
+ {
+ out.writeChars(s);
+ }
+
+ public final void writeUTF (String s) throws IOException
+ {
+ out.writeUTF(s);
+ }
+
+
+ // The underlying file.
+ private FileDescriptor fd;
+ // The corresponding input and output streams.
+ private DataOutputStream out;
+ private DataInputStream in;
+}
diff --git a/libjava/java/io/Reader.java b/libjava/java/io/Reader.java
new file mode 100644
index 0000000..b547358
--- /dev/null
+++ b/libjava/java/io/Reader.java
@@ -0,0 +1,87 @@
+/* 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 Per Bothner <bothner@cygnus.com>
+ * @date April 21, 1998.
+ */
+/* Written using "Java Class Libraries", 2nd edition, plus online
+ * API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct.
+ */
+
+public abstract class Reader
+{
+ protected Object lock;
+
+ protected Reader()
+ {
+ this.lock = this;
+ }
+
+ protected Reader(Object lock)
+ {
+ this.lock = lock;
+ }
+
+ abstract public int read(char buf[], int offset, int count)
+ throws IOException;
+
+ public int read(char buf[]) throws IOException
+ {
+ return read(buf, 0, buf.length);
+ }
+
+ public int read() throws IOException
+ {
+ char[] buf = new char[1];
+ int count = read(buf, 0, 1);
+ return count > 0 ? buf[0] : -1;
+ }
+
+ abstract public void close() throws IOException;
+
+ public boolean markSupported()
+ {
+ return false;
+ }
+
+ public void mark(int readLimit) throws IOException
+ {
+ throw new IOException("mark not supported");
+ }
+
+ public void reset() throws IOException
+ {
+ throw new IOException("reset not supported");
+ }
+
+ public boolean ready() throws IOException
+ {
+ return false;
+ }
+
+ public long skip(long count) throws IOException
+ {
+ if (count <= 0)
+ return 0;
+ int bsize = count > 1024 ? 1024 : (int) count;
+ char[] buffer = new char[bsize];
+ long todo = count;
+ while (todo > 0)
+ {
+ int skipped = read(buffer, 0, bsize > todo ? (int) todo : bsize);
+ if (skipped <= 0)
+ break;
+ todo -= skipped;
+ }
+ return count - todo;
+ }
+}
diff --git a/libjava/java/io/SequenceInputStream.java b/libjava/java/io/SequenceInputStream.java
new file mode 100644
index 0000000..7713517
--- /dev/null
+++ b/libjava/java/io/SequenceInputStream.java
@@ -0,0 +1,112 @@
+/* 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;
+
+import java.util.Enumeration;
+
+/**
+ * @author Warren Levy <warrenl@cygnus.com>
+ * @date November 3, 1998.
+ */
+/* 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.
+ */
+
+public class SequenceInputStream extends InputStream
+{
+ /* The handle for the current input stream. */
+ private InputStream in;
+
+ /* Secondary input stream; not used if constructed w/ enumeration. */
+ private InputStream in2;
+
+ /* The enum handle; not used if constructed w/ 2 explicit input streams. */
+ private Enumeration enum;
+
+ public SequenceInputStream(Enumeration e)
+ {
+ // FIXME: Assumes that enum contains only InputStreams.
+ enum = e;
+ in = (InputStream) enum.nextElement();
+ in2 = null;
+ }
+
+ public SequenceInputStream(InputStream s1, InputStream s2)
+ {
+ in = s1;
+ in2 = s2;
+ }
+
+ public int available() throws IOException
+ {
+ if (in == null)
+ return 0;
+
+ return in.available();
+ }
+
+ public void close() throws IOException
+ {
+ while (in != null)
+ {
+ in.close();
+ in = getNextStream ();
+ }
+ }
+
+ public int read() throws IOException
+ {
+ int ch = -1;
+
+ while (in != null && (ch = in.read()) < 0)
+ {
+ in.close();
+ in = getNextStream();
+ }
+
+ return ch;
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException
+ {
+ int ch = -1;
+
+ // The validity of the parameters will be checked by in.read so
+ // don't bother doing it here.
+ while (in != null && (ch = in.read(b, off, len)) < 0)
+ {
+ in.close();
+ in = getNextStream();
+ }
+
+ return ch;
+ }
+
+ private InputStream getNextStream()
+ {
+ InputStream nextIn = null;
+
+ // FIXME: Assumes that enum contains only InputStreams.
+ if (enum != null)
+ {
+ if (enum.hasMoreElements())
+ nextIn = (InputStream) enum.nextElement();
+ }
+ else
+ if (in2 != null)
+ {
+ nextIn = in2;
+ in2 = null;
+ }
+
+ return nextIn;
+ }
+}
diff --git a/libjava/java/io/Serializable.java b/libjava/java/io/Serializable.java
new file mode 100644
index 0000000..d4a31db
--- /dev/null
+++ b/libjava/java/io/Serializable.java
@@ -0,0 +1,21 @@
+/* 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 Warren Levy <warrenl@cygnus.com>
+ * @date August 18, 1998.
+ */
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * Status: Believed complete
+ */
+
+public interface Serializable
+{
+}
diff --git a/libjava/java/io/StreamTokenizer.java b/libjava/java/io/StreamTokenizer.java
new file mode 100644
index 0000000..d518f83
--- /dev/null
+++ b/libjava/java/io/StreamTokenizer.java
@@ -0,0 +1,433 @@
+/* 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 Warren Levy <warrenl@cygnus.com>
+ * @date October 25, 1998.
+ */
+/* 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.
+ */
+
+public class StreamTokenizer
+{
+ /* A constant indicating that the end of the stream has been read. */
+ public static final int TT_EOF = -1;
+
+ /* A constant indicating that the end of the line has been read. */
+ public static final int TT_EOL = '\n';
+
+ /* A constant indicating that a number token has been read. */
+ public static final int TT_NUMBER = -2;
+
+ /* A constant indicating that a word token has been read. */
+ public static final int TT_WORD = -3;
+
+ /* Contains the type of the token read resulting from a call to nextToken. */
+ public int ttype;
+
+ /* The String associated with word and string tokens. */
+ public String sval;
+
+ /* The numeric value associated with number tokens. */
+ public double nval;
+
+ /* Indicates whether end-of-line is recognized as a token. */
+ private boolean eolSignificant = false;
+
+ /* Indicates whether word tokens are automatically made lower case. */
+ private boolean lowerCase = false;
+
+ /* Indicates whether C++ style comments are recognized and skipped. */
+ private boolean slashSlash = false;
+
+ /* Indicates whether C style comments are recognized and skipped. */
+ private boolean slashStar = false;
+
+ /* Attribute tables of each byte from 0x00 to 0xFF. */
+ private boolean[] whitespace;
+ private boolean[] alphabetic;
+ private boolean[] numeric;
+ private boolean[] quote;
+ private boolean[] comment;
+
+ /* The Reader associated with this class. */
+ private PushbackReader in;
+
+ /* Indicates if a token has been pushed back. */
+ private boolean pushedBack = false;
+
+ /* Contains the current line number of the reader. */
+ private int lineNumber = 1;
+
+ // Deprecated in JDK 1.1.
+ public StreamTokenizer(InputStream is)
+ {
+ this(new InputStreamReader(is));
+ }
+
+ public StreamTokenizer(Reader r)
+ {
+ in = new PushbackReader(r);
+
+ whitespace = new boolean[256];
+ alphabetic = new boolean[256];
+ numeric = new boolean[256];
+ quote = new boolean[256];
+ comment = new boolean[256];
+ for (int i = 0; i < 256; i++)
+ resetChar(i);
+
+ whitespaceChars(0x00, 0x20);
+ wordChars('A', 'Z');
+ wordChars('a', 'z');
+ wordChars(0xA0, 0xFF);
+ commentChar('/');
+ quoteChar('\'');
+ quoteChar('"');
+ parseNumbers();
+ }
+
+ public void commentChar(int ch)
+ {
+ if (ch >= 0 && ch <= 255)
+ comment[ch] = true;
+ }
+
+ public void eolIsSignificant(boolean flag)
+ {
+ eolSignificant = flag;
+ }
+
+ public int lineno()
+ {
+ return lineNumber;
+ }
+
+ public void lowerCaseMode(boolean flag)
+ {
+ lowerCase = flag;
+ }
+
+ private boolean isWhitespace(int ch)
+ {
+ if (ch >= 0 && ch <= 255)
+ return whitespace[ch];
+
+ return false;
+ }
+
+ private boolean isAlphabetic(int ch)
+ {
+ if (ch >= 0 && ch <= 255)
+ return alphabetic[ch];
+ else if (ch > 255)
+ return true;
+
+ return false;
+ }
+
+ private boolean isNumeric(int ch)
+ {
+ if (ch >= 0 && ch <= 255)
+ return numeric[ch];
+
+ return false;
+ }
+
+ private boolean isQuote(int ch)
+ {
+ if (ch >= 0 && ch <= 255)
+ return quote[ch];
+
+ return false;
+ }
+
+ private boolean isComment(int ch)
+ {
+ if (ch >= 0 && ch <= 255)
+ return comment[ch];
+
+ return false;
+ }
+
+ public int nextToken() throws IOException
+ {
+ if (pushedBack)
+ {
+ pushedBack = false;
+ return ttype;
+ }
+
+ sval = null;
+ int ch;
+
+ // Skip whitespace. Deal with EOL along the way.
+ while (isWhitespace(ch = in.read()))
+ if (ch == '\n' || ch == '\r')
+ {
+ lineNumber++;
+
+ // Throw away \n if in combination with \r.
+ if (ch == '\r' && (ch = in.read()) != '\n')
+ in.unread(ch);
+ if (eolSignificant)
+ return (ttype = TT_EOL);
+ }
+
+ if (ch == TT_EOF)
+ ttype = TT_EOF;
+ else if (isNumeric(ch))
+ {
+ if (ch == '-')
+ {
+ // Read ahead to see if this is an ordinary '-' rather than numeric.
+ ch = in.read();
+ in.unread(ch);
+ if (isNumeric(ch) && ch != '-')
+ ch = '-';
+ else
+ return (ttype = '-');
+ }
+
+ StringBuffer tokbuf = new StringBuffer();
+ tokbuf.append((char) ch);
+
+ int decCount = 0;
+ while (isNumeric(ch = in.read()) && ch != '-')
+ if (ch == '.' && decCount++ > 0)
+ break;
+ else
+ tokbuf.append((char) ch);
+
+ in.unread(ch);
+ ttype = TT_NUMBER;
+ nval = Double.valueOf(tokbuf.toString()).doubleValue();
+ }
+ else if (isAlphabetic(ch))
+ {
+ StringBuffer tokbuf = new StringBuffer();
+ tokbuf.append((char) ch);
+ while (isAlphabetic(ch = in.read()) || isNumeric(ch))
+ tokbuf.append((char) ch);
+ in.unread(ch);
+ ttype = TT_WORD;
+ sval = tokbuf.toString();
+ if (lowerCase)
+ sval.toLowerCase();
+ }
+ else if (isComment(ch))
+ {
+ while ((ch = in.read()) != '\n' && ch != '\r' && ch != TT_EOF)
+ ;
+ in.unread(ch);
+ return nextToken(); // Recursive, but not too deep in normal cases.
+ }
+ else if (isQuote(ch))
+ {
+ ttype = ch;
+ StringBuffer tokbuf = new StringBuffer();
+ while ((ch = in.read()) != ttype && ch != '\n' && ch != '\r' &&
+ ch != TT_EOF)
+ {
+ if (ch == '\\')
+ switch (ch = in.read())
+ {
+ case 'a': ch = 0x7;
+ break;
+ case 'b': ch = '\b';
+ break;
+ case 'f': ch = 0xC;
+ break;
+ case 'n': ch = '\n';
+ break;
+ case 'r': ch = '\r';
+ break;
+ case 't': ch = '\t';
+ break;
+ case 'v': ch = 0xB;
+ break;
+ case '\"':
+ case '\'':
+ case '\\':
+ break;
+ default:
+ int ch1, nextch;
+ if ((nextch = ch1 = ch) >= '0' && ch <= '7')
+ {
+ ch -= '0';
+ if ((nextch = in.read()) >= '0' && nextch <= '7')
+ {
+ ch = ch * 8 + nextch - '0';
+ if ((nextch = in.read()) >= '0' && nextch <= '7' &&
+ ch1 >= '0' && ch1 <= '3')
+ {
+ ch = ch * 8 + nextch - '0';
+ nextch = in.read();
+ }
+ }
+ }
+
+ in.unread(nextch);
+ }
+
+ tokbuf.append((char) ch);
+ }
+
+ // Throw away matching quote char.
+ if (ch != ttype)
+ in.unread(ch);
+
+ sval = tokbuf.toString();
+ }
+ else
+ {
+ if (ch == '/')
+ if ((ch = in.read()) == '/' && slashSlash)
+ {
+ while ((ch = in.read()) != '\n' && ch != '\r' && ch != TT_EOF)
+ ;
+ in.unread(ch);
+ return nextToken(); // Recursive, but not too deep in normal cases
+ }
+ else if (ch == '*' && slashStar)
+ {
+ while (true)
+ {
+ ch = in.read();
+ if (ch == '*')
+ if ((ch = in.read()) == '/')
+ break;
+ else
+ in.unread(ch);
+ else if (ch == '\n' || ch == '\r')
+ {
+ lineNumber++;
+ if (ch == '\r' && (ch = in.read()) != '\n')
+ in.unread(ch);
+ }
+ else if (ch == TT_EOF)
+ {
+ in.unread(ch);
+ break;
+ }
+ }
+ return nextToken(); // Recursive, but not too deep in normal cases
+ }
+ else
+ {
+ in.unread(ch);
+ ch = '/';
+ }
+
+ ttype = ch;
+ }
+
+ return ttype;
+ }
+
+ private void resetChar(int ch)
+ {
+ whitespace[ch] = alphabetic[ch] = numeric[ch] = quote[ch] = comment[ch] =
+ false;
+ }
+
+ public void ordinaryChar(int ch)
+ {
+ if (ch >= 0 && ch <= 255)
+ resetChar(ch);
+ }
+
+ public void ordinaryChars(int low, int hi)
+ {
+ if (low < 0)
+ low = 0;
+ if (hi > 255)
+ hi = 255;
+ for (int i = low; i <= hi; i++)
+ resetChar(i);
+ }
+
+ public void parseNumbers()
+ {
+ for (int i = 0; i <= 9; i++)
+ numeric['0' + i] = true;
+
+ numeric['.'] = true;
+ numeric['-'] = true;
+ }
+
+ public void pushBack()
+ {
+ // pushBack may cause the lineno method to return an incorrect value
+ // if lineno is called before the next call to nextToken.
+ pushedBack = true;
+ }
+
+ public void quoteChar(int ch)
+ {
+ if (ch >= 0 && ch <= 255)
+ quote[ch] = true;
+ }
+
+ public void resetSyntax()
+ {
+ ordinaryChars(0x00, 0xFF);
+ }
+
+ public void slashSlashComments(boolean flag)
+ {
+ slashSlash = flag;
+ }
+
+ public void slashStarComments(boolean flag)
+ {
+ slashStar = flag;
+ }
+
+ public String toString()
+ {
+ String tempstr;
+ if (ttype == TT_EOF)
+ tempstr = "EOF";
+ else if (ttype == TT_EOL)
+ tempstr = "EOL";
+ else if (ttype == TT_WORD)
+ tempstr = sval;
+ else if (ttype == TT_NUMBER)
+ tempstr = "n=" + Double.toString(nval);
+ else // must be an ordinary char.
+ tempstr = "\'" + (new Character((char) ttype)).toString() + "\'";
+
+ return "Token[" + tempstr + "], line " + Integer.toString(lineno());
+ }
+
+ public void whitespaceChars(int low, int hi)
+ {
+ if (low < 0)
+ low = 0;
+ if (hi > 255)
+ hi = 255;
+ for (int i = low; i <= hi; i++)
+ whitespace[i] = true;
+ }
+
+ public void wordChars(int low, int hi)
+ {
+ if (low < 0)
+ low = 0;
+ if (hi > 255)
+ hi = 255;
+ for (int i = low; i <= hi; i++)
+ alphabetic[i] = true;
+ }
+}
diff --git a/libjava/java/io/StringBufferInputStream.java b/libjava/java/io/StringBufferInputStream.java
new file mode 100644
index 0000000..19e89db
--- /dev/null
+++ b/libjava/java/io/StringBufferInputStream.java
@@ -0,0 +1,83 @@
+/* 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 Warren Levy <warrenl@cygnus.com>
+ * @date November 11, 1998.
+ * @deprecated
+ */
+/* 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. Deprecated in JDK 1.1.
+ */
+
+public class StringBufferInputStream extends InputStream
+{
+ /* The String which is the input to this stream. */
+ protected String buffer;
+
+ /* Position of the next byte in buffer to be read. */
+ protected int pos = 0;
+
+ /* The length of the String buffer. */
+ protected int count;
+
+ public StringBufferInputStream(String s)
+ {
+ buffer = s;
+ count = s.length();
+ }
+
+ public int available()
+ {
+ return count - pos;
+ }
+
+ public int read()
+ {
+ if (pos >= count)
+ return -1; // EOF
+
+ return ((int) buffer.charAt(pos++)) & 0xFF;
+ }
+
+ public int read(byte[] b, int off, int len)
+ {
+ if (off < 0 || len < 0 || off + len > b.length)
+ throw new ArrayIndexOutOfBoundsException();
+
+ if (pos >= count)
+ return -1; // EOF
+
+ int numRead = Math.min(len, count - pos);
+ if (numRead < 0)
+ return 0;
+
+ buffer.getBytes(pos, pos + numRead, b, off);
+ pos += numRead;
+ return numRead;
+ }
+
+ public void reset()
+ {
+ pos = 0;
+ }
+
+ public long skip(long n)
+ {
+ if (n < 0)
+ return 0L;
+
+ long actualSkip = Math.min(n, count - pos);
+ pos += actualSkip;
+ return actualSkip;
+ }
+}
diff --git a/libjava/java/io/StringReader.java b/libjava/java/io/StringReader.java
new file mode 100644
index 0000000..08e8d0c
--- /dev/null
+++ b/libjava/java/io/StringReader.java
@@ -0,0 +1,139 @@
+/* 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 Warren Levy <warrenl@cygnus.com>
+ * @date October 19, 1998.
+ */
+/* 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
+ */
+
+public class StringReader extends Reader
+{
+ /* A String provided by the creator of the stream. */
+ private String buf;
+
+ /* Position of the next char in buf to be read. */
+ private int pos;
+
+ /* The currently marked position in the stream. */
+ private int markedPos;
+
+ /* The index in buf one greater than the last valid character. */
+ private int count;
+
+ public StringReader(String buffer)
+ {
+ super();
+ buf = buffer;
+
+ count = buffer.length();
+ markedPos = pos = 0;
+ }
+
+ public void close()
+ {
+ synchronized (lock)
+ {
+ buf = null;
+ }
+ }
+
+ public void mark(int readAheadLimit) throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException();
+
+ // readAheadLimit is ignored per Java Class Lib. book, p. 1692.
+ markedPos = pos;
+ }
+ }
+
+ public boolean markSupported()
+ {
+ return true;
+ }
+
+ public int read() throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException();
+
+ if (pos < count)
+ return ((int) buf.charAt(pos++)) & 0xFFFF;
+ return -1;
+ }
+ }
+
+ public int read(char[] b, int off, int len) throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException();
+
+ /* Don't need to check pos value, arraycopy will check it. */
+ if (off < 0 || len < 0 || off + len > b.length)
+ throw new ArrayIndexOutOfBoundsException();
+
+ if (pos >= count)
+ return -1;
+
+ int lastChar = Math.min(count, pos + len);
+ buf.getChars(pos, lastChar, b, off);
+ int numChars = lastChar - pos;
+ pos = lastChar;
+ return numChars;
+ }
+ }
+
+ public boolean ready() // TODO12: throws IOException
+ {
+ // TODO12: The JCL specifically says this returns true even if the
+ // reader has been closed, whereas the online 1.2 doc specifically
+ // says to throw an IOException if closed.
+ return true;
+ }
+
+ public void reset() throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException();
+
+ pos = markedPos;
+ }
+ }
+
+ public long skip(long n) throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException();
+
+ // Even though the var numChars is a long, in reality it can never
+ // be larger than an int since the result of subtracting 2 positive
+ // ints will always fit in an int. Since we have to return a long
+ // anyway, numChars might as well just be a long.
+ long numChars = Math.min((long) (count - pos), n < 0 ? 0L : n);
+ pos += numChars;
+ return numChars;
+ }
+ }
+}
diff --git a/libjava/java/io/StringWriter.java b/libjava/java/io/StringWriter.java
new file mode 100644
index 0000000..90ad9a9
--- /dev/null
+++ b/libjava/java/io/StringWriter.java
@@ -0,0 +1,80 @@
+// StringWriter.java - StringBuffer output 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 StringWriter extends Writer
+{
+ public void close ()
+ {
+ // JCL says this does nothing. This seems to violate the Writer
+ // contract, in that other methods should still throw and
+ // IOException after a close. Still, we just follow JCL.
+ }
+
+ public void flush ()
+ {
+ }
+
+ public StringBuffer getBuffer ()
+ {
+ return buffer;
+ }
+
+ public StringWriter ()
+ {
+ this (16);
+ }
+
+ protected StringWriter (int size)
+ {
+ super ();
+ buffer = new StringBuffer (size);
+ lock = buffer;
+ }
+
+ public String toString ()
+ {
+ return buffer.toString();
+ }
+
+ public void write (int oneChar)
+ {
+ buffer.append((char) oneChar);
+ }
+
+ public void write (char[] chars, int offset, int len)
+ {
+ buffer.append(chars, offset, len);
+ }
+
+ public void write (String str)
+ {
+ buffer.append(str);
+ }
+
+ public void write (String str, int offset, int len)
+ {
+ buffer.append(str.substring(offset, offset + len));
+ }
+
+ // The string buffer.
+ private StringBuffer buffer;
+}
diff --git a/libjava/java/io/SyncFailedException.java b/libjava/java/io/SyncFailedException.java
new file mode 100644
index 0000000..b920198
--- /dev/null
+++ b/libjava/java/io/SyncFailedException.java
@@ -0,0 +1,34 @@
+// SyncFailedException.java
+
+/* 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 24, 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 SyncFailedException extends IOException
+{
+ public SyncFailedException ()
+ {
+ super ();
+ }
+
+ public SyncFailedException (String s)
+ {
+ super (s);
+ }
+}
diff --git a/libjava/java/io/UTFDataFormatException.java b/libjava/java/io/UTFDataFormatException.java
new file mode 100644
index 0000000..aea3540
--- /dev/null
+++ b/libjava/java/io/UTFDataFormatException.java
@@ -0,0 +1,34 @@
+// UTFDataFormatException.java
+
+/* 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 24, 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 UTFDataFormatException extends IOException
+{
+ public UTFDataFormatException ()
+ {
+ super ();
+ }
+
+ public UTFDataFormatException (String s)
+ {
+ super (s);
+ }
+}
diff --git a/libjava/java/io/UnsupportedEncodingException.java b/libjava/java/io/UnsupportedEncodingException.java
new file mode 100644
index 0000000..f3c26f9
--- /dev/null
+++ b/libjava/java/io/UnsupportedEncodingException.java
@@ -0,0 +1,32 @@
+/* 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 Per Bothner <bothner@cygnus.com>
+ * @date April 17, 1998.
+ */
+
+/* Written using "Java Class Libraries", 2nd edition, plus online
+ * API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct.
+ */
+
+public class UnsupportedEncodingException extends IOException
+{
+ public UnsupportedEncodingException ()
+ {
+ super();
+ }
+
+ public UnsupportedEncodingException (String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/libjava/java/io/Writer.java b/libjava/java/io/Writer.java
new file mode 100644
index 0000000..48cedb6
--- /dev/null
+++ b/libjava/java/io/Writer.java
@@ -0,0 +1,67 @@
+/* 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 Per Bothner <bothner@cygnus.com>
+ * @date April 17, 1998.
+ */
+/* Written using "Java Class Libraries", 2nd edition, plus online
+ * API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct.
+ * However, write(String, int, int) should be made a native method.
+ */
+
+public abstract class Writer
+{
+ protected Object lock;
+
+ protected Writer ()
+ {
+ lock = this;
+ }
+
+ protected Writer (Object lock)
+ {
+ this.lock = lock;
+ }
+
+ abstract public void close() throws IOException;
+
+ abstract public void flush() throws IOException;
+
+ abstract public void write(char[] buf, int offset, int count)
+ throws IOException;
+
+ public void write(char[] buf) throws IOException
+ {
+ write(buf, 0, buf.length);
+ }
+
+ public void write(int ch) throws IOException
+ {
+ char[] buf = new char[1];
+ buf[0] = (char) ch;
+ write(buf, 0, 1);
+ }
+
+ // FIXME - re-write using native code to not require copied buffer.
+ public void write (String str, int offset, int count) throws IOException
+ {
+ char[] buf = new char[count];
+ str.getChars(offset, offset + count, buf, 0);
+ write(buf, 0, count);
+ }
+
+ public void write (String str) throws IOException
+ {
+ write(str, 0, str.length());
+ }
+
+}
diff --git a/libjava/java/io/natFile.cc b/libjava/java/io/natFile.cc
new file mode 100644
index 0000000..40f2277
--- /dev/null
+++ b/libjava/java/io/natFile.cc
@@ -0,0 +1,273 @@
+// natFile.cc - Native part of File class.
+
+/* 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. */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#ifdef HAVE_DIRENT_H
+#define _POSIX_PTHREAD_SEMANTICS
+#ifndef _REENTRANT
+# define _REENTRANT
+#endif
+#include <dirent.h>
+#endif
+#include <string.h>
+
+#include <cni.h>
+#include <jvm.h>
+#include <java/io/File.h>
+#include <java/io/IOException.h>
+#include <java/util/Vector.h>
+#include <java/lang/String.h>
+#include <java/io/FilenameFilter.h>
+#include <java/lang/System.h>
+
+jboolean
+java::io::File::access (jstring canon, jint query)
+{
+ if (! canon)
+ return false;
+ char buf[MAXPATHLEN];
+ jsize total = JvGetStringUTFRegion (canon, 0, canon->length(), buf);
+ // FIXME?
+ buf[total] = '\0';
+ JvAssert (query == READ || query == WRITE || query == EXISTS);
+#ifdef HAVE_ACCESS
+ int mode;
+ if (query == READ)
+ mode = R_OK;
+ else if (query == WRITE)
+ mode = W_OK;
+ else
+ mode = F_OK;
+ return ::access (buf, mode) == 0;
+#else
+ return false;
+#endif
+}
+
+jboolean
+java::io::File::stat (jstring canon, jint query)
+{
+ if (! canon)
+ return false;
+ char buf[MAXPATHLEN];
+ jsize total = JvGetStringUTFRegion (canon, 0, canon->length(), buf);
+ // FIXME?
+ buf[total] = '\0';
+
+#ifdef HAVE_STAT
+ struct stat sb;
+ if (::stat (buf, &sb))
+ return false;
+
+ JvAssert (query == DIRECTORY || query == ISFILE);
+ jboolean r = S_ISDIR (sb.st_mode);
+ return query == DIRECTORY ? r : ! r;
+#else
+ return false;
+#endif
+}
+
+jlong
+java::io::File::attr (jstring canon, jint query)
+{
+ if (! canon)
+ return false;
+
+ char buf[MAXPATHLEN];
+ jsize total = JvGetStringUTFRegion (canon, 0, canon->length(), buf);
+ // FIXME?
+ buf[total] = '\0';
+
+#ifdef HAVE_STAT
+ struct stat sb;
+ // FIXME: not sure about return value here.
+ if (::stat (buf, &sb))
+ return 0;
+
+ JvAssert (query == MODIFIED || query == LENGTH);
+ // FIXME: time computation is very POSIX-specific -- POSIX and Java
+ // have the same Epoch.
+ return query == MODIFIED ? sb.st_mtime * 1000 : sb.st_size;
+#else
+ // There's no good choice here.
+ return 23;
+#endif
+}
+
+jstring
+java::io::File::getCanonicalPath (void)
+{
+ char buf[MAXPATHLEN], buf2[MAXPATHLEN];
+ jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf);
+ // FIXME?
+ buf[total] = '\0';
+
+#ifdef HAVE_REALPATH
+ if (realpath (buf, buf2) == NULL)
+ _Jv_Throw (new IOException (JvNewStringLatin1 (strerror (errno))));
+
+ // FIXME: what encoding to assume for file names? This affects many
+ // calls.
+ return JvNewStringUTF (buf2);
+#else
+ return JvNewStringUTF (buf);
+#endif
+}
+
+jboolean
+java::io::File::isAbsolute (void)
+{
+ // FIXME: cpp define name.
+ // FIXME: cygwin.
+#ifdef WIN32
+ if (path->charAt(0) == '/' || path->charAt(0) == '\\')
+ return true;
+ if (path->length() < 3)
+ return false;
+ // Hard-code A-Za-z because Windows (I think) can't use non-ASCII
+ // letters as drive names.
+ if ((path->charAt(0) < 'a' || path->charAt(0) > 'z')
+ && (path->charAt(0) < 'A' || path->charAt(0) > 'Z'))
+ return false;
+ return (path->charAt(1) == ':'
+ && (path->charAt(2) == '/' || path->charAt(2) == '\\'));
+#else
+ return path->charAt(0) == '/';
+#endif
+}
+
+#ifdef HAVE_DIRENT_H
+#if defined(__JV_POSIX_THREADS__) && defined(HAVE_READDIR_R)
+
+static struct dirent *
+get_entry (DIR *dir, struct dirent *e)
+{
+ struct dirent *r;
+ if (readdir_r (dir, e, &r) || r == NULL)
+ return NULL;
+ return e;
+}
+
+#else /* defined(__JV_POSIX_THREADS__) && defined(HAVE_READDIR_R) */
+
+static struct dirent *
+get_entry (DIR *dir, struct dirent *)
+{
+ return readdir (dir);
+}
+
+#endif /* defined(__JV_POSIX_THREADS__) && defined(HAVE_READDIR_R) */
+#endif /* HAVE_DIRENT_H */
+
+jstringArray
+java::io::File::performList (jstring canon, FilenameFilter *filter)
+{
+ if (! canon)
+ return NULL;
+
+#ifdef HAVE_DIRENT_H
+ char buf[MAXPATHLEN];
+ jsize total = JvGetStringUTFRegion (canon, 0, canon->length(), buf);
+ // FIXME?
+ buf[total] = '\0';
+
+ DIR *dir = opendir (buf);
+ if (! dir)
+ return NULL;
+
+ java::util::Vector *vec = new java::util::Vector ();
+ struct dirent *d, d2;
+ while ((d = get_entry (dir, &d2)) != NULL)
+ {
+ if (! strcmp (d->d_name, ".") || ! strcmp (d->d_name, ".."))
+ continue;
+
+ jstring name = JvNewStringUTF (d->d_name);
+ if (filter && ! filter->accept(this, name))
+ continue;
+
+ vec->addElement(name);
+ }
+
+ closedir (dir);
+
+ jobjectArray ret = JvNewObjectArray (vec->size(), canon->getClass(),
+ NULL);
+ vec->copyInto(ret);
+ return reinterpret_cast<jstringArray> (ret);
+#else /* HAVE_DIRENT_H */
+ return NULL;
+#endif /* HAVE_DIRENT_H */
+}
+
+jboolean
+java::io::File::performMkdir (void)
+{
+ char buf[MAXPATHLEN];
+ jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf);
+ // FIXME?
+ buf[total] = '\0';
+
+#ifdef HAVE_MKDIR
+ // FIXME: mode.
+ return ::mkdir (buf, 0755) == 0;
+#else
+ return false;
+#endif
+}
+
+jboolean
+java::io::File::performRenameTo (File *dest)
+{
+ char buf[MAXPATHLEN];
+ jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf);
+ // FIXME?
+ buf[total] = '\0';
+ char buf2[MAXPATHLEN];
+ total = JvGetStringUTFRegion (dest->path, 0, dest->path->length(), buf2);
+ // FIXME?
+ buf2[total] = '\0';
+
+#ifdef HAVE_RENAME
+ return ::rename (buf, buf2) == 0;
+#else
+ return false;
+#endif
+}
+
+jboolean
+java::io::File::performDelete (jstring canon)
+{
+ char buf[MAXPATHLEN];
+ jsize total = JvGetStringUTFRegion (canon, 0, canon->length(), buf);
+ // FIXME?
+ buf[total] = '\0';
+
+#ifdef HAVE_UNLINK
+#ifdef HAVE_RMDIR
+ if (! ::rmdir (buf))
+ return true;
+#endif // HAVE_RMDIR
+ if (errno == ENOTDIR)
+ return ::unlink (buf) == 0;
+#endif // HAVE_UNLINK
+ return false;
+}
diff --git a/libjava/java/io/natFileDescriptorEcos.cc b/libjava/java/io/natFileDescriptorEcos.cc
new file mode 100644
index 0000000..f2c3fb0
--- /dev/null
+++ b/libjava/java/io/natFileDescriptorEcos.cc
@@ -0,0 +1,132 @@
+// natFileDescriptor.cc - Native part of FileDescriptor class.
+
+/* 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. */
+
+#include <config.h>
+
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#include <cni.h>
+#include <jvm.h>
+#include <java/io/FileDescriptor.h>
+#include <java/io/SyncFailedException.h>
+#include <java/io/IOException.h>
+#include <java/io/EOFException.h>
+#include <java/lang/ArrayIndexOutOfBoundsException.h>
+#include <java/lang/NullPointerException.h>
+#include <java/lang/String.h>
+#include <java/io/FileNotFoundException.h>
+
+extern "C" void diag_write_char (char c);
+
+static void
+diag_write (char *data, int len)
+{
+ while (len > 0)
+ {
+ diag_write_char (*data++);
+ len--;
+ }
+}
+
+#define NO_FSYNC_MESSAGE "sync unsupported"
+
+jboolean
+java::io::FileDescriptor::valid (void)
+{
+ return true;
+}
+
+void
+java::io::FileDescriptor::sync (void)
+{
+ // Some files don't support fsync. We don't bother reporting these
+ // as errors.
+#ifdef HAVE_FSYNC
+#else
+ JvThrow (new SyncFailedException (JvNewStringLatin1 (NO_FSYNC_MESSAGE)));
+#endif
+}
+
+jint
+java::io::FileDescriptor::open (jstring path, jint jflags)
+{
+ return fd;
+}
+
+void
+java::io::FileDescriptor::write (jint b)
+{
+ char d = (char) b;
+ ::diag_write (&d, 1);
+}
+
+void
+java::io::FileDescriptor::write (jbyteArray b, jint offset, jint len)
+{
+ if (! b)
+ JvThrow (new java::lang::NullPointerException);
+ if (offset < 0 || len < 0 || offset + len > JvGetArrayLength (b))
+ JvThrow (new java::lang::ArrayIndexOutOfBoundsException);
+ char *bytes = (char *)elements (b) + offset;
+ ::diag_write (bytes, len);
+}
+
+void
+java::io::FileDescriptor::close (void)
+{
+}
+
+jint
+java::io::FileDescriptor::seek (jlong pos, jint whence)
+{
+ JvAssert (whence == SET || whence == CUR);
+
+ jlong len = length ();
+ jlong here = getFilePointer ();
+
+ if ((whence == SET && pos > len) || (whence == CUR && here + pos > len))
+ JvThrow (new EOFException);
+
+ return 0;
+}
+
+jlong
+java::io::FileDescriptor::length (void)
+{
+ return 0;
+}
+
+jlong
+java::io::FileDescriptor::getFilePointer (void)
+{
+ return 0;
+}
+
+jint
+java::io::FileDescriptor::read (void)
+{
+ return 0;
+}
+
+jint
+java::io::FileDescriptor::read (jbyteArray buffer, jint offset, jint count)
+{
+ return 0;
+}
+
+jint
+java::io::FileDescriptor::available (void)
+{
+ return 0;
+}
diff --git a/libjava/java/io/natFileDescriptorPosix.cc b/libjava/java/io/natFileDescriptorPosix.cc
new file mode 100644
index 0000000..3efd8e4
--- /dev/null
+++ b/libjava/java/io/natFileDescriptorPosix.cc
@@ -0,0 +1,264 @@
+// natFileDescriptor.cc - Native part of FileDescriptor class.
+
+/* 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. */
+
+#include <config.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <fcntl.h>
+
+#ifdef HAVE_SYS_IOCTL_H
+#define BSD_COMP /* Get FIONREAD on Solaris2. */
+#include <sys/ioctl.h>
+#endif
+
+// Pick up FIONREAD on Solaris 2.5.
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
+
+#include <cni.h>
+#include <jvm.h>
+#include <java/io/FileDescriptor.h>
+#include <java/io/SyncFailedException.h>
+#include <java/io/IOException.h>
+#include <java/io/InterruptedIOException.h>
+#include <java/io/EOFException.h>
+#include <java/lang/ArrayIndexOutOfBoundsException.h>
+#include <java/lang/NullPointerException.h>
+#include <java/lang/String.h>
+#include <java/lang/Thread.h>
+#include <java/io/FileNotFoundException.h>
+
+#define NO_FSYNC_MESSAGE "sync unsupported"
+
+jboolean
+java::io::FileDescriptor::valid (void)
+{
+ struct stat sb;
+ return ::fstat (fd, &sb) == 0;
+}
+
+void
+java::io::FileDescriptor::sync (void)
+{
+ // Some files don't support fsync. We don't bother reporting these
+ // as errors.
+#ifdef HAVE_FSYNC
+ if (::fsync (fd) && errno != EROFS && errno != EINVAL)
+ JvThrow (new SyncFailedException (JvNewStringLatin1 (strerror (errno))));
+#else
+ JvThrow (new SyncFailedException (JvNewStringLatin1 (NO_FSYNC_MESSAGE)));
+#endif
+}
+
+jint
+java::io::FileDescriptor::open (jstring path, jint jflags)
+{
+ // FIXME: eww.
+ char buf[MAXPATHLEN];
+ jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf);
+ // FIXME?
+ buf[total] = '\0';
+ int flags = 0;
+#ifdef O_BINARY
+ flags |= O_BINARY;
+#endif
+
+ JvAssert ((jflags & READ) || (jflags & WRITE));
+ if ((jflags & READ) && (jflags & WRITE))
+ flags |= O_RDWR;
+ else if ((jflags & READ))
+ flags |= O_RDONLY;
+ else
+ {
+ flags |= O_WRONLY | O_CREAT;
+ if ((jflags & APPEND))
+ flags |= O_APPEND;
+ else
+ flags |= O_TRUNC;
+ }
+
+ // FIXME: mode?
+ int fd = ::open (buf, flags, 0755);
+ if (fd == -1)
+ {
+ char msg[MAXPATHLEN + 200];
+ sprintf (msg, "%s: %s", buf, strerror (errno));
+ JvThrow (new FileNotFoundException (JvNewStringLatin1 (msg)));
+ }
+ return fd;
+}
+
+void
+java::io::FileDescriptor::write (jint b)
+{
+ jbyte d = (jbyte) b;
+ int r = ::write (fd, &d, 1);
+ if (java::lang::Thread::interrupted())
+ {
+ InterruptedIOException *iioe
+ = new InterruptedIOException (JvNewStringLatin1 ("write interrupted"));
+ iioe->bytesTransferred = r == -1 ? 0 : r;
+ JvThrow (iioe);
+ }
+ else if (r == -1)
+ JvThrow (new IOException (JvNewStringLatin1 (strerror (errno))));
+ // FIXME: loop if r != 1.
+}
+
+void
+java::io::FileDescriptor::write (jbyteArray b, jint offset, jint len)
+{
+ if (! b)
+ JvThrow (new java::lang::NullPointerException);
+ if (offset < 0 || len < 0 || offset + len > JvGetArrayLength (b))
+ JvThrow (new java::lang::ArrayIndexOutOfBoundsException);
+ jbyte *bytes = elements (b) + offset;
+ int r = ::write (fd, bytes, len);
+ if (java::lang::Thread::interrupted())
+ {
+ InterruptedIOException *iioe
+ = new InterruptedIOException (JvNewStringLatin1 ("write interrupted"));
+ iioe->bytesTransferred = r == -1 ? 0 : r;
+ JvThrow (iioe);
+ }
+ else if (r == -1)
+ JvThrow (new IOException (JvNewStringLatin1 (strerror (errno))));
+ // FIXME: loop if r != len.
+}
+
+void
+java::io::FileDescriptor::close (void)
+{
+ jint save = fd;
+ fd = -1;
+ if (::close (save))
+ JvThrow (new IOException (JvNewStringLatin1 (strerror (errno))));
+}
+
+jint
+java::io::FileDescriptor::seek (jlong pos, jint whence)
+{
+ JvAssert (whence == SET || whence == CUR);
+
+ jlong len = length ();
+ jlong here = getFilePointer ();
+
+ if ((whence == SET && pos > len) || (whence == CUR && here + pos > len))
+ JvThrow (new EOFException);
+
+ off_t r = ::lseek (fd, (off_t) pos, whence == SET ? SEEK_SET : SEEK_CUR);
+ if (r == -1)
+ JvThrow (new IOException (JvNewStringLatin1 (strerror (errno))));
+ return r;
+}
+
+jlong
+java::io::FileDescriptor::length (void)
+{
+ struct stat sb;
+ if (::fstat (fd, &sb))
+ JvThrow (new IOException (JvNewStringLatin1 (strerror (errno))));
+ return sb.st_size;
+}
+
+jlong
+java::io::FileDescriptor::getFilePointer (void)
+{
+ off_t r = ::lseek (fd, 0, SEEK_CUR);
+ if (r == -1)
+ JvThrow (new IOException (JvNewStringLatin1 (strerror (errno))));
+ return r;
+}
+
+jint
+java::io::FileDescriptor::read (void)
+{
+ jbyte b;
+ int r = ::read (fd, &b, 1);
+ if (r == 0)
+ return -1;
+ if (java::lang::Thread::interrupted())
+ {
+ InterruptedIOException *iioe
+ = new InterruptedIOException (JvNewStringLatin1 ("read interrupted"));
+ iioe->bytesTransferred = r == -1 ? 0 : r;
+ JvThrow (iioe);
+ }
+ else if (r == -1)
+ JvThrow (new IOException (JvNewStringLatin1 (strerror (errno))));
+ return b & 0xFF;
+}
+
+jint
+java::io::FileDescriptor::read (jbyteArray buffer, jint offset, jint count)
+{
+ if (! buffer)
+ JvThrow (new java::lang::NullPointerException);
+ jsize bsize = JvGetArrayLength (buffer);
+ if (offset < 0 || count < 0 || offset + count > bsize)
+ JvThrow (new java::lang::ArrayIndexOutOfBoundsException);
+ jbyte *bytes = elements (buffer) + offset;
+ int r = ::read (fd, bytes, count);
+ if (r == 0)
+ return -1;
+ if (java::lang::Thread::interrupted())
+ {
+ InterruptedIOException *iioe
+ = new InterruptedIOException (JvNewStringLatin1 ("read interrupted"));
+ iioe->bytesTransferred = r == -1 ? 0 : r;
+ JvThrow (iioe);
+ }
+ else if (r == -1)
+ JvThrow (new IOException (JvNewStringLatin1 (strerror (errno))));
+ return r;
+}
+
+jint
+java::io::FileDescriptor::available (void)
+{
+#if defined (FIONREAD)
+ long num;
+ int r = ::ioctl (fd, FIONREAD, &num);
+ if (r == -1)
+ JvThrow (new IOException (JvNewStringLatin1 (strerror (errno))));
+ return (jint) num;
+#elif defined (HAVE_SELECT)
+ int r = -1;
+ if (fd < 0)
+ errno = EBADF;
+ else
+ {
+ fd_set rd;
+ FD_ZERO (&rd);
+ FD_SET (fd, &rd);
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ r = ::select (fd + 1, &rd, NULL, NULL, &tv);
+ }
+ if (r == -1)
+ JvThrow (new IOException (JvNewStringLatin1 (strerror (errno))));
+ return r == 0 ? 0 : 1;
+#else
+ JvThrow (new IOException (JvNewStringLatin1 ("unimplemented")));
+#endif
+}