1/*
2 * Copyright (c) 2002-2012, the original author or authors.
3 *
4 * This software is distributable under the BSD license. See the terms of the
5 * BSD license in the documentation provided with this software.
6 *
7 * http://www.opensource.org/licenses/bsd-license.php
8 */
9package jdk.internal.jline;
10
11import jdk.internal.jline.internal.Log;
12import jdk.internal.jline.internal.TerminalLineSettings;
13
14/**
15 * Terminal that is used for unix platforms. Terminal initialization
16 * is handled by issuing the <em>stty</em> command against the
17 * <em>/dev/tty</em> file to disable character echoing and enable
18 * character input. All known unix systems (including
19 * Linux and Macintosh OS X) support the <em>stty</em>), so this
20 * implementation should work for an reasonable POSIX system.
21 *
22 * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
23 * @author <a href="mailto:dwkemp@gmail.com">Dale Kemp</a>
24 * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
25 * @author <a href="mailto:jbonofre@apache.org">Jean-Baptiste Onofr\u00E9</a>
26 * @since 2.0
27 */
28public class UnixTerminal
29    extends TerminalSupport
30{
31    private final TerminalLineSettings settings = new TerminalLineSettings();
32
33    public UnixTerminal() throws Exception {
34        super(true);
35    }
36
37    protected TerminalLineSettings getSettings() {
38        return settings;
39    }
40
41    /**
42     * Remove line-buffered input by invoking "stty -icanon min 1"
43     * against the current terminal.
44     */
45    @Override
46    public void init() throws Exception {
47        super.init();
48
49        setAnsiSupported(true);
50
51        // Set the console to be character-buffered instead of line-buffered.
52        // Make sure we're distinguishing carriage return from newline.
53        // Allow ctrl-s keypress to be used (as forward search)
54        settings.set("-icanon min 1 -icrnl -inlcr -ixon");
55        settings.set("dsusp undef");
56
57        setEchoEnabled(false);
58    }
59
60    /**
61     * Restore the original terminal configuration, which can be used when
62     * shutting down the console reader. The ConsoleReader cannot be
63     * used after calling this method.
64     */
65    @Override
66    public void restore() throws Exception {
67        settings.restore();
68        super.restore();
69    }
70
71    /**
72     * Returns the value of <tt>stty columns</tt> param.
73     */
74    @Override
75    public int getWidth() {
76        int w = settings.getProperty("columns");
77        return w < 1 ? DEFAULT_WIDTH : w;
78    }
79
80    /**
81     * Returns the value of <tt>stty rows>/tt> param.
82     */
83    @Override
84    public int getHeight() {
85        int h = settings.getProperty("rows");
86        return h < 1 ? DEFAULT_HEIGHT : h;
87    }
88
89    @Override
90    public synchronized void setEchoEnabled(final boolean enabled) {
91        try {
92            if (enabled) {
93                settings.set("echo");
94            }
95            else {
96                settings.set("-echo");
97            }
98            super.setEchoEnabled(enabled);
99        }
100        catch (Exception e) {
101            if (e instanceof InterruptedException) {
102                Thread.currentThread().interrupt();
103            }
104            Log.error("Failed to ", (enabled ? "enable" : "disable"), " echo", e);
105        }
106    }
107
108    public void disableInterruptCharacter()
109    {
110        try {
111            settings.set("intr undef");
112        }
113        catch (Exception e) {
114            if (e instanceof InterruptedException) {
115                Thread.currentThread().interrupt();
116            }
117            Log.error("Failed to disable interrupt character", e);
118        }
119    }
120
121    public void enableInterruptCharacter()
122    {
123        try {
124            settings.set("intr ^C");
125        }
126        catch (Exception e) {
127            if (e instanceof InterruptedException) {
128                Thread.currentThread().interrupt();
129            }
130            Log.error("Failed to enable interrupt character", e);
131        }
132    }
133}
134