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