| 1 | /* Copyright (C) 1998, 1999, 2001 Free Software Foundation
|
|---|
| 2 |
|
|---|
| 3 | This file is part of libgcj.
|
|---|
| 4 |
|
|---|
| 5 | This software is copyrighted work licensed under the terms of the
|
|---|
| 6 | Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
|
|---|
| 7 | details. */
|
|---|
| 8 |
|
|---|
| 9 | package java.io;
|
|---|
| 10 |
|
|---|
| 11 | /**
|
|---|
| 12 | * @author Per Bothner <[email protected]>
|
|---|
| 13 | * @date April 22, 1998.
|
|---|
| 14 | */
|
|---|
| 15 | /* Written using "Java Class Libraries", 2nd edition, plus online
|
|---|
| 16 | * API docs for JDK 1.2 beta from http://www.javasoft.com.
|
|---|
| 17 | * Status: Believed complete and correct.
|
|---|
| 18 | *
|
|---|
| 19 | * This implementation has the feature that if '\r' is read, it
|
|---|
| 20 | * does not look for a '\n', but immediately returns '\n'.
|
|---|
| 21 | * On the next read(), if a '\n' is read, it is skipped.
|
|---|
| 22 | * This has the advantage that we do not read (and hang) unnecessarily.
|
|---|
| 23 | *
|
|---|
| 24 | * This implementation is also minimal in the number of fields it uses.
|
|---|
| 25 | */
|
|---|
| 26 |
|
|---|
| 27 | public class LineNumberReader extends BufferedReader
|
|---|
| 28 | {
|
|---|
| 29 | /** The current line number. */
|
|---|
| 30 | int lineNumber;
|
|---|
| 31 |
|
|---|
| 32 | public LineNumberReader(Reader in)
|
|---|
| 33 | {
|
|---|
| 34 | super(in, 8192);
|
|---|
| 35 | }
|
|---|
| 36 |
|
|---|
| 37 | public LineNumberReader(Reader in, int size)
|
|---|
| 38 | {
|
|---|
| 39 | super(in, size);
|
|---|
| 40 | }
|
|---|
| 41 |
|
|---|
| 42 | public int getLineNumber()
|
|---|
| 43 | {
|
|---|
| 44 | return lineNumber;
|
|---|
| 45 | }
|
|---|
| 46 |
|
|---|
| 47 | public void setLineNumber(int lineNumber)
|
|---|
| 48 | {
|
|---|
| 49 | this.lineNumber = lineNumber;
|
|---|
| 50 | }
|
|---|
| 51 |
|
|---|
| 52 | private static int countLines (char[] buffer, int off, int len)
|
|---|
| 53 | {
|
|---|
| 54 | int count = 0;
|
|---|
| 55 | char prev = '\0';
|
|---|
| 56 | for (int i = 0; i < len; i++)
|
|---|
| 57 | {
|
|---|
| 58 | char ch = buffer[i+off];
|
|---|
| 59 | if ((ch == '\n' && prev != '\r') || ch == '\r')
|
|---|
| 60 | count++;
|
|---|
| 61 | prev = ch;
|
|---|
| 62 | }
|
|---|
| 63 | return count;
|
|---|
| 64 | }
|
|---|
| 65 |
|
|---|
| 66 | public void mark(int readLimit) throws IOException
|
|---|
| 67 | {
|
|---|
| 68 | synchronized (lock)
|
|---|
| 69 | {
|
|---|
| 70 | // This is basically the same as BufferedReader.mark.
|
|---|
| 71 | // However, if the previous character was a '\r', we need to
|
|---|
| 72 | // save that 'r', in case the next character is a '\n'.
|
|---|
| 73 | if (pos + readLimit > limit)
|
|---|
| 74 | {
|
|---|
| 75 | int saveCR = (pos > 0 && buffer[pos-1] == '\r') ? 1 : 0;
|
|---|
| 76 | char[] old_buffer = buffer;
|
|---|
| 77 | if (readLimit > limit)
|
|---|
| 78 | buffer = new char[saveCR + readLimit];
|
|---|
| 79 | int copy_start = pos - saveCR;
|
|---|
| 80 | limit -= copy_start;
|
|---|
| 81 | System.arraycopy(old_buffer, copy_start, buffer, 0, limit);
|
|---|
| 82 | pos = saveCR;
|
|---|
| 83 | }
|
|---|
| 84 | markPos = pos;
|
|---|
| 85 | }
|
|---|
| 86 | }
|
|---|
| 87 |
|
|---|
| 88 | public void reset() throws IOException
|
|---|
| 89 | {
|
|---|
| 90 | synchronized (lock)
|
|---|
| 91 | {
|
|---|
| 92 | if (markPos < 0)
|
|---|
| 93 | throw new IOException("mark never set or invalidated");
|
|---|
| 94 | if (markPos > 0 && pos > markPos && buffer[markPos-1] == '\r'
|
|---|
| 95 | && buffer[markPos] == '\n')
|
|---|
| 96 | lineNumber--;
|
|---|
| 97 | lineNumber -= countLines(buffer, markPos, pos - markPos);
|
|---|
| 98 | pos = markPos;
|
|---|
| 99 | }
|
|---|
| 100 | }
|
|---|
| 101 |
|
|---|
| 102 | public int read() throws IOException
|
|---|
| 103 | {
|
|---|
| 104 | synchronized (lock)
|
|---|
| 105 | {
|
|---|
| 106 | skipRedundantLF();
|
|---|
| 107 | if (pos >= limit)
|
|---|
| 108 | {
|
|---|
| 109 | if (markPos >= 0 && limit == buffer.length)
|
|---|
| 110 | markPos = -1;
|
|---|
| 111 | if (markPos <= 0)
|
|---|
| 112 | pos = limit = 0;
|
|---|
| 113 | int count = in.read(buffer, limit, buffer.length - limit);
|
|---|
| 114 | if (count <= 0)
|
|---|
| 115 | return -1;
|
|---|
| 116 | limit += count;
|
|---|
| 117 | }
|
|---|
| 118 | char ch = buffer[pos++];
|
|---|
| 119 | if (ch == '\r' || ch == '\n')
|
|---|
| 120 | {
|
|---|
| 121 | lineNumber++;
|
|---|
| 122 | return '\n';
|
|---|
| 123 | }
|
|---|
| 124 | return (int) ch;
|
|---|
| 125 | }
|
|---|
| 126 | }
|
|---|
| 127 |
|
|---|
| 128 | public int read(char[] buf, int offset, int count) throws IOException
|
|---|
| 129 | {
|
|---|
| 130 | if (count <= 0)
|
|---|
| 131 | {
|
|---|
| 132 | if (count < 0)
|
|---|
| 133 | throw new IndexOutOfBoundsException();
|
|---|
| 134 | return 0;
|
|---|
| 135 | }
|
|---|
| 136 | synchronized (lock)
|
|---|
| 137 | {
|
|---|
| 138 | int first = read();
|
|---|
| 139 | if (first < 0)
|
|---|
| 140 | return -1;
|
|---|
| 141 | int start_offset = offset;
|
|---|
| 142 | buf[offset++] = (char) first;
|
|---|
| 143 | if (buffer[pos-1] == '\r' && pos < limit && buffer[pos] == '\n')
|
|---|
| 144 | pos++;
|
|---|
| 145 | count--;
|
|---|
| 146 | while (count-- > 0 && pos < limit)
|
|---|
| 147 | {
|
|---|
| 148 | char ch = buffer[pos++];
|
|---|
| 149 | if (ch == '\r')
|
|---|
| 150 | {
|
|---|
| 151 | lineNumber++;
|
|---|
| 152 | ch = '\n';
|
|---|
| 153 | if (pos < limit && buffer[pos] == '\n')
|
|---|
| 154 | pos++;
|
|---|
| 155 | }
|
|---|
| 156 | else if (ch == '\n')
|
|---|
| 157 | lineNumber++;
|
|---|
| 158 | buf[offset++] = ch;
|
|---|
| 159 | }
|
|---|
| 160 | return offset - start_offset;
|
|---|
| 161 | }
|
|---|
| 162 | }
|
|---|
| 163 |
|
|---|
| 164 | private void skipRedundantLF() throws IOException
|
|---|
| 165 | {
|
|---|
| 166 | if (pos > 0 && buffer[pos-1] == '\r')
|
|---|
| 167 | {
|
|---|
| 168 | if (pos < limit)
|
|---|
| 169 | { // fast case
|
|---|
| 170 | if (buffer[pos] == '\n')
|
|---|
| 171 | pos++;
|
|---|
| 172 | }
|
|---|
| 173 | else
|
|---|
| 174 | { // use read() to deal with the general case.
|
|---|
| 175 | // Set pos and limit to zero to avoid infinite recursion in read.
|
|---|
| 176 | // May need to invalidate markPos if we've exceeded the buffer.
|
|---|
| 177 | if (pos >= buffer.length)
|
|---|
| 178 | markPos = -1;
|
|---|
| 179 | pos = limit = 0;
|
|---|
| 180 | int ch = read();
|
|---|
| 181 | if (ch >= 0 && ch != '\n')
|
|---|
| 182 | pos--;
|
|---|
| 183 | }
|
|---|
| 184 | }
|
|---|
| 185 | }
|
|---|
| 186 |
|
|---|
| 187 | public String readLine() throws IOException
|
|---|
| 188 | {
|
|---|
| 189 | // BufferedReader.readLine already does this. Shouldn't need to keep
|
|---|
| 190 | // track of newlines (since the read method deals with this for us).
|
|---|
| 191 | // But if the buffer is large, we may not call the read method at all
|
|---|
| 192 | // and super.readLine can't increment lineNumber itself.
|
|---|
| 193 | // Though it may seem kludgy, the safest thing to do is to save off
|
|---|
| 194 | // lineNumber and increment it explicitly when we're done (iff we
|
|---|
| 195 | // ended with a '\n' or '\r' as opposed to EOF).
|
|---|
| 196 | //
|
|---|
| 197 | // Also, we need to undo the special casing done by BufferedReader.readLine
|
|---|
| 198 | // when a '\r' is the last char in the buffer. That situation is marked
|
|---|
| 199 | // by 'pos > limit'.
|
|---|
| 200 | int tmpLineNumber = lineNumber;
|
|---|
| 201 | skipRedundantLF();
|
|---|
| 202 | String str = super.readLine();
|
|---|
| 203 | if (pos > limit)
|
|---|
| 204 | --pos;
|
|---|
| 205 |
|
|---|
| 206 | int ch;
|
|---|
| 207 | if (pos > 0 && ((ch = buffer[pos - 1]) == '\n' || ch == '\r'))
|
|---|
| 208 | lineNumber = tmpLineNumber + 1;
|
|---|
| 209 |
|
|---|
| 210 | return str;
|
|---|
| 211 | }
|
|---|
| 212 |
|
|---|
| 213 | public long skip(long count) throws IOException
|
|---|
| 214 | {
|
|---|
| 215 | if (count <= 0)
|
|---|
| 216 | return 0;
|
|---|
| 217 | long to_do = count;
|
|---|
| 218 | do
|
|---|
| 219 | {
|
|---|
| 220 | int ch = read();
|
|---|
| 221 | if (ch < 0)
|
|---|
| 222 | break;
|
|---|
| 223 | to_do--;
|
|---|
| 224 | if (ch == '\n' || ch == '\r')
|
|---|
| 225 | lineNumber++;
|
|---|
| 226 | else
|
|---|
| 227 | {
|
|---|
| 228 | long fence = pos + to_do;
|
|---|
| 229 | if (limit < fence)
|
|---|
| 230 | fence = limit;
|
|---|
| 231 | int end = pos;
|
|---|
| 232 | for (; end < fence; end++)
|
|---|
| 233 | {
|
|---|
| 234 | char endch = buffer[end];
|
|---|
| 235 | if (endch == '\n' || endch == '\r')
|
|---|
| 236 | break;
|
|---|
| 237 | }
|
|---|
| 238 | to_do -= end - pos;
|
|---|
| 239 | pos = end;
|
|---|
| 240 | }
|
|---|
| 241 | }
|
|---|
| 242 | while (to_do > 0);
|
|---|
| 243 | return count - to_do;
|
|---|
| 244 | }
|
|---|
| 245 | }
|
|---|