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"
11 #include "llvm/ADT/STLExtras.h"
16 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
21 using namespace lldb_private;
24 Terminal::IsATerminal () const
27 return m_fd >= 0 && ::isatty (m_fd);
32 Terminal::SetEcho (bool enabled)
34 if (FileDescriptorIsValid())
36 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
39 struct termios fd_termios;
40 if (::tcgetattr(m_fd, &fd_termios) == 0)
42 bool set_corectly = false;
45 if (fd_termios.c_lflag & ECHO)
48 fd_termios.c_lflag |= ECHO;
52 if (fd_termios.c_lflag & ECHO)
53 fd_termios.c_lflag &= ~ECHO;
60 return ::tcsetattr (m_fd, TCSANOW, &fd_termios) == 0;
63 #endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
69 Terminal::SetCanonical (bool enabled)
71 if (FileDescriptorIsValid())
73 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
76 struct termios fd_termios;
77 if (::tcgetattr(m_fd, &fd_termios) == 0)
79 bool set_corectly = false;
82 if (fd_termios.c_lflag & ICANON)
85 fd_termios.c_lflag |= ICANON;
89 if (fd_termios.c_lflag & ICANON)
90 fd_termios.c_lflag &= ~ICANON;
97 return ::tcsetattr (m_fd, TCSANOW, &fd_termios) == 0;
100 #endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
105 //----------------------------------------------------------------------
106 // Default constructor
107 //----------------------------------------------------------------------
108 TerminalState::TerminalState() :
111 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
118 //----------------------------------------------------------------------
120 //----------------------------------------------------------------------
121 TerminalState::~TerminalState()
126 TerminalState::Clear ()
130 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
131 m_termios_ap.reset();
133 m_process_group = -1;
136 //----------------------------------------------------------------------
137 // Save the current state of the TTY for the file descriptor "fd"
138 // and if "save_process_group" is true, attempt to save the process
139 // group info for the TTY.
140 //----------------------------------------------------------------------
142 TerminalState::Save (int fd, bool save_process_group)
144 m_tty.SetFileDescriptor(fd);
145 if (m_tty.IsATerminal())
147 #ifndef LLDB_DISABLE_POSIX
148 m_tflags = ::fcntl (fd, F_GETFL, 0);
150 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
151 if (m_termios_ap.get() == NULL)
152 m_termios_ap.reset (new struct termios);
153 int err = ::tcgetattr (fd, m_termios_ap.get());
155 m_termios_ap.reset();
156 #endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
157 #ifndef LLDB_DISABLE_POSIX
158 if (save_process_group)
159 m_process_group = ::tcgetpgrp (0);
161 m_process_group = -1;
168 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
169 m_termios_ap.reset();
171 m_process_group = -1;
176 //----------------------------------------------------------------------
177 // Restore the state of the TTY using the cached values from a
178 // previous call to Save().
179 //----------------------------------------------------------------------
181 TerminalState::Restore () const
185 const int fd = m_tty.GetFileDescriptor();
186 #ifndef LLDB_DISABLE_POSIX
188 fcntl (fd, F_SETFL, m_tflags);
191 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
192 if (TTYStateIsValid())
193 tcsetattr (fd, TCSANOW, m_termios_ap.get());
194 #endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
196 #ifndef LLDB_DISABLE_POSIX
197 if (ProcessGroupIsValid())
199 // Save the original signal handler.
200 void (*saved_sigttou_callback) (int) = NULL;
201 saved_sigttou_callback = (void (*)(int)) signal (SIGTTOU, SIG_IGN);
202 // Set the process group
203 tcsetpgrp (fd, m_process_group);
204 // Restore the original signal handler.
205 signal (SIGTTOU, saved_sigttou_callback);
216 //----------------------------------------------------------------------
217 // Returns true if this object has valid saved TTY state settings
218 // that can be used to restore a previous state.
219 //----------------------------------------------------------------------
221 TerminalState::IsValid() const
223 return m_tty.FileDescriptorIsValid () && (TFlagsIsValid() || TTYStateIsValid());
226 //----------------------------------------------------------------------
227 // Returns true if m_tflags is valid
228 //----------------------------------------------------------------------
230 TerminalState::TFlagsIsValid() const
232 return m_tflags != -1;
235 //----------------------------------------------------------------------
236 // Returns true if m_ttystate is valid
237 //----------------------------------------------------------------------
239 TerminalState::TTYStateIsValid() const
241 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
242 return m_termios_ap.get() != 0;
248 //----------------------------------------------------------------------
249 // Returns true if m_process_group is valid
250 //----------------------------------------------------------------------
252 TerminalState::ProcessGroupIsValid() const
254 return static_cast<int32_t>(m_process_group) != -1;
257 //------------------------------------------------------------------
259 //------------------------------------------------------------------
260 TerminalStateSwitcher::TerminalStateSwitcher () :
261 m_currentState(UINT32_MAX)
265 //------------------------------------------------------------------
267 //------------------------------------------------------------------
268 TerminalStateSwitcher::~TerminalStateSwitcher ()
272 //------------------------------------------------------------------
273 // Returns the number of states that this switcher contains
274 //------------------------------------------------------------------
276 TerminalStateSwitcher::GetNumberOfStates() const
278 return llvm::array_lengthof(m_ttystates);
281 //------------------------------------------------------------------
282 // Restore the state at index "idx".
284 // Returns true if the restore was successful, false otherwise.
285 //------------------------------------------------------------------
287 TerminalStateSwitcher::Restore (uint32_t idx) const
289 const uint32_t num_states = GetNumberOfStates();
290 if (idx >= num_states)
293 // See if we already are in this state?
294 if (m_currentState < num_states && (idx == m_currentState) && m_ttystates[idx].IsValid())
297 // Set the state to match the index passed in and only update the
298 // current state if there are no errors.
299 if (m_ttystates[idx].Restore())
301 m_currentState = idx;
305 // We failed to set the state. The tty state was invalid or not
310 //------------------------------------------------------------------
311 // Save the state at index "idx" for file descriptor "fd" and
312 // save the process group if requested.
314 // Returns true if the restore was successful, false otherwise.
315 //------------------------------------------------------------------
317 TerminalStateSwitcher::Save (uint32_t idx, int fd, bool save_process_group)
319 const uint32_t num_states = GetNumberOfStates();
320 if (idx < num_states)
321 return m_ttystates[idx].Save(fd, save_process_group);