Frames | No Frames |
1: /* LineNumberInputStream.java -- An input stream which counts line numbers 2: Copyright (C) 1998, 1999, 2002, 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package java.io; 40: 41: /** 42: * This class functions like a standard <code>InputStream</code> 43: * except that it counts line numbers, and canonicalizes newline 44: * characters. As data is read, whenever the byte sequences "\r", 45: * "\n", or "\r\n" are encountered, the running line count is 46: * incremeted by one. Additionally, the whatever line termination 47: * sequence was encountered will be converted to a "\n" byte. Note 48: * that this class numbers lines from 0. When the first line 49: * terminator is encountered, the line number is incremented to 1, and 50: * so on. 51: * <p> 52: * This class counts only line termination characters. If the last line 53: * read from the stream does not end in a line termination sequence, it 54: * will not be counted as a line. 55: * <p> 56: * Note that since this class operates as a filter on an underlying 57: * stream, it has the same mark/reset functionality as the underlying 58: * stream. The <code>mark()</code> and <code>reset()</code> methods 59: * in this class handle line numbers correctly. Calling 60: * <code>reset()</code> resets the line number to the point at which 61: * <code>mark()</code> was called if the subordinate stream supports 62: * that functionality. 63: * <p> 64: * @deprecated This class is deprecated in favor if 65: * <code>LineNumberReader</code> because it operates on ASCII bytes 66: * instead of an encoded character stream. This class is for backward 67: * compatibility only and should not be used in new applications. 68: * 69: * @author Aaron M. Renn (arenn@urbanophile.com) 70: * @author Warren Levy (warrenl@cygnus.com) 71: */ 72: public class LineNumberInputStream extends FilterInputStream 73: { 74: /** The current line number. */ 75: private int lineNumber = 0; 76: 77: /** The line number when the stream was marked. */ 78: private int markLineNumber = 0; 79: 80: /** Flag to indicate a '\r' was just read so that an immediately 81: * subsequent '\n' can be ignored. */ 82: private boolean justReadReturnChar = false; 83: 84: /** 85: * Create a new <code>LineNumberInputStream</code> that reads from the 86: * specified subordinate <code>InputStream</code> 87: * 88: * @param in The subordinate <code>InputStream</code> to read from 89: */ 90: public LineNumberInputStream(InputStream in) 91: { 92: super(in); 93: } 94: 95: /** 96: * This method returns the number of bytes that can be read from the 97: * stream before the stream can block. This method is tricky 98: * because the subordinate <code>InputStream</code> might return 99: * only "\r\n" characters, which are replaced by a single "\n" 100: * character by the <code>read()</code> method of this class. So 101: * this method can only guarantee that <code>in.available() / 102: * 2</code> bytes can actually be read before blocking. In 103: * practice, considerably more bytes might be read before blocking 104: * <p> 105: * Note that the stream may not block if additional bytes beyond the count 106: * returned by this method are read. 107: * 108: * @return The number of bytes that can be read before blocking could occur 109: * 110: * @exception IOException If an error occurs 111: */ 112: public int available() throws IOException 113: { 114: // We can only guarantee half the characters that might be available 115: // without blocking because "\r\n" is treated as a single character. 116: return in.available() / 2; 117: } 118: 119: /** 120: * This method returns the current line number 121: * 122: * @return The current line number 123: */ 124: public int getLineNumber() 125: { 126: return lineNumber; 127: } 128: 129: /** 130: * This method marks a position in the input to which the stream can 131: * be "reset" byte calling the <code>reset()</code> method. The 132: * parameter <code>readlimit</code> is the number of bytes that can 133: * be read from the stream after setting the mark before the mark 134: * becomes invalid. For example, if <code>mark()</code> is called 135: * with a read limit of 10, then when 11 bytes of data are read from 136: * the stream before the <code>reset()</code> method is called, then 137: * the mark is invalid and the stream object instance is not 138: * required to remember the mark. 139: * <p> 140: * In this class, this method will remember the current line number 141: * as well as the current position in the stream. When the 142: * <code>reset()</code> method is called, the line number will be 143: * restored to the saved line number in addition to the stream 144: * position. 145: * <p> 146: * This method only works if the subordinate stream supports mark/reset 147: * functionality. 148: * 149: * @param readlimit The number of bytes that can be read before the 150: * mark becomes invalid 151: */ 152: public void mark(int readlimit) 153: { 154: in.mark(readlimit); 155: markLineNumber = lineNumber; 156: } 157: 158: /** 159: * This method reads an unsigned byte from the input stream and returns it 160: * as an int in the range of 0-255. This method will return -1 if the 161: * end of the stream has been reached. 162: * <p> 163: * Note that if a line termination sequence is encountered (ie, "\r", 164: * "\n", or "\r\n") then that line termination sequence is converted to 165: * a single "\n" value which is returned from this method. This means 166: * that it is possible this method reads two bytes from the subordinate 167: * stream instead of just one. 168: * <p> 169: * Note that this method will block until a byte of data is available 170: * to be read. 171: * 172: * @return The byte read or -1 if end of stream 173: * 174: * @exception IOException If an error occurs 175: */ 176: public int read() throws IOException 177: { 178: // Treat "\r\n" as a single character. A '\r' may have been read by 179: // a previous call to read so we keep an internal flag to avoid having 180: // to read ahead. 181: 182: int ch = in.read(); 183: 184: if (ch == '\n') 185: if (justReadReturnChar) 186: { 187: ch = in.read(); 188: justReadReturnChar = false; 189: } 190: else 191: lineNumber++; 192: else if (ch == '\r') 193: { 194: ch = '\n'; 195: justReadReturnChar = true; 196: lineNumber++; 197: } 198: else 199: justReadReturnChar = false; 200: 201: return ch; 202: } 203: 204: /** 205: * This method reads bytes from a stream and stores them into a caller 206: * supplied buffer. It starts storing data at index <code>offset</code> into 207: * the buffer and attemps to read <code>len</code> bytes. This method can 208: * return before reading the number of bytes requested. The actual number 209: * of bytes read is returned as an int. A -1 is returned to indicated the 210: * end of the stream. 211: * <p> 212: * This method will block until some data can be read. 213: * <p> 214: * Note that if a line termination sequence is encountered (ie, "\r", 215: * "\n", or "\r\n") then that line termination sequence is converted to 216: * a single "\n" value which is stored in the buffer. Only a single 217: * byte is counted towards the number of bytes read in this case. 218: * 219: * @param b The array into which the bytes read should be stored 220: * @param off The offset into the array to start storing bytes 221: * @param len The requested number of bytes to read 222: * 223: * @return The actual number of bytes read, or -1 if end of stream 224: * 225: * @exception IOException If an error occurs. 226: */ 227: public int read(byte[] b, int off, int len) throws IOException 228: { 229: if (off < 0 || len < 0 || off + len > b.length) 230: throw new ArrayIndexOutOfBoundsException(); 231: 232: // This case always succeeds. 233: if (len == 0) 234: return 0; 235: 236: // The simplest, though not necessarily the most time efficient thing 237: // to do is simply call read(void) len times. Since this is a deprecated 238: // class, that should be ok. 239: final int origOff = off; 240: while (len-- > 0) 241: { 242: int ch = read(); 243: if (ch < 0) 244: break; 245: 246: b[off++] = (byte) ch; 247: } 248: 249: // This is safe since we already know that some bytes were 250: // actually requested. 251: return off == origOff ? -1 : off - origOff; 252: } 253: 254: /** 255: * This method resets a stream to the point where the 256: * <code>mark()</code> method was called. Any bytes that were read 257: * after the mark point was set will be re-read during subsequent 258: * reads. 259: * <p> 260: * In this class, this method will also restore the line number that was 261: * current when the <code>mark()</code> method was called. 262: * <p> 263: * This method only works if the subordinate stream supports mark/reset 264: * functionality. 265: * 266: * @exception IOException If an error occurs 267: */ 268: public void reset() throws IOException 269: { 270: in.reset(); 271: lineNumber = markLineNumber; 272: justReadReturnChar = false; 273: } 274: 275: /** 276: * This method sets the current line number to the specified value. 277: * 278: * @param lineNumber The new line number 279: */ 280: public void setLineNumber(int lineNumber) 281: { 282: this.lineNumber = lineNumber; 283: } 284: 285: /** 286: * This method skips up to the requested number of bytes in the 287: * input stream. The actual number of bytes skipped is returned. If the 288: * desired number of bytes to skip is negative, no bytes are skipped. 289: * 290: * @param n requested number of bytes to skip. 291: * 292: * @return The actual number of bytes skipped. 293: * 294: * @exception IOException If an error occurs. 295: */ 296: public long skip(long n) throws IOException 297: { 298: if (n <= 0) 299: return 0L; 300: 301: final long origN = n; 302: 303: do 304: { 305: int ch = read(); 306: if (ch < 0) 307: break; 308: if (ch == '\n' || ch == '\r') 309: lineNumber++; 310: } 311: while (--n > 0); 312: 313: return origN - n; 314: } 315: }