blob: a1d2097ec35cfec2c47905d14f37864fe8d50ced [file] [log] [blame]
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package java.io;
import java.util.Formatter;
import libcore.io.ErrnoException;
import libcore.io.Libcore;
import static libcore.io.OsConstants.*;
/**
* Provides access to the console, if available. The system-wide instance can
* be accessed via {@link java.lang.System#console}.
* @since 1.6
*/
public final class Console implements Flushable {
private static final Object CONSOLE_LOCK = new Object();
private static final Console console = makeConsole();
private final ConsoleReader reader;
private final PrintWriter writer;
/**
* Secret accessor for {@code System.console}.
* @hide
*/
public static Console getConsole() {
return console;
}
private static Console makeConsole() {
// We don't care about stderr, because this class only uses stdin and stdout.
if (!Libcore.os.isatty(FileDescriptor.in) || !Libcore.os.isatty(FileDescriptor.out)) {
return null;
}
try {
return new Console(System.in, System.out);
} catch (IOException ex) {
throw new AssertionError(ex);
}
}
private Console(InputStream in, OutputStream out) throws IOException {
this.reader = new ConsoleReader(in);
this.writer = new ConsoleWriter(out);
}
public void flush() {
writer.flush();
}
/**
* Writes a formatted string to the console using
* the specified format string and arguments.
*
* @param format the format string (see {@link java.util.Formatter#format})
* @param args
* the list of arguments passed to the formatter. If there are
* more arguments than required by {@code format},
* additional arguments are ignored.
* @return the console instance.
*/
public Console format(String format, Object... args) {
Formatter f = new Formatter(writer);
f.format(format, args);
f.flush();
return this;
}
/**
* Equivalent to {@code format(format, args)}.
*/
public Console printf(String format, Object... args) {
return format(format, args);
}
/**
* Returns the {@link Reader} associated with this console.
*/
public Reader reader() {
return reader;
}
/**
* Reads a line from the console.
*
* @return the line, or null at EOF.
*/
public String readLine() {
try {
return reader.readLine();
} catch (IOException e) {
throw new IOError(e);
}
}
/**
* Reads a line from this console, using the specified prompt.
* The prompt is given as a format string and optional arguments.
* Note that this can be a source of errors: if it is possible that your
* prompt contains {@code %} characters, you must use the format string {@code "%s"}
* and pass the actual prompt as a parameter.
*
* @param format the format string (see {@link java.util.Formatter#format})
* @param args
* the list of arguments passed to the formatter. If there are
* more arguments than required by {@code format},
* additional arguments are ignored.
* @return the line, or null at EOF.
*/
public String readLine(String format, Object... args) {
synchronized (CONSOLE_LOCK) {
format(format, args);
return readLine();
}
}
/**
* Reads a password from the console. The password will not be echoed to the display.
*
* @return a character array containing the password, or null at EOF.
*/
public char[] readPassword() {
synchronized (CONSOLE_LOCK) {
int previousState = setEcho(false, 0);
try {
String password = readLine();
writer.println(); // We won't have echoed the user's newline.
return (password == null) ? null : password.toCharArray();
} finally {
setEcho(true, previousState);
}
}
}
private static int setEcho(boolean on, int previousState) {
try {
return setEchoImpl(on, previousState);
} catch (IOException ex) {
throw new IOError(ex);
}
}
private static native int setEchoImpl(boolean on, int previousState) throws IOException;
/**
* Reads a password from the console. The password will not be echoed to the display.
* A formatted prompt is also displayed.
*
* @param format the format string (see {@link java.util.Formatter#format})
* @param args
* the list of arguments passed to the formatter. If there are
* more arguments than required by {@code format},
* additional arguments are ignored.
* @return a character array containing the password, or null at EOF.
*/
public char[] readPassword(String format, Object... args) {
synchronized (CONSOLE_LOCK) {
format(format, args);
return readPassword();
}
}
/**
* Returns the {@link Writer} associated with this console.
*/
public PrintWriter writer() {
return writer;
}
private static class ConsoleReader extends BufferedReader {
public ConsoleReader(InputStream in) throws IOException {
super(new InputStreamReader(in, System.getProperty("file.encoding")), 256);
lock = CONSOLE_LOCK;
}
@Override
public void close() {
// Console.reader cannot be closed.
}
}
private static class ConsoleWriter extends PrintWriter {
public ConsoleWriter(OutputStream out) {
super(out, true);
lock = CONSOLE_LOCK;
}
@Override
public void close() {
// Console.writer cannot be closed.
flush();
}
}
}