]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - source/Host/common/Terminal.cpp
Import LLDB as of upstream SVN r216948 (git 50f7fe44)
[FreeBSD/FreeBSD.git] / source / Host / common / Terminal.cpp
1 //===-- Terminal.cpp --------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "lldb/Host/Terminal.h"
11 #include "llvm/ADT/STLExtras.h"
12
13 #include <fcntl.h>
14 #include <signal.h>
15
16 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
17 #include <termios.h>
18 #endif
19
20
21 using namespace lldb_private;
22
23 bool
24 Terminal::IsATerminal () const
25 {
26
27     return m_fd >= 0 && ::isatty (m_fd);
28 }
29     
30
31 bool
32 Terminal::SetEcho (bool enabled)
33 {
34     if (FileDescriptorIsValid())
35     {
36 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
37         if (IsATerminal ())
38         {
39             struct termios fd_termios;
40             if (::tcgetattr(m_fd, &fd_termios) == 0)
41             {    
42                 bool set_corectly = false;
43                 if (enabled)
44                 {
45                     if (fd_termios.c_lflag & ECHO)
46                         set_corectly = true;
47                     else
48                         fd_termios.c_lflag |= ECHO;
49                 }
50                 else
51                 {
52                     if (fd_termios.c_lflag & ECHO)
53                         fd_termios.c_lflag &= ~ECHO;
54                     else
55                         set_corectly = true;
56                 }
57                 
58                 if (set_corectly)
59                     return true;
60                 return ::tcsetattr (m_fd, TCSANOW, &fd_termios) == 0;
61             }
62         }
63 #endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
64     }
65     return false;
66 }
67
68 bool
69 Terminal::SetCanonical (bool enabled)
70 {
71     if (FileDescriptorIsValid())
72     {
73 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
74         if (IsATerminal ())
75         {
76             struct termios fd_termios;
77             if (::tcgetattr(m_fd, &fd_termios) == 0)
78             {    
79                 bool set_corectly = false;
80                 if (enabled)
81                 {
82                     if (fd_termios.c_lflag & ICANON)
83                         set_corectly = true;
84                     else
85                         fd_termios.c_lflag |= ICANON;
86                 }
87                 else
88                 {
89                     if (fd_termios.c_lflag & ICANON)
90                         fd_termios.c_lflag &= ~ICANON;
91                     else
92                         set_corectly = true;
93                 }
94                 
95                 if (set_corectly)
96                     return true;
97                 return ::tcsetattr (m_fd, TCSANOW, &fd_termios) == 0;
98             }
99         }
100 #endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
101     }
102     return false;
103 }
104
105 //----------------------------------------------------------------------
106 // Default constructor
107 //----------------------------------------------------------------------
108 TerminalState::TerminalState() :
109     m_tty(),
110     m_tflags(-1),
111 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
112     m_termios_ap(),
113 #endif
114     m_process_group(-1)
115 {
116 }
117
118 //----------------------------------------------------------------------
119 // Destructor
120 //----------------------------------------------------------------------
121 TerminalState::~TerminalState()
122 {
123 }
124
125 void
126 TerminalState::Clear ()
127 {
128     m_tty.Clear();
129     m_tflags = -1;
130 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
131     m_termios_ap.reset();
132 #endif
133     m_process_group = -1;
134 }
135
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 //----------------------------------------------------------------------
141 bool
142 TerminalState::Save (int fd, bool save_process_group)
143 {
144     m_tty.SetFileDescriptor(fd);
145     if (m_tty.IsATerminal())
146     {
147 #ifndef LLDB_DISABLE_POSIX
148         m_tflags = ::fcntl (fd, F_GETFL, 0);
149 #endif
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());
154         if (err != 0)
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);
160         else
161             m_process_group = -1;
162 #endif
163     }
164     else
165     {
166         m_tty.Clear();
167         m_tflags = -1;
168 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
169         m_termios_ap.reset();
170 #endif
171         m_process_group = -1;
172     }
173     return IsValid();
174 }
175
176 //----------------------------------------------------------------------
177 // Restore the state of the TTY using the cached values from a
178 // previous call to Save().
179 //----------------------------------------------------------------------
180 bool
181 TerminalState::Restore () const
182 {
183     if (IsValid())
184     {
185         const int fd = m_tty.GetFileDescriptor();
186 #ifndef LLDB_DISABLE_POSIX
187         if (TFlagsIsValid())
188             fcntl (fd, F_SETFL, m_tflags);
189 #endif
190
191 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
192         if (TTYStateIsValid())
193             tcsetattr (fd, TCSANOW, m_termios_ap.get());
194 #endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
195
196 #ifndef LLDB_DISABLE_POSIX
197         if (ProcessGroupIsValid())
198         {
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);
206         }
207 #endif
208         return true;
209     }
210     return false;
211 }
212
213
214
215
216 //----------------------------------------------------------------------
217 // Returns true if this object has valid saved TTY state settings
218 // that can be used to restore a previous state.
219 //----------------------------------------------------------------------
220 bool
221 TerminalState::IsValid() const
222 {
223     return m_tty.FileDescriptorIsValid () && (TFlagsIsValid() || TTYStateIsValid());
224 }
225
226 //----------------------------------------------------------------------
227 // Returns true if m_tflags is valid
228 //----------------------------------------------------------------------
229 bool
230 TerminalState::TFlagsIsValid() const
231 {
232     return m_tflags != -1;
233 }
234
235 //----------------------------------------------------------------------
236 // Returns true if m_ttystate is valid
237 //----------------------------------------------------------------------
238 bool
239 TerminalState::TTYStateIsValid() const
240 {
241 #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
242     return m_termios_ap.get() != 0;
243 #else
244     return false;
245 #endif
246 }
247
248 //----------------------------------------------------------------------
249 // Returns true if m_process_group is valid
250 //----------------------------------------------------------------------
251 bool
252 TerminalState::ProcessGroupIsValid() const
253 {
254     return static_cast<int32_t>(m_process_group) != -1;
255 }
256
257 //------------------------------------------------------------------
258 // Constructor
259 //------------------------------------------------------------------
260 TerminalStateSwitcher::TerminalStateSwitcher () :
261     m_currentState(UINT32_MAX)
262 {
263 }
264
265 //------------------------------------------------------------------
266 // Destructor
267 //------------------------------------------------------------------
268 TerminalStateSwitcher::~TerminalStateSwitcher ()
269 {
270 }
271
272 //------------------------------------------------------------------
273 // Returns the number of states that this switcher contains
274 //------------------------------------------------------------------
275 uint32_t
276 TerminalStateSwitcher::GetNumberOfStates() const
277 {
278     return llvm::array_lengthof(m_ttystates);
279 }
280
281 //------------------------------------------------------------------
282 // Restore the state at index "idx".
283 //
284 // Returns true if the restore was successful, false otherwise.
285 //------------------------------------------------------------------
286 bool
287 TerminalStateSwitcher::Restore (uint32_t idx) const
288 {
289     const uint32_t num_states = GetNumberOfStates();
290     if (idx >= num_states)
291         return false;
292
293     // See if we already are in this state?
294     if (m_currentState < num_states && (idx == m_currentState) && m_ttystates[idx].IsValid())
295         return true;
296
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())
300     {
301         m_currentState = idx;
302         return true;
303     }
304
305     // We failed to set the state. The tty state was invalid or not
306     // initialized.
307     return false;
308 }
309
310 //------------------------------------------------------------------
311 // Save the state at index "idx" for file descriptor "fd" and
312 // save the process group if requested.
313 //
314 // Returns true if the restore was successful, false otherwise.
315 //------------------------------------------------------------------
316 bool
317 TerminalStateSwitcher::Save (uint32_t idx, int fd, bool save_process_group)
318 {
319     const uint32_t num_states = GetNumberOfStates();
320     if (idx < num_states)
321         return m_ttystates[idx].Save(fd, save_process_group);
322     return false;
323 }
324
325