rt/emul/compact/src/main/java/java/io/LineNumberReader.java
author Jaroslav Tulach <jtulach@netbeans.org>
Thu, 03 Oct 2013 15:40:35 +0200
branchjdk7-b147
changeset 1334 588d5bf7a560
permissions -rw-r--r--
Set of JDK classes needed to run javac
     1 /*
     2  * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    25 
    26 package java.io;
    27 
    28 
    29 /**
    30  * A buffered character-input stream that keeps track of line numbers.  This
    31  * class defines methods {@link #setLineNumber(int)} and {@link
    32  * #getLineNumber()} for setting and getting the current line number
    33  * respectively.
    34  *
    35  * <p> By default, line numbering begins at 0. This number increments at every
    36  * <a href="#lt">line terminator</a> as the data is read, and can be changed
    37  * with a call to <tt>setLineNumber(int)</tt>.  Note however, that
    38  * <tt>setLineNumber(int)</tt> does not actually change the current position in
    39  * the stream; it only changes the value that will be returned by
    40  * <tt>getLineNumber()</tt>.
    41  *
    42  * <p> A line is considered to be <a name="lt">terminated</a> by any one of a
    43  * line feed ('\n'), a carriage return ('\r'), or a carriage return followed
    44  * immediately by a linefeed.
    45  *
    46  * @author      Mark Reinhold
    47  * @since       JDK1.1
    48  */
    49 
    50 public class LineNumberReader extends BufferedReader {
    51 
    52     /** The current line number */
    53     private int lineNumber = 0;
    54 
    55     /** The line number of the mark, if any */
    56     private int markedLineNumber; // Defaults to 0
    57 
    58     /** If the next character is a line feed, skip it */
    59     private boolean skipLF;
    60 
    61     /** The skipLF flag when the mark was set */
    62     private boolean markedSkipLF;
    63 
    64     /**
    65      * Create a new line-numbering reader, using the default input-buffer
    66      * size.
    67      *
    68      * @param  in
    69      *         A Reader object to provide the underlying stream
    70      */
    71     public LineNumberReader(Reader in) {
    72         super(in);
    73     }
    74 
    75     /**
    76      * Create a new line-numbering reader, reading characters into a buffer of
    77      * the given size.
    78      *
    79      * @param  in
    80      *         A Reader object to provide the underlying stream
    81      *
    82      * @param  sz
    83      *         An int specifying the size of the buffer
    84      */
    85     public LineNumberReader(Reader in, int sz) {
    86         super(in, sz);
    87     }
    88 
    89     /**
    90      * Set the current line number.
    91      *
    92      * @param  lineNumber
    93      *         An int specifying the line number
    94      *
    95      * @see #getLineNumber
    96      */
    97     public void setLineNumber(int lineNumber) {
    98         this.lineNumber = lineNumber;
    99     }
   100 
   101     /**
   102      * Get the current line number.
   103      *
   104      * @return  The current line number
   105      *
   106      * @see #setLineNumber
   107      */
   108     public int getLineNumber() {
   109         return lineNumber;
   110     }
   111 
   112     /**
   113      * Read a single character.  <a href="#lt">Line terminators</a> are
   114      * compressed into single newline ('\n') characters.  Whenever a line
   115      * terminator is read the current line number is incremented.
   116      *
   117      * @return  The character read, or -1 if the end of the stream has been
   118      *          reached
   119      *
   120      * @throws  IOException
   121      *          If an I/O error occurs
   122      */
   123     public int read() throws IOException {
   124         synchronized (lock) {
   125             int c = super.read();
   126             if (skipLF) {
   127                 if (c == '\n')
   128                     c = super.read();
   129                 skipLF = false;
   130             }
   131             switch (c) {
   132             case '\r':
   133                 skipLF = true;
   134             case '\n':          /* Fall through */
   135                 lineNumber++;
   136                 return '\n';
   137             }
   138             return c;
   139         }
   140     }
   141 
   142     /**
   143      * Read characters into a portion of an array.  Whenever a <a
   144      * href="#lt">line terminator</a> is read the current line number is
   145      * incremented.
   146      *
   147      * @param  cbuf
   148      *         Destination buffer
   149      *
   150      * @param  off
   151      *         Offset at which to start storing characters
   152      *
   153      * @param  len
   154      *         Maximum number of characters to read
   155      *
   156      * @return  The number of bytes read, or -1 if the end of the stream has
   157      *          already been reached
   158      *
   159      * @throws  IOException
   160      *          If an I/O error occurs
   161      */
   162     public int read(char cbuf[], int off, int len) throws IOException {
   163         synchronized (lock) {
   164             int n = super.read(cbuf, off, len);
   165 
   166             for (int i = off; i < off + n; i++) {
   167                 int c = cbuf[i];
   168                 if (skipLF) {
   169                     skipLF = false;
   170                     if (c == '\n')
   171                         continue;
   172                 }
   173                 switch (c) {
   174                 case '\r':
   175                     skipLF = true;
   176                 case '\n':      /* Fall through */
   177                     lineNumber++;
   178                     break;
   179                 }
   180             }
   181 
   182             return n;
   183         }
   184     }
   185 
   186     /**
   187      * Read a line of text.  Whenever a <a href="#lt">line terminator</a> is
   188      * read the current line number is incremented.
   189      *
   190      * @return  A String containing the contents of the line, not including
   191      *          any <a href="#lt">line termination characters</a>, or
   192      *          <tt>null</tt> if the end of the stream has been reached
   193      *
   194      * @throws  IOException
   195      *          If an I/O error occurs
   196      */
   197     public String readLine() throws IOException {
   198         synchronized (lock) {
   199             String l = super.readLine(skipLF);
   200             skipLF = false;
   201             if (l != null)
   202                 lineNumber++;
   203             return l;
   204         }
   205     }
   206 
   207     /** Maximum skip-buffer size */
   208     private static final int maxSkipBufferSize = 8192;
   209 
   210     /** Skip buffer, null until allocated */
   211     private char skipBuffer[] = null;
   212 
   213     /**
   214      * Skip characters.
   215      *
   216      * @param  n
   217      *         The number of characters to skip
   218      *
   219      * @return  The number of characters actually skipped
   220      *
   221      * @throws  IOException
   222      *          If an I/O error occurs
   223      *
   224      * @throws  IllegalArgumentException
   225      *          If <tt>n</tt> is negative
   226      */
   227     public long skip(long n) throws IOException {
   228         if (n < 0)
   229             throw new IllegalArgumentException("skip() value is negative");
   230         int nn = (int) Math.min(n, maxSkipBufferSize);
   231         synchronized (lock) {
   232             if ((skipBuffer == null) || (skipBuffer.length < nn))
   233                 skipBuffer = new char[nn];
   234             long r = n;
   235             while (r > 0) {
   236                 int nc = read(skipBuffer, 0, (int) Math.min(r, nn));
   237                 if (nc == -1)
   238                     break;
   239                 r -= nc;
   240             }
   241             return n - r;
   242         }
   243     }
   244 
   245     /**
   246      * Mark the present position in the stream.  Subsequent calls to reset()
   247      * will attempt to reposition the stream to this point, and will also reset
   248      * the line number appropriately.
   249      *
   250      * @param  readAheadLimit
   251      *         Limit on the number of characters that may be read while still
   252      *         preserving the mark.  After reading this many characters,
   253      *         attempting to reset the stream may fail.
   254      *
   255      * @throws  IOException
   256      *          If an I/O error occurs
   257      */
   258     public void mark(int readAheadLimit) throws IOException {
   259         synchronized (lock) {
   260             super.mark(readAheadLimit);
   261             markedLineNumber = lineNumber;
   262             markedSkipLF     = skipLF;
   263         }
   264     }
   265 
   266     /**
   267      * Reset the stream to the most recent mark.
   268      *
   269      * @throws  IOException
   270      *          If the stream has not been marked, or if the mark has been
   271      *          invalidated
   272      */
   273     public void reset() throws IOException {
   274         synchronized (lock) {
   275             super.reset();
   276             lineNumber = markedLineNumber;
   277             skipLF     = markedSkipLF;
   278         }
   279     }
   280 
   281 }