blob: 4db5affb11192d18a6653465244f48b5cc52b3c6 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- IOChannel.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 "IOChannel.h"
11
12#include <map>
13
Eli Friedmana382d472010-06-09 09:50:17 +000014#include "lldb/API/SBCommandInterpreter.h"
15#include "lldb/API/SBDebugger.h"
16#include "lldb/API/SBError.h"
17#include "lldb/API/SBEvent.h"
18#include "lldb/API/SBFileSpec.h"
19#include "lldb/API/SBHostOS.h"
20#include "lldb/API/SBListener.h"
21#include "lldb/API/SBStringList.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000022
Eli Friedman07b16272010-06-09 19:11:30 +000023#include <string.h>
24#include <limits.h>
25
Chris Lattner30fdc8d2010-06-08 16:52:24 +000026using namespace lldb;
27
28typedef std::map<EditLine *, std::string> PromptMap;
29const char *g_default_prompt = "(lldb) ";
30PromptMap g_prompt_map;
31
32static const char*
33el_prompt(EditLine *el)
34{
35 PromptMap::const_iterator pos = g_prompt_map.find (el);
36 if (pos == g_prompt_map.end())
37 return g_default_prompt;
38 return pos->second.c_str();
39}
40
41const char *
42IOChannel::GetPrompt ()
43{
44 PromptMap::const_iterator pos = g_prompt_map.find (m_edit_line);
45 if (pos == g_prompt_map.end())
46 return g_default_prompt;
47 return pos->second.c_str();
48}
49
50unsigned char
51IOChannel::ElCompletionFn (EditLine *e, int ch)
52{
53 IOChannel *io_channel;
54 if (el_get(e, EL_CLIENTDATA, &io_channel) == 0)
55 {
56 return io_channel->HandleCompletion (e, ch);
57 }
58 else
59 {
60 return CC_ERROR;
61 }
62}
63
64unsigned char
65IOChannel::HandleCompletion (EditLine *e, int ch)
66{
67 assert (e == m_edit_line);
68
69 const LineInfo *line_info = el_line(m_edit_line);
70 SBStringList completions;
Greg Claytonc982c762010-07-09 20:39:50 +000071 int page_size = 40;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000072
Greg Clayton66111032010-06-23 01:19:29 +000073 int num_completions = m_driver->GetDebugger().GetCommandInterpreter().HandleCompletion (line_info->buffer,
74 line_info->cursor,
75 line_info->lastchar,
76 0,
77 -1,
78 completions);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000079
80 if (num_completions == -1)
81 {
82 el_insertstr (m_edit_line, m_completion_key);
83 return CC_REDISPLAY;
84 }
85
86 // If we get a longer match display that first.
87 const char *completion_str = completions.GetStringAtIndex(0);
88 if (completion_str != NULL && *completion_str != '\0')
89 {
90 el_insertstr (m_edit_line, completion_str);
91 return CC_REDISPLAY;
92 }
93
94 if (num_completions > 1)
95 {
96 const char *comment = "\nAvailable completions:";
97
98 int num_elements = num_completions + 1;
Caroline Tice969ed3d2011-05-02 20:41:46 +000099 OutWrite(comment, strlen (comment), NO_ASYNC);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000100 if (num_completions < page_size)
101 {
102 for (int i = 1; i < num_elements; i++)
103 {
Greg Claytonb1320972010-07-14 00:18:15 +0000104 completion_str = completions.GetStringAtIndex(i);
Caroline Tice969ed3d2011-05-02 20:41:46 +0000105 OutWrite("\n\t", 2, NO_ASYNC);
106 OutWrite(completion_str, strlen (completion_str), NO_ASYNC);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000107 }
Caroline Tice969ed3d2011-05-02 20:41:46 +0000108 OutWrite ("\n", 1, NO_ASYNC);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000109 }
110 else
111 {
112 int cur_pos = 1;
113 char reply;
114 int got_char;
115 while (cur_pos < num_elements)
116 {
117 int endpoint = cur_pos + page_size;
118 if (endpoint > num_elements)
119 endpoint = num_elements;
120 for (; cur_pos < endpoint; cur_pos++)
121 {
Greg Claytonb1320972010-07-14 00:18:15 +0000122 completion_str = completions.GetStringAtIndex(cur_pos);
Caroline Tice969ed3d2011-05-02 20:41:46 +0000123 OutWrite("\n\t", 2, NO_ASYNC);
124 OutWrite(completion_str, strlen (completion_str), NO_ASYNC);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000125 }
126
127 if (cur_pos >= num_elements)
128 {
Caroline Tice969ed3d2011-05-02 20:41:46 +0000129 OutWrite("\n", 1, NO_ASYNC);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000130 break;
131 }
132
Caroline Tice969ed3d2011-05-02 20:41:46 +0000133 OutWrite("\nMore (Y/n/a): ", strlen ("\nMore (Y/n/a): "), NO_ASYNC);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000134 reply = 'n';
135 got_char = el_getc(m_edit_line, &reply);
136 if (got_char == -1 || reply == 'n')
137 break;
138 if (reply == 'a')
139 page_size = num_elements - cur_pos;
140 }
141 }
142
143 }
144
145 if (num_completions == 0)
146 return CC_REFRESH_BEEP;
147 else
148 return CC_REDISPLAY;
149}
150
151IOChannel::IOChannel
152(
Caroline Tice969ed3d2011-05-02 20:41:46 +0000153 FILE *editline_in,
154 FILE *editline_out,
155 FILE *out,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000156 FILE *err,
157 Driver *driver
158) :
159 SBBroadcaster ("IOChannel"),
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000160 m_output_mutex (),
161 m_enter_elgets_time (),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000162 m_driver (driver),
163 m_read_thread (LLDB_INVALID_HOST_THREAD),
164 m_read_thread_should_exit (false),
165 m_out_file (out),
166 m_err_file (err),
Greg Claytonc982c762010-07-09 20:39:50 +0000167 m_command_queue (),
168 m_completion_key ("\t"),
Caroline Tice969ed3d2011-05-02 20:41:46 +0000169 m_edit_line (::el_init (SBHostOS::GetProgramFileSpec().GetFilename(), editline_in, editline_out, editline_out)),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000170 m_history (history_init()),
Greg Claytonc982c762010-07-09 20:39:50 +0000171 m_history_event(),
Caroline Tice969ed3d2011-05-02 20:41:46 +0000172 m_getting_command (false),
173 m_expecting_prompt (false),
Caroline Tice86a73f92011-05-03 20:53:11 +0000174 m_prompt_str (),
175 m_refresh_request_pending (false)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000176{
177 assert (m_edit_line);
178 ::el_set (m_edit_line, EL_PROMPT, el_prompt);
179 ::el_set (m_edit_line, EL_EDITOR, "emacs");
180 ::el_set (m_edit_line, EL_HIST, history, m_history);
181
182 // Source $PWD/.editrc then $HOME/.editrc
183 ::el_source (m_edit_line, NULL);
184
185 el_set(m_edit_line, EL_ADDFN, "lldb_complete",
186 "LLDB completion function",
187 IOChannel::ElCompletionFn);
188 el_set(m_edit_line, EL_BIND, m_completion_key, "lldb_complete", NULL);
189 el_set (m_edit_line, EL_CLIENTDATA, this);
190
191 assert (m_history);
192 ::history (m_history, &m_history_event, H_SETSIZE, 800);
193 ::history (m_history, &m_history_event, H_SETUNIQUE, 1);
194 // Load history
195 HistorySaveLoad (false);
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000196
197 // Set up mutex to make sure OutErr, OutWrite and RefreshPrompt do not interfere
198 // with each other when writing.
199
200 int error;
201 ::pthread_mutexattr_t attr;
202 error = ::pthread_mutexattr_init (&attr);
203 assert (error == 0);
204 error = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
205 assert (error == 0);
206 error = ::pthread_mutex_init (&m_output_mutex, &attr);
207 assert (error == 0);
208 error = ::pthread_mutexattr_destroy (&attr);
209 assert (error == 0);
210
211 // Initialize time that ::el_gets was last called.
212
213 m_enter_elgets_time.tv_sec = 0;
214 m_enter_elgets_time.tv_usec = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000215}
216
217IOChannel::~IOChannel ()
218{
219 // Save history
220 HistorySaveLoad (true);
221
222 if (m_history != NULL)
223 {
224 ::history_end (m_history);
225 m_history = NULL;
226 }
227
228 if (m_edit_line != NULL)
229 {
230 ::el_end (m_edit_line);
231 m_edit_line = NULL;
232 }
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000233
234 ::pthread_mutex_destroy (&m_output_mutex);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000235}
236
237void
238IOChannel::HistorySaveLoad (bool save)
239{
240 if (m_history != NULL)
241 {
242 char history_path[PATH_MAX];
Johnny Chen23fd10c2010-08-27 22:35:26 +0000243 ::snprintf (history_path, sizeof(history_path), "~/.%s-history", SBHostOS::GetProgramFileSpec().GetFilename());
Greg Claytonc982c762010-07-09 20:39:50 +0000244 if ((size_t)SBFileSpec::ResolvePath (history_path, history_path, sizeof(history_path)) < sizeof(history_path) - 1)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000245 {
246 const char *path_ptr = history_path;
247 if (save)
248 ::history (m_history, &m_history_event, H_SAVE, path_ptr);
249 else
250 ::history (m_history, &m_history_event, H_LOAD, path_ptr);
251 }
252 }
253}
254
Caroline Tice969ed3d2011-05-02 20:41:46 +0000255void
256IOChannel::LibeditOutputBytesReceived (void *baton, const void *src, size_t src_len)
257{
258 // Make this a member variable.
259 // static std::string prompt_str;
260 IOChannel *io_channel = (IOChannel *) baton;
Caroline Tice86a73f92011-05-03 20:53:11 +0000261 IOLocker locker (io_channel->m_output_mutex);
Caroline Tice969ed3d2011-05-02 20:41:46 +0000262 const char *bytes = (const char *) src;
263
264 if (io_channel->IsGettingCommand() && io_channel->m_expecting_prompt)
265 {
266 io_channel->m_prompt_str.append (bytes, src_len);
267 // Log this to make sure the prompt is really what you think it is.
268 if (io_channel->m_prompt_str.find (el_prompt(io_channel->m_edit_line)) == 0)
269 {
270 io_channel->m_expecting_prompt = false;
Caroline Tice86a73f92011-05-03 20:53:11 +0000271 io_channel->m_refresh_request_pending = false;
Caroline Tice969ed3d2011-05-02 20:41:46 +0000272 io_channel->OutWrite (io_channel->m_prompt_str.c_str(),
273 io_channel->m_prompt_str.size(), NO_ASYNC);
274 io_channel->m_prompt_str.clear();
275 }
Caroline Tice969ed3d2011-05-02 20:41:46 +0000276 }
277 else
278 {
279 if (io_channel->m_prompt_str.size() > 0)
280 io_channel->m_prompt_str.clear();
Caroline Tice86a73f92011-05-03 20:53:11 +0000281 std::string tmp_str (bytes, src_len);
282 if (tmp_str.find (el_prompt (io_channel->m_edit_line)) == 0)
283 io_channel->m_refresh_request_pending = false;
Caroline Tice969ed3d2011-05-02 20:41:46 +0000284 io_channel->OutWrite (bytes, src_len, NO_ASYNC);
285 }
286}
287
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000288bool
289IOChannel::LibeditGetInput (std::string &new_line)
290{
291 if (m_edit_line != NULL)
292 {
293 int line_len = 0;
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000294
295 // Set boolean indicating whether or not el_gets is trying to get input (i.e. whether or not to attempt
296 // to refresh the prompt after writing data).
297 SetGettingCommand (true);
Caroline Tice969ed3d2011-05-02 20:41:46 +0000298 m_expecting_prompt = true;
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000299
300 // Call el_gets to prompt the user and read the user's input.
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000301 const char *line = ::el_gets (m_edit_line, &line_len);
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000302
303 // Re-set the boolean indicating whether or not el_gets is trying to get input.
304 SetGettingCommand (false);
305
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000306 if (line)
307 {
308 // strip any newlines off the end of the string...
309 while (line_len > 0 && (line[line_len - 1] == '\n' || line[line_len - 1] == '\r'))
310 --line_len;
311 if (line_len > 0)
312 {
313 ::history (m_history, &m_history_event, H_ENTER, line);
314 new_line.assign (line, line_len); // Omit the newline
315 }
316 else
317 {
318 // Someone just hit ENTER, return the empty string
319 new_line.clear();
320 }
321 // Return true to indicate success even if a string is empty
322 return true;
323 }
324 }
325 // Return false to indicate failure. This can happen when the file handle
326 // is closed (EOF).
327 new_line.clear();
328 return false;
329}
330
331void *
332IOChannel::IOReadThread (void *ptr)
333{
334 IOChannel *myself = static_cast<IOChannel *> (ptr);
335 myself->Run();
336 return NULL;
337}
338
339void
340IOChannel::Run ()
341{
342 SBListener listener("IOChannel::Run");
343 std::string new_line;
344
Greg Clayton66111032010-06-23 01:19:29 +0000345 SBBroadcaster interpreter_broadcaster (m_driver->GetDebugger().GetCommandInterpreter().GetBroadcaster());
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000346 listener.StartListeningForEvents (interpreter_broadcaster,
347 SBCommandInterpreter::eBroadcastBitResetPrompt |
348 SBCommandInterpreter::eBroadcastBitThreadShouldExit |
Caroline Tice86a73f92011-05-03 20:53:11 +0000349 SBCommandInterpreter::eBroadcastBitQuitCommandReceived);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000350
351 listener.StartListeningForEvents (*this,
352 IOChannel::eBroadcastBitThreadShouldExit);
353
354 listener.StartListeningForEvents (*m_driver,
355 Driver::eBroadcastBitReadyForInput |
356 Driver::eBroadcastBitThreadShouldExit);
357
358 // Let anyone know that the IO channel is up and listening and ready for events
359 BroadcastEventByType (eBroadcastBitThreadDidStart);
360 bool done = false;
361 while (!done)
362 {
363 SBEvent event;
364
365 listener.WaitForEvent (UINT32_MAX, event);
366 if (!event.IsValid())
367 continue;
368
369 const uint32_t event_type = event.GetType();
370
371 if (event.GetBroadcaster().IsValid())
372 {
373 if (event.BroadcasterMatchesPtr (m_driver))
374 {
375 if (event_type & Driver::eBroadcastBitReadyForInput)
376 {
377 std::string line;
378
379 if (CommandQueueIsEmpty())
380 {
381 if (LibeditGetInput(line) == false)
382 {
383 // EOF or some other file error occurred
384 done = true;
385 continue;
386 }
387 }
388 else
389 {
390 GetCommandFromQueue (line);
391 }
392
393 // TO BE DONE: FIGURE OUT WHICH COMMANDS SHOULD NOT BE REPEATED IF USER PRESSES PLAIN 'RETURN'
394 // AND TAKE CARE OF THAT HERE.
395
396 SBEvent line_event(IOChannel::eBroadcastBitHasUserInput,
397 line.c_str(),
398 line.size());
399 BroadcastEvent (line_event);
400 }
401 else if (event_type & Driver::eBroadcastBitThreadShouldExit)
402 {
403 done = true;
404 break;
405 }
406 }
407 else if (event.BroadcasterMatchesRef (interpreter_broadcaster))
408 {
409 switch (event_type)
410 {
411 case SBCommandInterpreter::eBroadcastBitResetPrompt:
412 {
413 const char *new_prompt = SBEvent::GetCStringFromEvent (event);
414 if (new_prompt)
415 g_prompt_map[m_edit_line] = new_prompt;
416 }
417 break;
418
419 case SBCommandInterpreter::eBroadcastBitThreadShouldExit:
420 case SBCommandInterpreter::eBroadcastBitQuitCommandReceived:
421 done = true;
422 break;
423 }
424 }
425 else if (event.BroadcasterMatchesPtr (this))
426 {
427 if (event_type & IOChannel::eBroadcastBitThreadShouldExit)
428 {
429 done = true;
430 break;
431 }
432 }
433 }
434 }
435 BroadcastEventByType (IOChannel::eBroadcastBitThreadDidExit);
436 m_driver = NULL;
437 m_read_thread = NULL;
438}
439
440bool
441IOChannel::Start ()
442{
Greg Clayton2da6d492011-02-08 01:34:25 +0000443 if (IS_VALID_LLDB_HOST_THREAD(m_read_thread))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000444 return true;
445
446 m_read_thread = SBHostOS::ThreadCreate ("<lldb.driver.commandline_io>", IOChannel::IOReadThread, this,
447 NULL);
448
Greg Clayton2da6d492011-02-08 01:34:25 +0000449 return (IS_VALID_LLDB_HOST_THREAD(m_read_thread));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000450}
451
452bool
453IOChannel::Stop ()
454{
Greg Clayton2da6d492011-02-08 01:34:25 +0000455 if (!IS_VALID_LLDB_HOST_THREAD(m_read_thread))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000456 return true;
457
458 BroadcastEventByType (eBroadcastBitThreadShouldExit);
459
460 // Don't call Host::ThreadCancel since el_gets won't respond to this
461 // function call -- the thread will just die and all local variables in
462 // IOChannel::Run() won't get destructed down which is bad since there is
463 // a local listener holding onto broadcasters... To ensure proper shutdown,
464 // a ^D (control-D) sequence (0x04) should be written to other end of the
465 // the "in" file handle that was passed into the contructor as closing the
466 // file handle doesn't seem to make el_gets() exit....
467 return SBHostOS::ThreadJoin (m_read_thread, NULL, NULL);
468}
469
470void
471IOChannel::RefreshPrompt ()
472{
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000473 // If we are not in the middle of getting input from the user, there is no need to
474 // refresh the prompt.
Caroline Tice86a73f92011-05-03 20:53:11 +0000475 IOLocker locker (m_output_mutex);
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000476 if (! IsGettingCommand())
477 return;
478
Caroline Tice969ed3d2011-05-02 20:41:46 +0000479 // If we haven't finished writing the prompt, there's no need to refresh it.
480 if (m_expecting_prompt)
481 return;
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000482
Caroline Tice86a73f92011-05-03 20:53:11 +0000483 if (m_refresh_request_pending)
484 return;
485
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000486 ::el_set (m_edit_line, EL_REFRESH);
Caroline Tice86a73f92011-05-03 20:53:11 +0000487 m_refresh_request_pending = true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000488}
489
490void
Caroline Tice969ed3d2011-05-02 20:41:46 +0000491IOChannel::OutWrite (const char *buffer, size_t len, bool asynchronous)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000492{
493 if (len == 0)
494 return;
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000495
Caroline Tice969ed3d2011-05-02 20:41:46 +0000496 // Use the mutex to make sure OutWrite and ErrWrite do not interfere with each other's output.
497 IOLocker locker (m_output_mutex);
498 if (asynchronous)
499 ::fwrite ("\n", 1, 1, m_out_file);
500 ::fwrite (buffer, 1, len, m_out_file);
501 if (asynchronous)
502 m_driver->GetDebugger().NotifyTopInputReader (eInputReaderAsynchronousOutputWritten);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000503}
504
505void
Caroline Tice969ed3d2011-05-02 20:41:46 +0000506IOChannel::ErrWrite (const char *buffer, size_t len, bool asynchronous)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000507{
508 if (len == 0)
509 return;
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000510
Caroline Tice969ed3d2011-05-02 20:41:46 +0000511 // Use the mutex to make sure OutWrite and ErrWrite do not interfere with each other's output.
512 IOLocker locker (m_output_mutex);
513 if (asynchronous)
514 ::fwrite ("\n", 1, 1, m_err_file);
515 ::fwrite (buffer, 1, len, m_err_file);
516 if (asynchronous)
517 m_driver->GetDebugger().NotifyTopInputReader (eInputReaderAsynchronousOutputWritten);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000518}
519
520void
521IOChannel::AddCommandToQueue (const char *command)
522{
523 m_command_queue.push (std::string(command));
524}
525
526bool
527IOChannel::GetCommandFromQueue (std::string &cmd)
528{
529 if (m_command_queue.empty())
530 return false;
531 cmd.swap(m_command_queue.front());
532 m_command_queue.pop ();
533 return true;
534}
535
536int
537IOChannel::CommandQueueSize () const
538{
539 return m_command_queue.size();
540}
541
542void
543IOChannel::ClearCommandQueue ()
544{
545 while (!m_command_queue.empty())
546 m_command_queue.pop();
547}
548
549bool
550IOChannel::CommandQueueIsEmpty () const
551{
552 return m_command_queue.empty();
553}
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000554
555bool
556IOChannel::IsGettingCommand () const
557{
558 return m_getting_command;
559}
560
561void
562IOChannel::SetGettingCommand (bool new_value)
563{
564 m_getting_command = new_value;
565}
566
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000567IOLocker::IOLocker (pthread_mutex_t &mutex) :
568 m_mutex_ptr (&mutex)
569{
570 if (m_mutex_ptr)
571 ::pthread_mutex_lock (m_mutex_ptr);
572
573}
574
575IOLocker::~IOLocker ()
576{
577 if (m_mutex_ptr)
578 ::pthread_mutex_unlock (m_mutex_ptr);
579}