/[classpath]/classpath/java/io/PushbackReader.java
ViewVC logotype

Diff of /classpath/java/io/PushbackReader.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.8 by mark, Tue Jan 22 22:26:59 2002 UTC revision 1.9 by bryce, Mon Mar 25 01:11:08 2002 UTC
# Line 39  exception statement from your version. * Line 39  exception statement from your version. *
39  package java.io;  package java.io;
40    
41  /**  /**
42    * This subclass of <code>FilterReader</code> provides the ability to   * This subclass of <code>FilterReader</code> provides the ability to
43    * unread data from a stream.  It maintains an internal buffer of unread   * unread data from a stream.  It maintains an internal buffer of unread
44    * data that is supplied to the next read operation.  This is conceptually   * data that is supplied to the next read operation.  This is conceptually
45    * similar to mark/reset functionality, except that in this case the   * similar to mark/reset functionality, except that in this case the
46    * position to reset the stream to does not need to be known in advance.   * position to reset the stream to does not need to be known in advance.
47    * <p>   * <p>
48    * The default pushback buffer size one char, but this can be overridden   * The default pushback buffer size one char, but this can be overridden
49    * by the creator of the stream.   * by the creator of the stream.
50    *   *
51    * @version 0.0   * @version 0.0
52    *   *
53    * @author Aaron M. Renn (arenn@urbanophile.com)   * @author Aaron M. Renn (arenn@urbanophile.com)
54    * @author Warren Levy <warrenl@cygnus.com>   * @author Warren Levy <warrenl@cygnus.com>
   */  
 public class PushbackReader extends FilterReader  
 {  
   
 /*************************************************************************/  
   
 /*  
  * Class Variables  
  */  
   
 /**  
   * This is the default buffer size  
   */  
 private static final int DEFAULT_BUFFER_SIZE = 1;  
   
 /*************************************************************************/  
   
 /*  
  * Instance Variables  
  */  
   
 /**  
   * This is the buffer that is used to store the pushed back data  
   */  
 private char[] buf;  
   
 /**  
   * This is the position in the buffer from which the next char will be  
   * read.  Bytes are stored in reverse order in the buffer, starting from  
   * <code>buf[buf.length - 1]</code> to <code>buf[0]</code>.  Thus when  
   * <code>pos</code> is 0 the buffer is full and <code>buf.length</code> when  
   * it is empty  
   */  
 private int pos;  
   
 /*************************************************************************/  
   
 /*  
  * Constructors  
  */  
   
 /**  
   * This method initializes a <code>PushbackReader</code> to read from the  
   * specified subordinate <code>Reader</code> with a default pushback buffer  
   * size of 1.  
   *  
   * @code in The subordinate stream to read from  
   */  
 public  
 PushbackReader(Reader in)  
 {  
   this(in, DEFAULT_BUFFER_SIZE);  
 }  
   
 /*************************************************************************/  
   
 /**  
   * This method initializes a <code>PushbackReader</code> to read from the  
   * specified subordinate <code>Reader</code> with the specified buffer  
   * size  
   *  
   * @param in The subordinate <code>Reader</code> to read from  
   * @param bufsize The pushback buffer size to use  
   */  
 public  
 PushbackReader(Reader in, int bufsize)  
 {  
   super(in);  
   
   if (bufsize < 0)  
     throw new IllegalArgumentException("buffer size must be positive");  
   
   buf = new char[bufsize];  
   pos = bufsize;  
 }  
   
 /*************************************************************************/  
   
 /*  
  * Instance Methods  
55   */   */
56    public class PushbackReader extends FilterReader
 /**  
   * This method closes the stream and frees any associated resources.  
   *  
   * @exception IOException If an error occurs.  
   */  
 public void  
 close() throws IOException  
 {  
   synchronized (lock)  
     {  
       buf = null;  
       super.close();  
     }  
 }  
   
 /*************************************************************************/  
   
 /**  
   * This method throws an exception when called since this class does  
   * not support mark/reset.  
   *  
   * @param read_limit Not used.  
   *  
   * @exception IOException Always thrown to indicate mark/reset not supported.  
   */  
 public void  
 mark(int read_limit) throws IOException  
 {  
   throw new IOException("mark not supported in this class");  
 }  
   
 /*************************************************************************/  
   
 /**  
   * This method returns <code>false</code> to indicate that it does not support  
   * mark/reset functionality.  
   *  
   * @return This method returns <code>false</code> to indicate that this class does not support mark/reset functionality  
   *  
   */  
 public boolean  
 markSupported()  
 {  
   return(false);  
 }  
   
 /*************************************************************************/  
   
 /**  
   * This method always throws an IOException in this class because  
   * mark/reset functionality is not supported.  
   *  
   * @exception IOException Always thrown for this class  
   */  
 public void  
 reset() throws IOException  
 {  
   throw new IOException("reset not supported in this class");  
 }  
   
 /*************************************************************************/  
   
 /**  
   * This method determines whether or not this stream is ready to be read.  
   * If it returns <code>false</code> to indicate that the stream is not  
   * ready, any attempt to read from the stream could (but is not  
   * guaranteed to) block.  
   * <p>  
   * This stream is ready to read if there are either chars waiting to be  
   * read in the pushback buffer or if the underlying stream is ready to  
   * be read.  
   *  
   * @return <code>true</code> if this stream is ready to be read, <code>false</code> otherwise  
   *  
   * @exception IOException If an error occurs  
   */  
 public boolean  
 ready() throws IOException  
 {  
   synchronized (lock)  
     {  
       if (buf == null)  
         throw new IOException ("stream closed");  
   
       if (((buf.length - pos) > 0) || super.ready())  
         return(true);  
       else  
         return(false);  
     }  
 }  
   
 /*************************************************************************/  
   
 // Don't delete this method just because the spec says it shouldn't be there!  
 // See the CVS log for details.  
 /**  
   * This method skips the specified number of chars in the stream.  It  
   * returns the actual number of chars skipped, which may be less than the  
   * requested amount.  
   * <p>  
   * This method first discards chars from the buffer, then calls the  
   * <code>skip</code> method on the underlying <code>Reader</code> to  
   * skip additional chars if necessary.  
   *  
   * @param num_chars The requested number of chars to skip  
   *  
   * @return The actual number of chars skipped.  
   *  
   * @exception IOException If an error occurs  
   */  
 public long  
 skip(long num_chars) throws IOException  
 {  
   synchronized (lock)  
     {  
       if (num_chars <= 0)  
         return(0);  
   
       if ((buf.length - pos) >= num_chars)  
         {  
           pos += num_chars;  
           return(num_chars);  
         }  
   
       int chars_discarded = buf.length - pos;  
       pos = buf.length;  
   
       long chars_skipped = in.skip(num_chars - chars_discarded);  
   
       return(chars_discarded + chars_skipped);  
     } // synchronized  
 }  
   
 /*************************************************************************/  
   
 /**  
   * This method reads an unsigned char from the input stream and returns it  
   * as an int in the range of 0-65535.  This method also will return -1 if  
   * the end of the stream has been reached.  The char returned will be read  
   * from the pushback buffer, unless the buffer is empty, in which case  
   * the char will be read from the underlying stream.  
   * <p>  
   * This method will block until the char can be read.  
   *  
   * @return The char read or -1 if end of stream  
   *  
   * @exception IOException If an error occurs  
   */  
 public int  
 read() throws IOException  
 {  
   synchronized (lock)  
     {  
       if (buf == null)  
         throw new IOException("stream closed");  
   
       if (pos == buf.length)  
         return(super.read());  
   
       ++pos;  
       return((buf[pos - 1] & 0xFFFF));  
     }  
 }  
   
 /*************************************************************************/  
   
 /**  
   * This method read chars from a stream and stores them into a caller  
   * supplied buffer.  It starts storing the data at index <code>offset</code> into  
   * the buffer and attempts to read <code>len</code> chars.  This method can  
   * return before reading the number of chars requested.  The actual number  
   * of chars read is returned as an int.  A -1 is returned to indicate the  
   * end of the stream.  
   *  <p>  
   * This method will block until some data can be read.  
   * <p>  
   * This method first reads chars from the pushback buffer in order to  
   * satisfy the read request.  If the pushback buffer cannot provide all  
   * of the chars requested, the remaining chars are read from the  
   * underlying stream.  
   *  
   * @param buf The array into which the chars read should be stored  
   * @param offset The offset into the array to start storing chars  
   * @param len The requested number of chars to read  
   *  
   * @return The actual number of chars read, or -1 if end of stream.  
   *  
   * @exception IOException If an error occurs.  
   */  
 public synchronized int  
 read(char[] b, int offset, int len) throws IOException  
 {  
   synchronized (lock)  
     {  
       if (buf == null)  
         throw new IOException("stream closed");  
   
       if (offset < 0 || len < 0 || offset + len > b.length)  
         throw new ArrayIndexOutOfBoundsException();  
   
       int numBytes = Math.min(buf.length - pos, len);  
       if (numBytes > 0)  
         {  
           System.arraycopy (buf, pos, b, offset, numBytes);  
           pos += numBytes;  
           return numBytes;  
         }  
   
       return super.read(b, offset, len);  
     }  
 }  
   
 /*************************************************************************/  
   
 /**  
   * This method pushes a single char of data into the pushback buffer.  
   * The char pushed back is the one that will be returned as the first char  
   * of the next read.  
   * <p>  
   * If the pushback buffer is full, this method throws an exception.  
   * <p>  
   * The argument to this method is an <code>int</code>.  Only the low eight bits  
   * of this value are pushed back.  
   *  
   * @param b The char to be pushed back, passed as an int  
   *  
   * @exception IOException If the pushback buffer is full.  
   */  
 public void  
 unread(int b) throws IOException  
 {  
   synchronized (lock)  
     {  
       if (buf == null)  
         throw new IOException("stream closed");  
       if (pos == 0)  
         throw new IOException("Pushback buffer is full");  
   
       --pos;  
       buf[pos] = (char)(b & 0xFFFF);  
     } // synchronized  
 }  
   
 /*************************************************************************/  
   
 /**  
   * This method pushes all of the chars in the passed char array into  
   * the pushback buffer.  These chars are pushed in reverse order so that  
   * the next char read from the stream after this operation will be  
   * <code>buf[0]</code> followed by <code>buf[1]</code>, etc.  
   * <p>  
   * If the pushback buffer cannot hold all of the requested chars, an  
   * exception is thrown.  
   *  
   * @param buf The char array to be pushed back  
   *  
   * @exception IOException If the pushback buffer is full  
   */  
 public synchronized void  
 unread(char[] buf) throws IOException  
 {  
   unread(buf, 0, buf.length);  
 }  
   
 /*************************************************************************/  
   
 /**  
   * This method pushed back chars from the passed in array into the pushback  
   * buffer.  The chars from <code>buf[offset]</code> to <code>buf[offset + len]</code>  
   * are pushed in reverse order so that the next char read from the stream  
   * after this operation will be <code>buf[offset]</code> followed by  
   * <code>buf[offset + 1]</code>, etc.  
   * <p>  
   * If the pushback buffer cannot hold all of the requested chars, an  
   * exception is thrown.  
   *  
   * @param buf The char array to be pushed back  
   * @param offset The index into the array where the chars to be push start  
   * @param len The number of chars to be pushed.  
   *  
   * @exception IOException If the pushback buffer is full  
   */  
 public synchronized void  
 unread(char[] b, int offset, int len) throws IOException  
57  {  {
58    synchronized (lock)    /**
59      {     * This is the default buffer size
60        if (buf == null)     */
61          throw new IOException("stream closed");    private static final int DEFAULT_BUFFER_SIZE = 1;
62        if (pos < len)  
63          throw new IOException("Pushback buffer is full");    /**
64       * This is the buffer that is used to store the pushed back data
65        // Note the order that these chars are being added is the opposite     */
66        // of what would be done if they were added to the buffer one at a time.    private char[] buf;
67        // See the Java Class Libraries book p. 1397.  
68        System.arraycopy(b, offset, buf, pos - len, len);    /**
69       * This is the position in the buffer from which the next char will be
70        // Don't put this into the arraycopy above, an exception might be thrown     * read.  Bytes are stored in reverse order in the buffer, starting from
71        // and in that case we don't want to modify pos.     * <code>buf[buf.length - 1]</code> to <code>buf[0]</code>.  Thus when
72        pos -= len;     * <code>pos</code> is 0 the buffer is full and <code>buf.length</code> when
73      }     * it is empty
74       */
75      private int pos;
76    
77      /**
78       * This method initializes a <code>PushbackReader</code> to read from the
79       * specified subordinate <code>Reader</code> with a default pushback buffer
80       * size of 1.
81       *
82       * @code in The subordinate stream to read from
83       */
84      public PushbackReader(Reader in)
85      {
86        this(in, DEFAULT_BUFFER_SIZE);
87      }
88    
89      /**
90       * This method initializes a <code>PushbackReader</code> to read from the
91       * specified subordinate <code>Reader</code> with the specified buffer
92       * size
93       *
94       * @param in The subordinate <code>Reader</code> to read from
95       * @param bufsize The pushback buffer size to use
96       */
97      public PushbackReader(Reader in, int bufsize)
98      {
99        super(in);
100    
101        if (bufsize < 0)
102          throw new IllegalArgumentException("buffer size must be positive");
103    
104        buf = new char[bufsize];
105        pos = bufsize;
106      }
107    
108      /**
109       * This method closes the stream and frees any associated resources.
110       *
111       * @exception IOException If an error occurs.
112       */
113      public void close() throws IOException
114      {
115        synchronized (lock)
116          {
117            buf = null;
118            super.close();
119          }
120      }
121    
122      /**
123       * This method throws an exception when called since this class does
124       * not support mark/reset.
125       *
126       * @param read_limit Not used.
127       *
128       * @exception IOException Always thrown to indicate mark/reset not supported.
129       */
130      public void mark(int read_limit) throws IOException
131      {
132        throw new IOException("mark not supported in this class");
133      }
134    
135      /**
136       * This method returns <code>false</code> to indicate that it does not support
137       * mark/reset functionality.
138       *
139       * @return This method returns <code>false</code> to indicate that this class does not support mark/reset functionality
140       *
141       */
142      public boolean markSupported()
143      {
144        return(false);
145      }
146    
147      /**
148       * This method always throws an IOException in this class because
149       * mark/reset functionality is not supported.
150       *
151       * @exception IOException Always thrown for this class
152       */
153      public void reset() throws IOException
154      {
155        throw new IOException("reset not supported in this class");
156      }
157    
158      /**
159       * This method determines whether or not this stream is ready to be read.
160       * If it returns <code>false</code> to indicate that the stream is not
161       * ready, any attempt to read from the stream could (but is not
162       * guaranteed to) block.
163       * <p>
164       * This stream is ready to read if there are either chars waiting to be
165       * read in the pushback buffer or if the underlying stream is ready to
166       * be read.
167       *
168       * @return <code>true</code> if this stream is ready to be read, <code>false</code> otherwise
169       *
170       * @exception IOException If an error occurs
171       */
172      public boolean ready() throws IOException
173      {
174        synchronized (lock)
175          {
176            if (buf == null)
177              throw new IOException ("stream closed");
178    
179            if (((buf.length - pos) > 0) || super.ready())
180              return(true);
181            else
182              return(false);
183          }
184      }
185    
186      // Don't delete this method just because the spec says it shouldn't be there!
187      // See the CVS log for details.
188      /**
189        * This method skips the specified number of chars in the stream.  It
190        * returns the actual number of chars skipped, which may be less than the
191        * requested amount.
192        * <p>
193        * This method first discards chars from the buffer, then calls the
194        * <code>skip</code> method on the underlying <code>Reader</code> to
195        * skip additional chars if necessary.
196        *
197        * @param num_chars The requested number of chars to skip
198        *
199        * @return The actual number of chars skipped.
200        *
201        * @exception IOException If an error occurs
202        */
203      public long skip(long num_chars) throws IOException
204      {
205        synchronized (lock)
206          {
207            if (num_chars <= 0)
208              return(0);
209    
210            if ((buf.length - pos) >= num_chars)
211              {
212                pos += num_chars;
213                return(num_chars);
214              }
215    
216            int chars_discarded = buf.length - pos;
217            pos = buf.length;
218    
219            long chars_skipped = in.skip(num_chars - chars_discarded);
220    
221            return(chars_discarded + chars_skipped);
222          }
223      }
224    
225      /**
226       * This method reads an unsigned char from the input stream and returns it
227       * as an int in the range of 0-65535.  This method also will return -1 if
228       * the end of the stream has been reached.  The char returned will be read
229       * from the pushback buffer, unless the buffer is empty, in which case
230       * the char will be read from the underlying stream.
231       * <p>
232       * This method will block until the char can be read.
233       *
234       * @return The char read or -1 if end of stream
235       *
236       * @exception IOException If an error occurs
237       */
238      public int read() throws IOException
239      {
240        synchronized (lock)
241          {
242            if (buf == null)
243              throw new IOException("stream closed");
244    
245            if (pos == buf.length)
246              return(super.read());
247    
248            ++pos;
249            return((buf[pos - 1] & 0xFFFF));
250          }
251      }
252    
253      /**
254       * This method read chars from a stream and stores them into a caller
255       * supplied buffer.  It starts storing the data at index <code>offset</code> into
256       * the buffer and attempts to read <code>len</code> chars.  This method can
257       * return before reading the number of chars requested.  The actual number
258       * of chars read is returned as an int.  A -1 is returned to indicate the
259       * end of the stream.
260       *  <p>
261       * This method will block until some data can be read.
262       * <p>
263       * This method first reads chars from the pushback buffer in order to
264       * satisfy the read request.  If the pushback buffer cannot provide all
265       * of the chars requested, the remaining chars are read from the
266       * underlying stream.
267       *
268       * @param buf The array into which the chars read should be stored
269       * @param offset The offset into the array to start storing chars
270       * @param len The requested number of chars to read
271       *
272       * @return The actual number of chars read, or -1 if end of stream.
273       *
274       * @exception IOException If an error occurs.
275       */
276      public synchronized int read(char[] b, int offset, int len) throws IOException
277      {
278        synchronized (lock)
279          {
280            if (buf == null)
281              throw new IOException("stream closed");
282    
283            if (offset < 0 || len < 0 || offset + len > b.length)
284              throw new ArrayIndexOutOfBoundsException();
285    
286            int numBytes = Math.min(buf.length - pos, len);
287            if (numBytes > 0)
288              {
289                System.arraycopy (buf, pos, b, offset, numBytes);
290                pos += numBytes;
291                return numBytes;
292              }
293    
294            return super.read(b, offset, len);
295          }
296      }
297    
298      /**
299       * This method pushes a single char of data into the pushback buffer.
300       * The char pushed back is the one that will be returned as the first char
301       * of the next read.
302       * <p>
303       * If the pushback buffer is full, this method throws an exception.
304       * <p>
305       * The argument to this method is an <code>int</code>.  Only the low eight bits
306       * of this value are pushed back.
307       *
308       * @param b The char to be pushed back, passed as an int
309       *
310       * @exception IOException If the pushback buffer is full.
311       */
312      public void unread(int b) throws IOException
313      {
314        synchronized (lock)
315          {
316            if (buf == null)
317              throw new IOException("stream closed");
318            if (pos == 0)
319              throw new IOException("Pushback buffer is full");
320    
321            --pos;
322            buf[pos] = (char)(b & 0xFFFF);
323          }
324      }
325    
326      /**
327       * This method pushes all of the chars in the passed char array into
328       * the pushback buffer.  These chars are pushed in reverse order so that
329       * the next char read from the stream after this operation will be
330       * <code>buf[0]</code> followed by <code>buf[1]</code>, etc.
331       * <p>
332       * If the pushback buffer cannot hold all of the requested chars, an
333       * exception is thrown.
334       *
335       * @param buf The char array to be pushed back
336       *
337       * @exception IOException If the pushback buffer is full
338       */
339      public synchronized void unread(char[] buf) throws IOException
340      {
341        unread(buf, 0, buf.length);
342      }
343    
344      /**
345       * This method pushed back chars from the passed in array into the pushback
346       * buffer.  The chars from <code>buf[offset]</code> to <code>buf[offset + len]</code>
347       * are pushed in reverse order so that the next char read from the stream
348       * after this operation will be <code>buf[offset]</code> followed by
349       * <code>buf[offset + 1]</code>, etc.
350       * <p>
351       * If the pushback buffer cannot hold all of the requested chars, an
352       * exception is thrown.
353       *
354       * @param buf The char array to be pushed back
355       * @param offset The index into the array where the chars to be push start
356       * @param len The number of chars to be pushed.
357       *
358       * @exception IOException If the pushback buffer is full
359       */
360      public synchronized void unread(char[] b, int offset, int len)
361        throws IOException
362      {
363        synchronized (lock)
364          {
365            if (buf == null)
366              throw new IOException("stream closed");
367            if (pos < len)
368              throw new IOException("Pushback buffer is full");
369    
370            // Note the order that these chars are being added is the opposite
371            // of what would be done if they were added to the buffer one at a time.
372            // See the Java Class Libraries book p. 1397.
373            System.arraycopy(b, offset, buf, pos - len, len);
374    
375            // Don't put this into the arraycopy above, an exception might be thrown
376            // and in that case we don't want to modify pos.
377            pos -= len;
378          }
379      }
380  }  }
   
 } // class PushbackReader  

Legend:
Removed from v.1.8  
changed lines
  Added in v.1.9

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26