1 //===-- Terminal.cpp --------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lldb/Host/Terminal.h"
12 #include "lldb/Host/PosixApi.h"
13 #include "llvm/ADT/STLExtras.h"
18 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
22 using namespace lldb_private;
24 bool Terminal::IsATerminal() const { return m_fd >= 0 && ::isatty(m_fd); }
26 bool Terminal::SetEcho(bool enabled) {
27 if (FileDescriptorIsValid()) {
28 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
30 struct termios fd_termios;
31 if (::tcgetattr(m_fd, &fd_termios) == 0) {
32 bool set_corectly = false;
34 if (fd_termios.c_lflag & ECHO)
37 fd_termios.c_lflag |= ECHO;
39 if (fd_termios.c_lflag & ECHO)
40 fd_termios.c_lflag &= ~ECHO;
47 return ::tcsetattr(m_fd, TCSANOW, &fd_termios) == 0;
50 #endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
55 bool Terminal::SetCanonical(bool enabled) {
56 if (FileDescriptorIsValid()) {
57 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
59 struct termios fd_termios;
60 if (::tcgetattr(m_fd, &fd_termios) == 0) {
61 bool set_corectly = false;
63 if (fd_termios.c_lflag & ICANON)
66 fd_termios.c_lflag |= ICANON;
68 if (fd_termios.c_lflag & ICANON)
69 fd_termios.c_lflag &= ~ICANON;
76 return ::tcsetattr(m_fd, TCSANOW, &fd_termios) == 0;
79 #endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
84 //----------------------------------------------------------------------
85 // Default constructor
86 //----------------------------------------------------------------------
87 TerminalState::TerminalState()
88 : m_tty(), m_tflags(-1),
89 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
95 //----------------------------------------------------------------------
97 //----------------------------------------------------------------------
98 TerminalState::~TerminalState() {}
100 void TerminalState::Clear() {
103 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
104 m_termios_ap.reset();
106 m_process_group = -1;
109 //----------------------------------------------------------------------
110 // Save the current state of the TTY for the file descriptor "fd"
111 // and if "save_process_group" is true, attempt to save the process
112 // group info for the TTY.
113 //----------------------------------------------------------------------
114 bool TerminalState::Save(int fd, bool save_process_group) {
115 m_tty.SetFileDescriptor(fd);
116 if (m_tty.IsATerminal()) {
117 #ifndef LLDB_DISABLE_POSIX
118 m_tflags = ::fcntl(fd, F_GETFL, 0);
120 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
121 if (m_termios_ap.get() == NULL)
122 m_termios_ap.reset(new struct termios);
123 int err = ::tcgetattr(fd, m_termios_ap.get());
125 m_termios_ap.reset();
126 #endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
127 #ifndef LLDB_DISABLE_POSIX
128 if (save_process_group)
129 m_process_group = ::tcgetpgrp(0);
131 m_process_group = -1;
136 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
137 m_termios_ap.reset();
139 m_process_group = -1;
144 //----------------------------------------------------------------------
145 // Restore the state of the TTY using the cached values from a
146 // previous call to Save().
147 //----------------------------------------------------------------------
148 bool TerminalState::Restore() const {
149 #ifndef LLDB_DISABLE_POSIX
151 const int fd = m_tty.GetFileDescriptor();
153 fcntl(fd, F_SETFL, m_tflags);
155 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
156 if (TTYStateIsValid())
157 tcsetattr(fd, TCSANOW, m_termios_ap.get());
158 #endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
160 if (ProcessGroupIsValid()) {
161 // Save the original signal handler.
162 void (*saved_sigttou_callback)(int) = NULL;
163 saved_sigttou_callback = (void (*)(int))signal(SIGTTOU, SIG_IGN);
164 // Set the process group
165 tcsetpgrp(fd, m_process_group);
166 // Restore the original signal handler.
167 signal(SIGTTOU, saved_sigttou_callback);
175 //----------------------------------------------------------------------
176 // Returns true if this object has valid saved TTY state settings
177 // that can be used to restore a previous state.
178 //----------------------------------------------------------------------
179 bool TerminalState::IsValid() const {
180 return m_tty.FileDescriptorIsValid() &&
181 (TFlagsIsValid() || TTYStateIsValid());
184 //----------------------------------------------------------------------
185 // Returns true if m_tflags is valid
186 //----------------------------------------------------------------------
187 bool TerminalState::TFlagsIsValid() const { return m_tflags != -1; }
189 //----------------------------------------------------------------------
190 // Returns true if m_ttystate is valid
191 //----------------------------------------------------------------------
192 bool TerminalState::TTYStateIsValid() const {
193 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
194 return m_termios_ap.get() != 0;
200 //----------------------------------------------------------------------
201 // Returns true if m_process_group is valid
202 //----------------------------------------------------------------------
203 bool TerminalState::ProcessGroupIsValid() const {
204 return static_cast<int32_t>(m_process_group) != -1;
207 //------------------------------------------------------------------
209 //------------------------------------------------------------------
210 TerminalStateSwitcher::TerminalStateSwitcher() : m_currentState(UINT32_MAX) {}
212 //------------------------------------------------------------------
214 //------------------------------------------------------------------
215 TerminalStateSwitcher::~TerminalStateSwitcher() {}
217 //------------------------------------------------------------------
218 // Returns the number of states that this switcher contains
219 //------------------------------------------------------------------
220 uint32_t TerminalStateSwitcher::GetNumberOfStates() const {
221 return llvm::array_lengthof(m_ttystates);
224 //------------------------------------------------------------------
225 // Restore the state at index "idx".
227 // Returns true if the restore was successful, false otherwise.
228 //------------------------------------------------------------------
229 bool TerminalStateSwitcher::Restore(uint32_t idx) const {
230 const uint32_t num_states = GetNumberOfStates();
231 if (idx >= num_states)
234 // See if we already are in this state?
235 if (m_currentState < num_states && (idx == m_currentState) &&
236 m_ttystates[idx].IsValid())
239 // Set the state to match the index passed in and only update the
240 // current state if there are no errors.
241 if (m_ttystates[idx].Restore()) {
242 m_currentState = idx;
246 // We failed to set the state. The tty state was invalid or not
251 //------------------------------------------------------------------
252 // Save the state at index "idx" for file descriptor "fd" and
253 // save the process group if requested.
255 // Returns true if the restore was successful, false otherwise.
256 //------------------------------------------------------------------
257 bool TerminalStateSwitcher::Save(uint32_t idx, int fd,
258 bool save_process_group) {
259 const uint32_t num_states = GetNumberOfStates();
260 if (idx < num_states)
261 return m_ttystates[idx].Save(fd, save_process_group);