summaryrefslogtreecommitdiff
path: root/examples/scala-js/javalib/src/main/scala/java/io/PrintWriter.scala
blob: 4e693e043b241c6442dd38abe161037711e5961a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package java.io

import java.util.Formatter

class PrintWriter(protected[io] var out: Writer,
    autoFlush: Boolean) extends Writer {

  def this(out: Writer) = this(out, false)

  def this(out: OutputStream, autoFlush: Boolean) =
    this(new OutputStreamWriter(out), autoFlush)
  def this(out: OutputStream) =
    this(out, false)

  /* The following constructors, although implemented, will not link, since
   * File, FileOutputStream and BufferedOutputStream are not implemented.
   * They're here just in case a third-party library on the classpath
   * implements those.
   */
  def this(file: File) =
    this(new BufferedOutputStream(new FileOutputStream(file)))
  def this(file: File, csn: String) =
    this(new OutputStreamWriter(new BufferedOutputStream(
        new FileOutputStream(file)), csn))
  def this(fileName: String) = this(new File(fileName))
  def this(fileName: String, csn: String) = this(new File(fileName), csn)

  private var closed: Boolean = false
  private var errorFlag: Boolean = false

  def flush(): Unit =
    ensureOpenAndTrapIOExceptions(out.flush())

  def close(): Unit = trapIOExceptions {
    if (!closed) {
      flush()
      closed = true
      out.close()
    }
  }

  def checkError(): Boolean = {
    if (closed) {
      /* Just check the error flag.
       * Common sense would tell us to look at the underlying writer's
       * checkError() result too (like we do in the not closed case below).
       * But the JDK does not behave like that. So we don't either.
       */
      errorFlag
    } else {
      flush()
      /* If the underlying writer is also a PrintWriter, we also check its
       * checkError() result. This is not clearly specified by the JavaDoc,
       * but, experimentally, the JDK seems to behave that way.
       */
      errorFlag || (out match {
        case out: PrintWriter => out.checkError()
        case _                => false
      })
    }
  }

  protected[io] def setError(): Unit = errorFlag = true
  protected[io] def clearError(): Unit = errorFlag = false

  override def write(c: Int): Unit =
    ensureOpenAndTrapIOExceptions(out.write(c))

  override def write(buf: Array[Char], off: Int, len: Int): Unit =
    ensureOpenAndTrapIOExceptions(out.write(buf, off, len))

  override def write(buf: Array[Char]): Unit =
    ensureOpenAndTrapIOExceptions(out.write(buf))

  override def write(s: String, off: Int, len: Int): Unit =
    ensureOpenAndTrapIOExceptions(out.write(s, off, len))

  override def write(s: String): Unit =
    ensureOpenAndTrapIOExceptions(out.write(s))

  def print(b: Boolean): Unit     = write(String.valueOf(b))
  def print(c: Char): Unit        = write(c)
  def print(i: Int): Unit         = write(String.valueOf(i))
  def print(l: Long): Unit        = write(String.valueOf(l))
  def print(f: Float): Unit       = write(String.valueOf(f))
  def print(d: Double): Unit      = write(String.valueOf(d))
  def print(s: Array[Char]): Unit = write(s)
  def print(s: String): Unit      = write(if (s == null) "null" else s)
  def print(obj: AnyRef): Unit    = write(String.valueOf(obj))

  def println(): Unit = {
    write('\n') // In Scala.js the line separator is always LF
    if (autoFlush)
      flush()
  }

  def println(b: Boolean): Unit     = { print(b); println() }
  def println(c: Char): Unit        = { print(c); println() }
  def println(i: Int): Unit         = { print(i); println() }
  def println(l: Long): Unit        = { print(l); println() }
  def println(f: Float): Unit       = { print(f); println() }
  def println(d: Double): Unit      = { print(d); println() }
  def println(s: Array[Char]): Unit = { print(s); println() }
  def println(s: String): Unit      = { print(s); println() }
  def println(obj: AnyRef): Unit    = { print(obj); println() }

  def printf(fmt: String, args: Array[Object]): PrintWriter =
    format(fmt, args)

  // Not implemented:
  //def printf(l: java.util.Locale, fmt: String, args: Array[Object]): PrintWriter = ???

  def format(fmt: String, args: Array[Object]): PrintWriter = {
    new Formatter(this).format(fmt, args)
    if (autoFlush)
      flush()
    this
  }

  // Not implemented:
  //def format(l: java.util.Locale, fmt: String, args: Array[Object]): PrintWriter = ???

  override def append(csq: CharSequence): PrintWriter = {
    super.append(csq)
    this
  }

  override def append(csq: CharSequence, start: Int, end: Int): PrintWriter = {
    super.append(csq, start, end)
    this
  }

  override def append(c: Char): PrintWriter = {
    super.append(c)
    this
  }

  @inline private[this] def trapIOExceptions(body: => Unit): Unit = {
    try {
      body
    } catch {
      case _: IOException => setError()
    }
  }

  @inline private[this] def ensureOpenAndTrapIOExceptions(body: => Unit): Unit = {
    if (closed) setError()
    else trapIOExceptions(body)
  }
}