--- old/src/java.base/share/classes/java/io/BufferedReader.java 2020-03-19 07:28:50.000000000 -0700 +++ new/src/java.base/share/classes/java/io/BufferedReader.java 2020-03-19 07:28:49.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -302,6 +302,8 @@ * (EOF). * * @param ignoreLF If true, the next '\n' will be skipped + * @param term Output: Whether a line terminator was encountered + * while reading the line; may be {@code null}. * * @return A String containing the contents of the line, not including * any line-termination characters, or null if the end of the @@ -311,13 +313,14 @@ * * @throws IOException If an I/O error occurs */ - String readLine(boolean ignoreLF) throws IOException { + String readLine(boolean ignoreLF, boolean[] term) throws IOException { StringBuilder s = null; int startChar; synchronized (lock) { ensureOpen(); boolean omitLF = ignoreLF || skipLF; + if (term != null) term[0] = false; bufferLoop: for (;;) { @@ -344,6 +347,7 @@ for (i = nextChar; i < nChars; i++) { c = cb[i]; if ((c == '\n') || (c == '\r')) { + if (term != null) term[0] = true; eol = true; break charLoop; } @@ -389,7 +393,7 @@ * @see java.nio.file.Files#readAllLines */ public String readLine() throws IOException { - return readLine(false); + return readLine(false, null); } /** --- old/src/java.base/share/classes/java/io/LineNumberReader.java 2020-03-19 07:28:51.000000000 -0700 +++ new/src/java.base/share/classes/java/io/LineNumberReader.java 2020-03-19 07:28:50.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ package java.io; - /** * A buffered character-input stream that keeps track of line numbers. This * class defines methods {@link #setLineNumber(int)} and {@link @@ -33,15 +32,17 @@ * respectively. * *
By default, line numbering begins at 0. This number increments at every - * line terminator as the data is read, and can be changed - * with a call to {@code setLineNumber(int)}. Note however, that - * {@code setLineNumber(int)} does not actually change the current position in - * the stream; it only changes the value that will be returned by + * line terminator as the data is read, and at the end of the + * stream if the last character in the stream is not a line terminator. This + * number can be changed with a call to {@code setLineNumber(int)}. Note + * however, that {@code setLineNumber(int)} does not actually change the current + * position in the stream; it only changes the value that will be returned by * {@code getLineNumber()}. * *
A line is considered to be terminated by any one of a
* line feed ('\n'), a carriage return ('\r'), or a carriage return followed
- * immediately by a linefeed.
+ * immediately by a linefeed, or any of the previous terminators followed by
+ * end of stream, or end of stream not preceded by another terminator.
*
* @author Mark Reinhold
* @since 1.1
@@ -49,6 +50,15 @@
public class LineNumberReader extends BufferedReader {
+ /** Previous character types */
+ private static final int NONE = 0; // no previous character
+ private static final int CHAR = 1; // non-line terminator
+ private static final int EOL = 2; // line terminator
+ private static final int EOF = 3; // end-of-file
+
+ /** The previous character type */
+ private int prevChar = NONE;
+
/** The current line number */
private int lineNumber = 0;
@@ -111,8 +121,10 @@
/**
* Read a single character. Line terminators are
- * compressed into single newline ('\n') characters. Whenever a line
- * terminator is read the current line number is incremented.
+ * compressed into single newline ('\n') characters. The current line
+ * number is incremented whenever a line terminator is read, or when the
+ * end of the stream is reached and the last character in the stream is
+ * not a line terminator.
*
* @return The character read, or -1 if the end of the stream has been
* reached
@@ -134,16 +146,26 @@
skipLF = true;
case '\n': /* Fall through */
lineNumber++;
+ prevChar = EOL;
return '\n';
+ case -1:
+ if (prevChar == CHAR)
+ lineNumber++;
+ prevChar = EOF;
+ break;
+ default:
+ prevChar = CHAR;
+ break;
}
return c;
}
}
/**
- * Read characters into a portion of an array. Whenever a line terminator is read the current line number is
- * incremented.
+ * Read characters into a portion of an array. The current line
+ * number is incremented whenever a line terminator is read, or when the
+ * end of the stream is reached and the last character in the stream is
+ * not a line terminator.
*
* @param cbuf
* Destination buffer
@@ -167,6 +189,13 @@
synchronized (lock) {
int n = super.read(cbuf, off, len);
+ if (n == -1) {
+ if (prevChar == CHAR)
+ lineNumber++;
+ prevChar = EOF;
+ return -1;
+ }
+
for (int i = off; i < off + n; i++) {
int c = cbuf[i];
if (skipLF) {
@@ -183,13 +212,26 @@
}
}
+ if (n > 0) {
+ switch ((int)cbuf[off + n - 1]) {
+ case '\r':
+ case '\n': /* Fall through */
+ prevChar = EOL;
+ break;
+ default:
+ prevChar = CHAR;
+ break;
+ }
+ }
+
return n;
}
}
/**
- * Read a line of text. Whenever a line terminator is
- * read the current line number is incremented.
+ * Read a line of text. The current line number is incremented whenever
+ * a line terminator is read, or when the end of the stream is reached and
+ * the last character in the stream is not a line terminator.
*
* @return A String containing the contents of the line, not including
* any line termination characters, or
@@ -200,10 +242,17 @@
*/
public String readLine() throws IOException {
synchronized (lock) {
- String l = super.readLine(skipLF);
+ boolean[] term = new boolean[1];
+ String l = super.readLine(skipLF, term);
skipLF = false;
- if (l != null)
+ if (l != null) {
lineNumber++;
+ prevChar = term[0] ? EOL : EOF;
+ } else { // l == null
+ if (prevChar == CHAR)
+ lineNumber++;
+ prevChar = EOF;
+ }
return l;
}
}
@@ -242,6 +291,9 @@
break;
r -= nc;
}
+ if (n - r > 0) {
+ prevChar = NONE;
+ }
return n - r;
}
}
--- old/test/jdk/java/io/LineNumberReader/Read.java 2020-03-19 07:28:51.000000000 -0700
+++ new/test/jdk/java/io/LineNumberReader/Read.java 2020-03-19 07:28:51.000000000 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -22,16 +22,24 @@
*/
/* @test
- @bug 4074875 4063511
+ @bug 4074875 4063511 8235792
@summary Make sure LineNumberReader.read(char, int , int) will increase
the linenumber correctly.
*/
-import java.io.*;
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.io.StringReader;
+import java.util.function.Consumer;
public class Read {
public static void main(String[] args) throws Exception {
+ testReadChars();
+ testEofs();
+ }
+
+ private static void testReadChars() throws Exception {
String s = "aaaa\nbbb\n";
char[] buf = new char[5];
int n = 0;
@@ -49,4 +57,49 @@
throw new Exception("Failed test: Expected line number: 2, got "
+ line);
}
+
+ private static void testEofs() throws Exception {
+ String string = "first \n second";
+
+ Consumer