diff options
-rw-r--r-- | src/library/scala/LowPriorityImplicits.scala | 4 | ||||
-rw-r--r-- | src/library/scala/io/BufferedSource.scala | 6 | ||||
-rw-r--r-- | src/library/scala/io/Codec.scala | 22 | ||||
-rw-r--r-- | src/library/scala/io/Source.scala | 194 | ||||
-rw-r--r-- | src/library/scala/xml/parsing/ConstructingParser.scala | 2 | ||||
-rw-r--r-- | src/library/scala/xml/parsing/ExternalSources.scala | 5 | ||||
-rw-r--r-- | src/library/scala/xml/persistent/CachedFileStorage.scala | 2 | ||||
-rw-r--r-- | test/files/jvm/unittest_io.scala | 2 |
8 files changed, 137 insertions, 100 deletions
diff --git a/src/library/scala/LowPriorityImplicits.scala b/src/library/scala/LowPriorityImplicits.scala index 6fdf977dd4..32bdf7e30d 100644 --- a/src/library/scala/LowPriorityImplicits.scala +++ b/src/library/scala/LowPriorityImplicits.scala @@ -6,8 +6,6 @@ ** |/ ** \* */ - - package scala import collection.mutable._ @@ -59,6 +57,4 @@ class LowPriorityImplicits { def wrapArray(xs: Array[Short]): WrappedArray[Short] = new WrappedArray.ofShort(xs) def wrapArray(xs: Array[Boolean]): WrappedArray[Boolean] = new WrappedArray.ofBoolean(xs) def wrapArray(xs: Array[Unit]): WrappedArray[Unit] = new WrappedArray.ofUnit(xs) - - } diff --git a/src/library/scala/io/BufferedSource.scala b/src/library/scala/io/BufferedSource.scala index b4e0389e12..f0230d3724 100644 --- a/src/library/scala/io/BufferedSource.scala +++ b/src/library/scala/io/BufferedSource.scala @@ -18,10 +18,10 @@ import Source.DefaultBufSize * * @author Burak Emir, Paul Phillips */ -class BufferedSource(inputStream: InputStream)(implicit codec: Codec = Codec.default) extends Source -{ +class BufferedSource(inputStream: InputStream, bufferSize: Int)(implicit val codec: Codec) extends Source { + def this(inputStream: InputStream)(implicit codec: Codec) = this(inputStream, DefaultBufSize)(codec) def reader() = new InputStreamReader(inputStream, codec.decoder) - def bufferedReader() = new BufferedReader(reader(), DefaultBufSize) + def bufferedReader() = new BufferedReader(reader(), bufferSize) override val iter = { val reader = bufferedReader() diff --git a/src/library/scala/io/Codec.scala b/src/library/scala/io/Codec.scala index 2b74c67134..e001e732c2 100644 --- a/src/library/scala/io/Codec.scala +++ b/src/library/scala/io/Codec.scala @@ -25,8 +25,7 @@ import java.nio.charset.{ Charset, CharsetDecoder, CharsetEncoder, CharacterCodi /** A class for character encoding/decoding preferences. * */ -class Codec(val charSet: Charset) -{ +class Codec(val charSet: Charset) { type Configure[T] = (T => T, Boolean) type Handler = CharacterCodingException => Int @@ -70,11 +69,26 @@ class Codec(val charSet: Charset) }) } -object Codec { +trait LowPriorityCodecImplicits { + self: Codec.type => + + /** The Codec of Last Resort. */ + implicit def fallbackSystemCodec: Codec = defaultCharsetCodec +} + +object Codec extends LowPriorityCodecImplicits { final val ISO8859 = Charset forName "ISO-8859-1" final val UTF8 = Charset forName "UTF-8" - def default = apply(Charset.defaultCharset) + /** Optimistically these two possible defaults will be the same thing. + * In practice this is not necessarily true, and in fact Sun classifies + * the fact that you can influence anything at all via -Dfile.encoding + * as an accident, with any anomalies considered "not a bug". + */ + def defaultCharsetCodec = apply(Charset.defaultCharset) + def fileEncodingCodec = apply(util.Properties.encodingString) + def default = defaultCharsetCodec + def apply(encoding: String): Codec = new Codec(Charset forName encoding) def apply(charSet: Charset): Codec = new Codec(charSet) def apply(decoder: CharsetDecoder): Codec = { diff --git a/src/library/scala/io/Source.scala b/src/library/scala/io/Source.scala index 5b279d720c..b5313ef61b 100644 --- a/src/library/scala/io/Source.scala +++ b/src/library/scala/io/Source.scala @@ -26,36 +26,78 @@ object Source { */ def stdin = fromInputStream(System.in) - /** Creates a <code>Source</code> from an Iterable. + /** Creates a Source from an Iterable. * * @param iterable the Iterable - * @return the <code>Source</code> instance. + * @return the Source */ def fromIterable(iterable: Iterable[Char]): Source = new Source { val iter = iterable.iterator } withReset(() => fromIterable(iterable)) - /** Creates a <code>Source</code> instance from a single character. - * - * @param c ... - * @return the create <code>Source</code> instance. + /** Creates a Source instance from a single character. */ def fromChar(c: Char): Source = fromIterable(Array(c)) /** creates Source from array of characters, with empty description. - * - * @param chars ... - * @return ... */ def fromChars(chars: Array[Char]): Source = fromIterable(chars) - /** creates Source from string, with empty description. - * - * @param s ... - * @return ... + /** creates Source from a String, with no description. */ def fromString(s: String): Source = fromIterable(s) + /** creates Source from file with given name, setting its description to + * filename. + */ + def fromFile(name: String)(implicit codec: Codec): BufferedSource = + fromFile(new JFile(name))(codec) + + /** creates Source from file with given name, using given encoding, setting + * its description to filename. + */ + def fromFile(name: String, enc: String): BufferedSource = + fromFile(name)(Codec(enc)) + + /** creates <code>Source</code> from file with given file: URI + */ + def fromFile(uri: URI)(implicit codec: Codec): BufferedSource = + fromFile(new JFile(uri))(codec) + + /** creates Source from file with given file: URI + */ + def fromFile(uri: URI, enc: String): BufferedSource = + fromFile(uri)(Codec(enc)) + + /** creates Source from file, using default character encoding, setting its + * description to filename. + */ + def fromFile(file: JFile)(implicit codec: Codec): BufferedSource = + fromFile(file, Source.DefaultBufSize)(codec) + + /** same as fromFile(file, enc, Source.DefaultBufSize) + */ + def fromFile(file: JFile, enc: String): BufferedSource = + fromFile(file)(Codec(enc)) + + def fromFile(file: JFile, enc: String, bufferSize: Int): BufferedSource = + fromFile(file, bufferSize)(Codec(enc)) + + /** Creates Source from <code>file</code>, using given character encoding, + * setting its description to filename. Input is buffered in a buffer of + * size <code>bufferSize</code>. + */ + def fromFile(file: JFile, bufferSize: Int)(implicit codec: Codec): BufferedSource = { + val inputStream = new FileInputStream(file) + + createBufferedSource( + inputStream, + bufferSize, + () => fromFile(file, bufferSize)(codec), + () => inputStream.close() + )(codec) withDescription ("file:" + file.getAbsolutePath) + } + /** Create a <code>Source</code> from array of bytes, decoding * the bytes according to codec. * @@ -63,74 +105,69 @@ object Source { * @param enc ... * @return the created <code>Source</code> instance. */ - def fromBytes(bytes: Array[Byte])(implicit codec: Codec = Codec.default): Source = + def fromBytes(bytes: Array[Byte])(implicit codec: Codec): Source = fromString(new String(bytes, codec.name)) + def fromBytes(bytes: Array[Byte], enc: String): Source = + fromBytes(bytes)(Codec(enc)) + /** Create a <code>Source</code> from array of bytes, assuming * one byte per character (ISO-8859-1 encoding.) */ def fromRawBytes(bytes: Array[Byte]): Source = fromString(new String(bytes, Codec.ISO8859.name)) - /** creates Source from file with given name, setting - * its description to filename. + /** creates <code>Source</code> from file with given file: URI */ - def fromPath(name: String)(implicit codec: Codec = Codec.default): Source = fromFile(new JFile(name)) + def fromURI(uri: URI)(implicit codec: Codec): BufferedSource = fromFile(new JFile(uri))(codec) - /** creates <code>Source</code> from file with given file: URI + /** same as fromURL(new URL(s))(Codec(enc)) */ - def fromURI(uri: URI)(implicit codec: Codec = Codec.default): Source = fromFile(new JFile(uri)) + def fromURL(s: String, enc: String): BufferedSource = + fromURL(s)(Codec(enc)) - /** same as fromInputStream(url.openStream())(codec) + /** same as fromURL(new URL(s)) */ - def fromURL(url: URL)(implicit codec: Codec = Codec.default): Source = - fromInputStream(url.openStream())(codec) + def fromURL(s: String)(implicit codec: Codec): BufferedSource = + fromURL(new URL(s))(codec) - /** Creates Source from <code>file</code>, using given character encoding, - * setting its description to filename. Input is buffered in a buffer of - * size <code>bufferSize</code>. + /** same as fromInputStream(url.openStream())(Codec(enc)) */ - def fromFile(file: JFile, bufferSize: Int = DefaultBufSize)(implicit codec: Codec = Codec.default): Source = { - val inputStream = new FileInputStream(file) + def fromURL(url: URL, enc: String): BufferedSource = + fromURL(url)(Codec(enc)) - fromInputStream( - inputStream, - bufferSize, - () => fromFile(file, bufferSize)(codec), - () => inputStream.close() - ) withDescription ("file:" + file.getAbsolutePath) - } + /** same as fromInputStream(url.openStream())(codec) + */ + def fromURL(url: URL)(implicit codec: Codec): BufferedSource = + fromInputStream(url.openStream())(codec) - /** Reads data from <code>inputStream</code> with a buffered reader, - * using encoding in implicit parameter <code>codec</code>. + /** Reads data from inputStream with a buffered reader, using the encoding + * in implicit parameter codec. * * @param inputStream the input stream from which to read * @param bufferSize buffer size (defaults to Source.DefaultBufSize) * @param reset a () => Source which resets the stream (if unset, reset() will throw an Exception) + * @param close a () => Unit method which closes the stream (if unset, close() will do nothing) * @param codec (implicit) a scala.io.Codec specifying behavior (defaults to Codec.default) * @return the buffered source */ - def fromInputStream( + def createBufferedSource( inputStream: InputStream, bufferSize: Int = DefaultBufSize, reset: () => Source = null, close: () => Unit = null - )(implicit codec: Codec = Codec.default): Source = - { + )(implicit codec: Codec): BufferedSource = { // workaround for default arguments being unable to refer to other parameters - val resetFn = if (reset == null) () => fromInputStream(inputStream, bufferSize, reset, close) else reset - new BufferedSource(inputStream)(codec) . - withReset (resetFn) . - withClose (close) + val resetFn = if (reset == null) () => createBufferedSource(inputStream, bufferSize, reset, close)(codec) else reset + + new BufferedSource(inputStream, bufferSize)(codec) withReset resetFn withClose close } -} -// Coming Soon? -// -// abstract class Source2[T] extends Iterable[T] { } -// -// abstract class ByteSource() extends Source2[Byte] { } -// -// abstract class CharSource(implicit codec: Codec = Codec.default) extends Source2[Char] { } + def fromInputStream(is: InputStream, enc: String): BufferedSource = + fromInputStream(is)(Codec(enc)) + + def fromInputStream(is: InputStream)(implicit codec: Codec): BufferedSource = + createBufferedSource(is, reset = () => fromInputStream(is)(codec), close = () => is.close())(codec) +} /** The class <code>Source</code> implements an iterable representation * of source data. Calling method <code>reset</code> returns an identical, @@ -139,8 +176,7 @@ object Source { * @author Burak Emir * @version 1.0 */ -abstract class Source extends Iterator[Char] -{ +abstract class Source extends Iterator[Char] { /** the actual iterator */ protected val iter: Iterator[Char] @@ -152,42 +188,35 @@ abstract class Source extends Iterator[Char] var nerrors = 0 var nwarnings = 0 - /** convenience method, returns given line (not including newline) + /** Convenience method, returns given line (not including newline) * from Source. * * @param line the line index, first line is 1 - * @return the character string of the specified line. + * @return the specified line. * */ + @deprecated("Use a collections method such as getLines().toIndexedSeq for random access.") def getLine(line: Int): String = getLines() drop (line - 1) next - class LineIterator(separator: String) extends Iterator[String] { - require(separator.length == 1 || separator.length == 2, "Line separator may be 1 or 2 characters only.") - lazy val iter: BufferedIterator[Char] = Source.this.iter.buffered - // For two character newline sequences like \r\n, we peek at - // the iterator head after seeing \r, and drop the \n if present. - val isNewline: Char => Boolean = { - val firstCh = separator(0) - if (separator.length == 1) (_ == firstCh) - else (ch: Char) => (ch == firstCh) && iter.hasNext && { - val res = iter.head == separator(1) - if (res) { iter.next } // drop the second character - res - } - } + class LineIterator() extends Iterator[String] { private[this] val sb = new StringBuilder - private def getc() = - if (!iter.hasNext) false + lazy val iter: BufferedIterator[Char] = Source.this.iter.buffered + def isNewline(ch: Char) = ch == '\r' || ch == '\n' + def getc() = iter.hasNext && { + val ch = iter.next + if (ch == '\n') false + else if (ch == '\r') { + if (iter.hasNext && iter.head == '\n') + iter.next + + false + } else { - val ch = iter.next - if (isNewline(ch)) false - else { - sb append ch - true - } + sb append ch + true } - + } def hasNext = iter.hasNext def next = { sb.clear @@ -196,12 +225,11 @@ abstract class Source extends Iterator[Char] } } - /** returns an iterator who returns lines (NOT including newline character(s)). - * If no separator is given, the platform-specific value "line.separator" is used. - * a line ends in \r, \n, or \r\n. + /** Returns an iterator who returns lines (NOT including newline character(s)). + * It will treat any of \r\n, \r, or \n as a line separator (longest match) - if + * you need more refined behavior you can subclass Source#LineIterator directly. */ - def getLines(separator: String = compat.Platform.EOL): Iterator[String] = - new LineIterator(separator) + def getLines(): Iterator[String] = new LineIterator() /** Returns <code>true</code> if this source has more characters. */ diff --git a/src/library/scala/xml/parsing/ConstructingParser.scala b/src/library/scala/xml/parsing/ConstructingParser.scala index e54e411587..aaa9f020dd 100644 --- a/src/library/scala/xml/parsing/ConstructingParser.scala +++ b/src/library/scala/xml/parsing/ConstructingParser.scala @@ -17,7 +17,7 @@ import scala.io.{ Source, Codec } object ConstructingParser { def fromFile(inp: File, preserveWS: Boolean) = - new ConstructingParser(Source.fromFile(inp)(), preserveWS) initialize + new ConstructingParser(Source.fromFile(inp), preserveWS) initialize def fromSource(inp: Source, preserveWS: Boolean) = new ConstructingParser(inp, preserveWS) initialize diff --git a/src/library/scala/xml/parsing/ExternalSources.scala b/src/library/scala/xml/parsing/ExternalSources.scala index e0a0f6b986..a1363b8b17 100644 --- a/src/library/scala/xml/parsing/ExternalSources.scala +++ b/src/library/scala/xml/parsing/ExternalSources.scala @@ -20,8 +20,7 @@ import scala.io.Source * @author Burak Emir * @version 1.0 */ -trait ExternalSources -{ +trait ExternalSources { self: ExternalSources with MarkupParser with MarkupHandler => /** ... @@ -38,6 +37,6 @@ trait ExternalSources case x => x take ((x lastIndexOf separator) + 1) } - Source.fromPath(fileStr + systemId)() + Source.fromFile(fileStr + systemId) } } diff --git a/src/library/scala/xml/persistent/CachedFileStorage.scala b/src/library/scala/xml/persistent/CachedFileStorage.scala index dfd675f36a..5550259a09 100644 --- a/src/library/scala/xml/persistent/CachedFileStorage.scala +++ b/src/library/scala/xml/persistent/CachedFileStorage.scala @@ -73,7 +73,7 @@ extends java.lang.Thread with scala.util.logging.Logged { import scala.io.Source import scala.xml.parsing.ConstructingParser log("[load]\nloading "+theFile) - val src = Source.fromFile(theFile)() + val src = Source.fromFile(theFile) log("parsing "+theFile) val res = ConstructingParser.fromSource(src,false).document.docElem(0) switch diff --git a/test/files/jvm/unittest_io.scala b/test/files/jvm/unittest_io.scala index 80d33d8433..fd5889cb86 100644 --- a/test/files/jvm/unittest_io.scala +++ b/test/files/jvm/unittest_io.scala @@ -15,7 +15,7 @@ it is split on several lines. isn't it? """) - def runTest() = assertEquals("wrong number of lines",src.getLines("\n").toList.length,5) // five new lines in there + def runTest() = assertEquals("wrong number of lines",src.getLines.toList.length,5) // five new lines in there //for (line <- src.getLines) { // Console.print(line) //} |