Home | History | Annotate | Download | only in io
      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.ErrnoException;
     20 import libcore.io.Libcore;
     21 import static libcore.io.OsConstants.*;
     22 
     23 /**
     24  * Provides access to the console, if available. The system-wide instance can
     25  * be accessed via {@link java.lang.System#console}.
     26  * @since 1.6
     27  */
     28 public final class Console implements Flushable {
     29     private static final Object CONSOLE_LOCK = new Object();
     30 
     31     private static final Console console = makeConsole();
     32 
     33     private final ConsoleReader reader;
     34     private final PrintWriter writer;
     35 
     36     /**
     37      * Secret accessor for {@code System.console}.
     38      * @hide
     39      */
     40     public static Console getConsole() {
     41         return console;
     42     }
     43 
     44     private static Console makeConsole() {
     45         // We don't care about stderr, because this class only uses stdin and stdout.
     46         if (!Libcore.os.isatty(FileDescriptor.in) || !Libcore.os.isatty(FileDescriptor.out)) {
     47             return null;
     48         }
     49         try {
     50             return new Console(System.in, System.out);
     51         } catch (IOException ex) {
     52             throw new AssertionError(ex);
     53         }
     54     }
     55 
     56     private Console(InputStream in, OutputStream out) throws IOException {
     57         this.reader = new ConsoleReader(in);
     58         this.writer = new ConsoleWriter(out);
     59     }
     60 
     61     public void flush() {
     62         writer.flush();
     63     }
     64 
     65     /**
     66      * Writes a formatted string to the console using
     67      * the specified format string and arguments.
     68      *
     69      * @param format the format string (see {@link java.util.Formatter#format})
     70      * @param args
     71      *            the list of arguments passed to the formatter. If there are
     72      *            more arguments than required by {@code format},
     73      *            additional arguments are ignored.
     74      * @return the console instance.
     75      */
     76     public Console format(String format, Object... args) {
     77         Formatter f = new Formatter(writer);
     78         f.format(format, args);
     79         f.flush();
     80         return this;
     81     }
     82 
     83     /**
     84      * Equivalent to {@code format(format, args)}.
     85      */
     86     public Console printf(String format, Object... args) {
     87         return format(format, args);
     88     }
     89 
     90     /**
     91      * Returns the {@link Reader} associated with this console.
     92      */
     93     public Reader reader() {
     94         return reader;
     95     }
     96 
     97     /**
     98      * Reads a line from the console.
     99      *
    100      * @return the line, or null at EOF.
    101      */
    102     public String readLine() {
    103         try {
    104             return reader.readLine();
    105         } catch (IOException e) {
    106             throw new IOError(e);
    107         }
    108     }
    109 
    110     /**
    111      * Reads a line from this console, using the specified prompt.
    112      * The prompt is given as a format string and optional arguments.
    113      * Note that this can be a source of errors: if it is possible that your
    114      * prompt contains {@code %} characters, you must use the format string {@code "%s"}
    115      * and pass the actual prompt as a parameter.
    116      *
    117      * @param format the format string (see {@link java.util.Formatter#format})
    118      * @param args
    119      *            the list of arguments passed to the formatter. If there are
    120      *            more arguments than required by {@code format},
    121      *            additional arguments are ignored.
    122      * @return the line, or null at EOF.
    123      */
    124     public String readLine(String format, Object... args) {
    125         synchronized (CONSOLE_LOCK) {
    126             format(format, args);
    127             return readLine();
    128         }
    129     }
    130 
    131     /**
    132      * Reads a password from the console. The password will not be echoed to the display.
    133      *
    134      * @return a character array containing the password, or null at EOF.
    135      */
    136     public char[] readPassword() {
    137         synchronized (CONSOLE_LOCK) {
    138             int previousState = setEcho(false, 0);
    139             try {
    140                 String password = readLine();
    141                 writer.println(); // We won't have echoed the user's newline.
    142                 return (password == null) ? null : password.toCharArray();
    143             } finally {
    144                 setEcho(true, previousState);
    145             }
    146         }
    147     }
    148 
    149     private static int setEcho(boolean on, int previousState) {
    150         try {
    151             return setEchoImpl(on, previousState);
    152         } catch (IOException ex) {
    153             throw new IOError(ex);
    154         }
    155     }
    156     private static native int setEchoImpl(boolean on, int previousState) throws IOException;
    157 
    158     /**
    159      * Reads a password from the console. The password will not be echoed to the display.
    160      * A formatted prompt is also displayed.
    161      *
    162      * @param format the format string (see {@link java.util.Formatter#format})
    163      * @param args
    164      *            the list of arguments passed to the formatter. If there are
    165      *            more arguments than required by {@code format},
    166      *            additional arguments are ignored.
    167      * @return a character array containing the password, or null at EOF.
    168      */
    169     public char[] readPassword(String format, Object... args) {
    170         synchronized (CONSOLE_LOCK) {
    171             format(format, args);
    172             return readPassword();
    173         }
    174     }
    175 
    176     /**
    177      * Returns the {@link Writer} associated with this console.
    178      */
    179     public PrintWriter writer() {
    180         return writer;
    181     }
    182 
    183     private static class ConsoleReader extends BufferedReader {
    184         public ConsoleReader(InputStream in) throws IOException {
    185             super(new InputStreamReader(in, System.getProperty("file.encoding")), 256);
    186             lock = CONSOLE_LOCK;
    187         }
    188 
    189         @Override
    190         public void close() {
    191             // Console.reader cannot be closed.
    192         }
    193     }
    194 
    195     private static class ConsoleWriter extends PrintWriter {
    196         public ConsoleWriter(OutputStream out) {
    197             super(out, true);
    198             lock = CONSOLE_LOCK;
    199         }
    200 
    201         @Override
    202         public void close() {
    203             // Console.writer cannot be closed.
    204             flush();
    205         }
    206     }
    207 }
    208