1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package java.io;
17 
18 import java.util.Formatter;
19 import libcore.io.Libcore;
20 
21 /**
22  * Provides access to the console, if available. The system-wide instance can
23  * be accessed via {@link java.lang.System#console}.
24  * @since 1.6
25  */
26 public final class Console implements Flushable {
27     private static final Object CONSOLE_LOCK = new Object();
28 
29     private static final Console console = makeConsole();
30 
31     private final ConsoleReader reader;
32     private final PrintWriter writer;
33 
34     /**
35      * Secret accessor for {@code System.console}.
36      * @hide
37      */
getConsole()38     public static Console getConsole() {
39         return console;
40     }
41 
makeConsole()42     private static Console makeConsole() {
43         // We don't care about stderr, because this class only uses stdin and stdout.
44         if (!Libcore.os.isatty(FileDescriptor.in) || !Libcore.os.isatty(FileDescriptor.out)) {
45             return null;
46         }
47         try {
48             return new Console(System.in, System.out);
49         } catch (UnsupportedEncodingException ex) {
50             throw new AssertionError(ex);
51         }
52     }
53 
Console(InputStream in, OutputStream out)54     private Console(InputStream in, OutputStream out) throws UnsupportedEncodingException {
55         this.reader = new ConsoleReader(in);
56         this.writer = new ConsoleWriter(out);
57     }
58 
flush()59     public void flush() {
60         writer.flush();
61     }
62 
63     /**
64      * Writes a formatted string to the console using
65      * the specified format string and arguments.
66      *
67      * @param format the format string (see {@link java.util.Formatter#format})
68      * @param args
69      *            the list of arguments passed to the formatter. If there are
70      *            more arguments than required by {@code format},
71      *            additional arguments are ignored.
72      * @return the console instance.
73      */
format(String format, Object... args)74     public Console format(String format, Object... args) {
75         Formatter f = new Formatter(writer);
76         f.format(format, args);
77         f.flush();
78         return this;
79     }
80 
81     /**
82      * Equivalent to {@code format(format, args)}.
83      */
printf(String format, Object... args)84     public Console printf(String format, Object... args) {
85         return format(format, args);
86     }
87 
88     /**
89      * Returns the {@link Reader} associated with this console.
90      */
reader()91     public Reader reader() {
92         return reader;
93     }
94 
95     /**
96      * Reads a line from the console.
97      *
98      * @return the line, or null at EOF.
99      */
readLine()100     public String readLine() {
101         try {
102             return reader.readLine();
103         } catch (IOException e) {
104             throw new IOError(e);
105         }
106     }
107 
108     /**
109      * Reads a line from this console, using the specified prompt.
110      * The prompt is given as a format string and optional arguments.
111      * Note that this can be a source of errors: if it is possible that your
112      * prompt contains {@code %} characters, you must use the format string {@code "%s"}
113      * and pass the actual prompt as a parameter.
114      *
115      * @param format the format string (see {@link java.util.Formatter#format})
116      * @param args
117      *            the list of arguments passed to the formatter. If there are
118      *            more arguments than required by {@code format},
119      *            additional arguments are ignored.
120      * @return the line, or null at EOF.
121      */
readLine(String format, Object... args)122     public String readLine(String format, Object... args) {
123         synchronized (CONSOLE_LOCK) {
124             format(format, args);
125             return readLine();
126         }
127     }
128 
129     /**
130      * This method is unimplemented on Android.
131      */
readPassword()132     public char[] readPassword() {
133         throw new UnsupportedOperationException();
134     }
135 
136     /**
137      * This method is unimplemented on Android.
138      */
readPassword(String format, Object... args)139     public char[] readPassword(String format, Object... args) {
140         throw new UnsupportedOperationException();
141     }
142 
143     /**
144      * Returns the {@link Writer} associated with this console.
145      */
writer()146     public PrintWriter writer() {
147         return writer;
148     }
149 
150     private static class ConsoleReader extends BufferedReader {
ConsoleReader(InputStream in)151         public ConsoleReader(InputStream in) throws UnsupportedEncodingException {
152             super(new InputStreamReader(in, System.getProperty("file.encoding")), 256);
153             lock = CONSOLE_LOCK;
154         }
155 
156         @Override
close()157         public void close() {
158             // Console.reader cannot be closed.
159         }
160     }
161 
162     private static class ConsoleWriter extends PrintWriter {
ConsoleWriter(OutputStream out)163         public ConsoleWriter(OutputStream out) {
164             super(out, true);
165             lock = CONSOLE_LOCK;
166         }
167 
168         @Override
close()169         public void close() {
170             // Console.writer cannot be closed.
171             flush();
172         }
173     }
174 }
175