summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/library/scala/io/BufferedSource.scala59
-rw-r--r--test/files/run/bug4671.check46
-rw-r--r--test/files/run/bug4671.scala13
3 files changed, 108 insertions, 10 deletions
diff --git a/src/library/scala/io/BufferedSource.scala b/src/library/scala/io/BufferedSource.scala
index 60d67a0b58..b5144a891f 100644
--- a/src/library/scala/io/BufferedSource.scala
+++ b/src/library/scala/io/BufferedSource.scala
@@ -8,7 +8,7 @@
package scala.io
-import java.io.{ InputStream, BufferedReader, InputStreamReader }
+import java.io.{ InputStream, BufferedReader, InputStreamReader, PushbackReader }
import Source.DefaultBufSize
import scala.collection.Iterator
@@ -22,20 +22,59 @@ class BufferedSource(inputStream: InputStream, bufferSize: Int)(implicit val cod
def reader() = new InputStreamReader(inputStream, codec.decoder)
def bufferedReader() = new BufferedReader(reader(), bufferSize)
- override val iter = {
- val reader = bufferedReader()
- Iterator continually (codec wrap reader.read()) takeWhile (_ != -1) map (_.toChar)
+ // The same reader has to be shared between the iterators produced
+ // by iter and getLines. This is because calling hasNext can cause a
+ // block of data to be read from the stream, which will then be lost
+ // to getLines if it creates a new reader, even though next() was
+ // never called on the original.
+ private var charReaderCreated = false
+ private lazy val charReader = {
+ charReaderCreated = true
+ bufferedReader()
}
+ override lazy val iter = (
+ Iterator
+ continually (codec wrap charReader.read())
+ takeWhile (_ != -1)
+ map (_.toChar)
+ )
+
class BufferedLineIterator extends Iterator[String] {
- val bufReader = BufferedSource.this.bufferedReader()
- var nextLine = bufReader.readLine
+ // Don't want to lose a buffered char sitting in iter either. Yes,
+ // this is ridiculous, but if I can't get rid of Source, and all the
+ // Iterator bits are designed into Source, and people create Sources
+ // in the repl, and the repl calls toString for the result line, and
+ // that calls hasNext to find out if they're empty, and that leads
+ // to chars being buffered, and no, I don't work here, they left a
+ // door unlocked.
+ private val lineReader: BufferedReader = {
+ // To avoid inflicting this silliness indiscriminately, we can
+ // skip it if the char reader was never created: and almost always
+ // it will not have been created, since getLines will be called
+ // immediately on the source.
+ if (charReaderCreated && iter.hasNext) {
+ val pb = new PushbackReader(charReader)
+ pb unread iter.next()
+ new BufferedReader(pb, bufferSize)
+ }
+ else charReader
+ }
+ var nextLine: String = null
- override def hasNext = nextLine != null
+ override def hasNext = {
+ if (nextLine == null)
+ nextLine = lineReader.readLine
+
+ nextLine != null
+ }
override def next(): String = {
- val result = nextLine
- nextLine = bufReader.readLine
- result
+ val result = {
+ if (nextLine == null) lineReader.readLine
+ else try nextLine finally nextLine = null
+ }
+ if (result == null) Iterator.empty.next
+ else result
}
}
diff --git a/test/files/run/bug4671.check b/test/files/run/bug4671.check
new file mode 100644
index 0000000000..dc92c9a72f
--- /dev/null
+++ b/test/files/run/bug4671.check
@@ -0,0 +1,46 @@
+Type in expressions to have them evaluated.
+Type :help for more information.
+
+scala> object o { val file = sys.props("partest.cwd") + "/bug4671.scala" }
+defined module o
+
+scala> val s = scala.io.Source.fromFile(o.file)
+s: scala.io.BufferedSource = non-empty iterator
+
+scala> println(s.getLines.mkString("\n"))
+import scala.tools.partest.ReplTest
+
+object Test extends ReplTest {
+ // My god...it's full of quines
+ def code = """
+object o { val file = sys.props("partest.cwd") + "/bug4671.scala" }
+val s = scala.io.Source.fromFile(o.file)
+println(s.getLines.mkString("\n"))
+
+val s = scala.io.Source.fromFile(o.file)
+println(s.mkString(""))
+""".trim
+}
+
+scala>
+
+scala> val s = scala.io.Source.fromFile(o.file)
+s: scala.io.BufferedSource = non-empty iterator
+
+scala> println(s.mkString(""))
+import scala.tools.partest.ReplTest
+
+object Test extends ReplTest {
+ // My god...it's full of quines
+ def code = """
+object o { val file = sys.props("partest.cwd") + "/bug4671.scala" }
+val s = scala.io.Source.fromFile(o.file)
+println(s.getLines.mkString("\n"))
+
+val s = scala.io.Source.fromFile(o.file)
+println(s.mkString(""))
+""".trim
+}
+
+
+scala>
diff --git a/test/files/run/bug4671.scala b/test/files/run/bug4671.scala
new file mode 100644
index 0000000000..0c1e5908bf
--- /dev/null
+++ b/test/files/run/bug4671.scala
@@ -0,0 +1,13 @@
+import scala.tools.partest.ReplTest
+
+object Test extends ReplTest {
+ // My god...it's full of quines
+ def code = """
+object o { val file = sys.props("partest.cwd") + "/bug4671.scala" }
+val s = scala.io.Source.fromFile(o.file)
+println(s.getLines.mkString("\n"))
+
+val s = scala.io.Source.fromFile(o.file)
+println(s.mkString(""))
+""".trim
+}