diff options
Diffstat (limited to 'libjava/java/io')
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 +} |