2003-12-26 Guilhem Lavaux <guilhem@kaffe.org>
[official-gcc.git] / libjava / java / io / BufferedReader.java
blob46c9e417b1be9c5cae4ce61ceeed1c198ffb583c
1 /* BufferedReader.java
2 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
3 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING. If not, write to the
19 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307 USA.
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library. Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module. An independent module is a module which is not derived from
34 or based on this library. If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so. If you do not wish to do so, delete this
37 exception statement from your version. */
40 package java.io;
42 /* Written using "Java Class Libraries", 2nd edition, plus online
43 * API docs for JDK 1.2 beta from http://www.javasoft.com.
44 * Status: Believed complete and correct.
47 /**
48 * This subclass of <code>FilterReader</code> buffers input from an
49 * underlying implementation to provide a possibly more efficient read
50 * mechanism. It maintains the buffer and buffer state in instance
51 * variables that are available to subclasses. The default buffer size
52 * of 8192 chars can be overridden by the creator of the stream.
53 * <p>
54 * This class also implements mark/reset functionality. It is capable
55 * of remembering any number of input chars, to the limits of
56 * system memory or the size of <code>Integer.MAX_VALUE</code>
58 * @author Per Bothner <bothner@cygnus.com>
59 * @author Aaron M. Renn <arenn@urbanophile.com>
61 public class BufferedReader extends Reader
63 Reader in;
64 char[] buffer;
65 /* Index of current read position. Must be >= 0 and <= limit. */
66 /* There is a special case where pos may be equal to limit+1; this
67 * is used as an indicator that a readLine was done with a '\r' was
68 * the very last char in the buffer. Since we don't want to read-ahead
69 * and potentially block, we set pos this way to indicate the situation
70 * and deal with it later. Doing it this way rather than having a
71 * separate boolean field to indicate the condition has the advantage
72 * that it is self-clearing on things like mark/reset.
74 int pos;
75 /* Limit of valid data in buffer. Must be >= pos and <= buffer.length. */
76 /* This can be < pos in the one special case described above. */
77 int limit;
79 /* The value -1 means there is no mark, or the mark has been invalidated.
80 Otherwise, markPos is the index in the buffer of the marked position.
81 Must be >= 0 and <= pos.
82 Note we do not explicitly store the read-limit.
83 The implicit read-limit is (buffer.length - markPos), which is
84 guaranteed to be >= the read-limit requested in the call to mark. */
85 int markPos = -1;
87 // The JCL book specifies the default buffer size as 8K characters.
88 // This is package-private because it is used by LineNumberReader.
89 static final int DEFAULT_BUFFER_SIZE = 8192;
91 /**
92 * Create a new <code>BufferedReader</code> that will read from the
93 * specified subordinate stream with a default buffer size of 8192 chars.
95 * @param in The subordinate stream to read from
97 public BufferedReader(Reader in)
99 this(in, DEFAULT_BUFFER_SIZE);
103 * Create a new <code>BufferedReader</code> that will read from the
104 * specified subordinate stream with a buffer size that is specified by the
105 * caller.
107 * @param in The subordinate stream to read from
108 * @param size The buffer size to use
110 public BufferedReader(Reader in, int size)
112 super(in.lock);
113 this.in = in;
114 buffer = new char[size];
118 * This method closes the underlying stream and frees any associated
119 * resources.
121 * @exception IOException If an error occurs
123 public void close() throws IOException
125 synchronized (lock)
127 if (in != null)
128 in.close();
129 in = null;
130 buffer = null;
135 * Returns <code>true</code> to indicate that this class supports mark/reset
136 * functionality.
138 * @return <code>true</code>
140 public boolean markSupported()
142 return true;
146 * Mark a position in the input to which the stream can be
147 * "reset" by calling the <code>reset()</code> method. The parameter
148 * <code>readLimit</code> is the number of chars that can be read from the
149 * stream after setting the mark before the mark becomes invalid. For
150 * example, if <code>mark()</code> is called with a read limit of 10, then
151 * when 11 chars of data are read from the stream before the
152 * <code>reset()</code> method is called, then the mark is invalid and the
153 * stream object instance is not required to remember the mark.
154 * <p>
155 * Note that the number of chars that can be remembered by this method
156 * can be greater than the size of the internal read buffer. It is also
157 * not dependent on the subordinate stream supporting mark/reset
158 * functionality.
160 * @param readLimit The number of chars that can be read before the mark
161 * becomes invalid
163 * @exception IOException If an error occurs
165 public void mark(int readLimit) throws IOException
167 if (readLimit < 0)
168 throw new IllegalArgumentException();
170 synchronized (lock)
172 checkStatus();
173 // In this method we need to be aware of the special case where
174 // pos + 1 == limit. This indicates that a '\r' was the last char
175 // in the buffer during a readLine. We'll want to maintain that
176 // condition after we shift things around and if a larger buffer is
177 // needed to track readLimit, we'll have to make it one element
178 // larger to ensure we don't invalidate the mark too early, if the
179 // char following the '\r' is NOT a '\n'. This is ok because, per
180 // the spec, we are not required to invalidate when passing readLimit.
182 // Note that if 'pos > limit', then doing 'limit -= pos' will cause
183 // limit to be negative. This is the only way limit will be < 0.
185 if (pos + readLimit > limit)
187 char[] old_buffer = buffer;
188 int extraBuffSpace = 0;
189 if (pos > limit)
190 extraBuffSpace = 1;
191 if (readLimit + extraBuffSpace > limit)
192 buffer = new char[readLimit + extraBuffSpace];
193 limit -= pos;
194 if (limit >= 0)
196 System.arraycopy(old_buffer, pos, buffer, 0, limit);
197 pos = 0;
201 if (limit < 0)
203 // Maintain the relationship of 'pos > limit'.
204 pos = 1;
205 limit = markPos = 0;
207 else
208 markPos = pos;
209 // Now pos + readLimit <= buffer.length. thus if we need to read
210 // beyond buffer.length, then we are allowed to invalidate markPos.
215 * Reset the stream to the point where the <code>mark()</code> method
216 * was called. Any chars that were read after the mark point was set will
217 * be re-read during subsequent reads.
218 * <p>
219 * This method will throw an IOException if the number of chars read from
220 * the stream since the call to <code>mark()</code> exceeds the mark limit
221 * passed when establishing the mark.
223 * @exception IOException If an error occurs;
225 public void reset() throws IOException
227 synchronized (lock)
229 checkStatus();
230 if (markPos < 0)
231 throw new IOException("mark never set or invalidated");
233 // Need to handle the extremely unlikely case where a readLine was
234 // done with a '\r' as the last char in the buffer; which was then
235 // immediately followed by a mark and a reset with NO intervening
236 // read of any sort. In that case, setting pos to markPos would
237 // lose that info and a subsequent read would thus not skip a '\n'
238 // (if one exists). The value of limit in this rare case is zero.
239 // We can assume that if limit is zero for other reasons, then
240 // pos is already set to zero and doesn't need to be readjusted.
241 if (limit > 0)
242 pos = markPos;
247 * This method determines whether or not a stream is ready to be read. If
248 * this method returns <code>false</code> then this stream could (but is
249 * not guaranteed to) block on the next read attempt.
251 * @return <code>true</code> if this stream is ready to be read,
252 * <code>false</code> otherwise
254 * @exception IOException If an error occurs
256 public boolean ready() throws IOException
258 synchronized (lock)
260 checkStatus();
261 return pos < limit || in.ready();
266 * This method read chars from a stream and stores them into a caller
267 * supplied buffer. It starts storing the data at index
268 * <code>offset</code> into
269 * the buffer and attempts to read <code>len</code> chars. This method can
270 * return before reading the number of chars requested. The actual number
271 * of chars read is returned as an int. A -1 is returned to indicate the
272 * end of the stream.
273 * <p>
274 * This method will block until some data can be read.
276 * @param buf The array into which the chars read should be stored
277 * @param offset The offset into the array to start storing chars
278 * @param count The requested number of chars to read
280 * @return The actual number of chars read, or -1 if end of stream.
282 * @exception IOException If an error occurs.
284 public int read(char[] buf, int offset, int count) throws IOException
286 synchronized (lock)
288 checkStatus();
289 // Once again, we need to handle the special case of a readLine
290 // that has a '\r' at the end of the buffer. In this case, we'll
291 // need to skip a '\n' if it is the next char to be read.
292 // This special case is indicated by 'pos > limit'.
293 boolean retAtEndOfBuffer = false;
295 int avail = limit - pos;
296 if (count > avail)
298 if (avail > 0)
299 count = avail;
300 else // pos >= limit
302 if (limit == buffer.length)
303 markPos = -1; // read too far - invalidate the mark.
304 if (pos > limit)
306 // Set a boolean and make pos == limit to simplify things.
307 retAtEndOfBuffer = true;
308 --pos;
310 if (markPos < 0)
312 // Optimization: can read directly into buf.
313 if (count >= buffer.length && !retAtEndOfBuffer)
314 return in.read(buf, offset, count);
315 pos = limit = 0;
317 avail = in.read(buffer, limit, buffer.length - limit);
318 if (retAtEndOfBuffer && avail > 0 && buffer[limit] == '\n')
320 --avail;
321 limit++;
323 if (avail < count)
325 if (avail <= 0)
326 return avail;
327 count = avail;
329 limit += avail;
332 System.arraycopy(buffer, pos, buf, offset, count);
333 pos += count;
334 return count;
338 /* Read more data into the buffer. Update pos and limit appropriately.
339 Assumes pos==limit initially. May invalidate the mark if read too much.
340 Return number of chars read (never 0), or -1 on eof. */
341 private int fill() throws IOException
343 checkStatus();
344 // Handle the special case of a readLine that has a '\r' at the end of
345 // the buffer. In this case, we'll need to skip a '\n' if it is the
346 // next char to be read. This special case is indicated by 'pos > limit'.
347 boolean retAtEndOfBuffer = false;
348 if (pos > limit)
350 retAtEndOfBuffer = true;
351 --pos;
354 if (markPos >= 0 && limit == buffer.length)
355 markPos = -1;
356 if (markPos < 0)
357 pos = limit = 0;
358 int count = in.read(buffer, limit, buffer.length - limit);
359 if (count > 0)
360 limit += count;
362 if (retAtEndOfBuffer && buffer[pos] == '\n')
364 --count;
365 // If the mark was set to the location of the \n, then we
366 // must change it to fully pretend that the \n does not
367 // exist.
368 if (markPos == pos)
369 ++markPos;
370 ++pos;
373 return count;
376 public int read() throws IOException
378 synchronized (lock)
380 checkStatus();
381 if (pos >= limit && fill () <= 0)
382 return -1;
383 return buffer[pos++];
387 /* Return the end of the line starting at this.pos and ending at limit.
388 * The index returns is *before* any line terminators, or limit
389 * if no line terminators were found.
391 private int lineEnd(int limit)
393 int i = pos;
394 for (; i < limit; i++)
396 char ch = buffer[i];
397 if (ch == '\n' || ch == '\r')
398 break;
400 return i;
404 * This method reads a single line of text from the input stream, returning
405 * it as a <code>String</code>. A line is terminated by "\n", a "\r", or
406 * an "\r\n" sequence. The system dependent line separator is not used.
407 * The line termination characters are not returned in the resulting
408 * <code>String</code>.
410 * @return The line of text read, or <code>null</code> if end of stream.
412 * @exception IOException If an error occurs
414 public String readLine() throws IOException
416 checkStatus();
417 // Handle the special case where a previous readLine (with no intervening
418 // reads/skips) had a '\r' at the end of the buffer.
419 // In this case, we'll need to skip a '\n' if it's the next char to be read.
420 // This special case is indicated by 'pos > limit'.
421 if (pos > limit)
423 int ch = read();
424 if (ch < 0)
425 return null;
426 if (ch != '\n')
427 --pos;
429 int i = lineEnd(limit);
430 if (i < limit)
432 String str = new String(buffer, pos, i - pos);
433 pos = i + 1;
434 // If the last char in the buffer is a '\r', we must remember
435 // to check if the next char to be read after the buffer is refilled
436 // is a '\n'. If so, skip it. To indicate this condition, we set pos
437 // to be limit + 1, which normally is never possible.
438 if (buffer[i] == '\r')
439 if (pos == limit || buffer[pos] == '\n')
440 pos++;
441 return str;
443 StringBuffer sbuf = new StringBuffer(200);
444 sbuf.append(buffer, pos, i - pos);
445 pos = i;
446 // We only want to return null when no characters were read before
447 // EOF. So we must keep track of this separately. Otherwise we
448 // would treat an empty `sbuf' as an EOF condition, which is wrong
449 // when there is just a newline.
450 boolean eof = false;
451 for (;;)
453 int ch = read();
454 if (ch < 0)
456 eof = true;
457 break;
459 if (ch == '\n' || ch == '\r')
461 // Check here if a '\r' was the last char in the buffer; if so,
462 // mark it as in the comment above to indicate future reads
463 // should skip a newline that is the next char read after
464 // refilling the buffer.
465 if (ch == '\r')
466 if (pos == limit || buffer[pos] == '\n')
467 pos++;
468 break;
470 i = lineEnd(limit);
471 sbuf.append(buffer, pos - 1, i - (pos - 1));
472 pos = i;
474 return (sbuf.length() == 0 && eof) ? null : sbuf.toString();
478 * This method skips the specified number of chars in the stream. It
479 * returns the actual number of chars skipped, which may be less than the
480 * requested amount.
481 * <p>
482 * This method first discards chars in the buffer, then calls the
483 * <code>skip</code> method on the underlying stream to skip the
484 * remaining chars.
486 * @param numChars The requested number of chars to skip
488 * @return The actual number of chars skipped.
490 * @exception IOException If an error occurs
492 public long skip(long count) throws IOException
494 synchronized (lock)
496 checkStatus();
497 if (count <= 0)
498 return 0;
499 // Yet again, we need to handle the special case of a readLine
500 // that has a '\r' at the end of the buffer. In this case, we need
501 // to ignore a '\n' if it is the next char to be read.
502 // This special case is indicated by 'pos > limit' (i.e. avail < 0).
503 // To simplify things, if we're dealing with the special case for
504 // readLine, just read the next char (since the fill method will
505 // skip the '\n' for us). By doing this, we'll have to back up pos.
506 // That's easier than trying to keep track of whether we've skipped
507 // one element or not.
508 int ch;
509 if (pos > limit)
510 if ((ch = read()) < 0)
511 return 0;
512 else
513 --pos;
515 int avail = limit - pos;
517 if (count < avail)
519 pos += count;
520 return count;
523 pos = limit;
524 long todo = count - avail;
525 if (todo > buffer.length)
527 markPos = -1;
528 todo -= in.skip(todo);
530 else
532 while (todo > 0)
534 avail = fill();
535 if (avail <= 0)
536 break;
537 if (avail > todo)
538 avail = (int) todo;
539 pos += avail;
540 todo -= avail;
543 return count - todo;
547 private void checkStatus() throws IOException
549 if (in == null)
550 throw new IOException("Stream closed");