blob: a553ff67fb6a1bfae8e1c05b098157f2089c85bc [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
Caroline Ticefe1bdf22011-05-04 16:44:57 +000032// Printing the following string causes libedit to back up to the beginning of the line & blank it out.
33const char undo_prompt_string[4] = { (char) 13, (char) 27, (char) 91, (char) 75};
34
Chris Lattner30fdc8d2010-06-08 16:52:24 +000035static const char*
36el_prompt(EditLine *el)
37{
38 PromptMap::const_iterator pos = g_prompt_map.find (el);
39 if (pos == g_prompt_map.end())
40 return g_default_prompt;
41 return pos->second.c_str();
42}
43
44const char *
45IOChannel::GetPrompt ()
46{
47 PromptMap::const_iterator pos = g_prompt_map.find (m_edit_line);
48 if (pos == g_prompt_map.end())
49 return g_default_prompt;
50 return pos->second.c_str();
51}
52
Jim Ingham6d10c172012-06-01 01:03:40 +000053bool
54IOChannel::EditLineHasCharacters ()
55{
56 const LineInfo *line_info = el_line(m_edit_line);
57 if (line_info)
58 return line_info->cursor != line_info->buffer;
59 else
60 return false;
61}
62
63
Johnny Chenfd02a892012-05-09 21:03:07 +000064void
65IOChannel::EraseCharsBeforeCursor ()
66{
67 const LineInfo *line_info = el_line(m_edit_line);
68 el_deletestr(m_edit_line, line_info->cursor - line_info->buffer);
69}
70
Chris Lattner30fdc8d2010-06-08 16:52:24 +000071unsigned char
72IOChannel::ElCompletionFn (EditLine *e, int ch)
73{
74 IOChannel *io_channel;
75 if (el_get(e, EL_CLIENTDATA, &io_channel) == 0)
76 {
77 return io_channel->HandleCompletion (e, ch);
78 }
79 else
80 {
81 return CC_ERROR;
82 }
83}
84
85unsigned char
86IOChannel::HandleCompletion (EditLine *e, int ch)
87{
88 assert (e == m_edit_line);
89
90 const LineInfo *line_info = el_line(m_edit_line);
91 SBStringList completions;
Greg Claytonc982c762010-07-09 20:39:50 +000092 int page_size = 40;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000093
Greg Clayton66111032010-06-23 01:19:29 +000094 int num_completions = m_driver->GetDebugger().GetCommandInterpreter().HandleCompletion (line_info->buffer,
95 line_info->cursor,
96 line_info->lastchar,
97 0,
98 -1,
99 completions);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000100
101 if (num_completions == -1)
102 {
103 el_insertstr (m_edit_line, m_completion_key);
104 return CC_REDISPLAY;
105 }
Jim Inghama5a97eb2011-07-12 03:12:18 +0000106 else if (num_completions == -2)
107 {
108 el_deletestr (m_edit_line, line_info->cursor - line_info->buffer);
109 el_insertstr (m_edit_line, completions.GetStringAtIndex(0));
110 return CC_REDISPLAY;
111 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000112
113 // If we get a longer match display that first.
114 const char *completion_str = completions.GetStringAtIndex(0);
115 if (completion_str != NULL && *completion_str != '\0')
116 {
117 el_insertstr (m_edit_line, completion_str);
118 return CC_REDISPLAY;
119 }
120
121 if (num_completions > 1)
122 {
123 const char *comment = "\nAvailable completions:";
124
125 int num_elements = num_completions + 1;
Caroline Tice969ed3d2011-05-02 20:41:46 +0000126 OutWrite(comment, strlen (comment), NO_ASYNC);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000127 if (num_completions < page_size)
128 {
129 for (int i = 1; i < num_elements; i++)
130 {
Greg Claytonb1320972010-07-14 00:18:15 +0000131 completion_str = completions.GetStringAtIndex(i);
Caroline Tice969ed3d2011-05-02 20:41:46 +0000132 OutWrite("\n\t", 2, NO_ASYNC);
133 OutWrite(completion_str, strlen (completion_str), NO_ASYNC);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000134 }
Caroline Tice969ed3d2011-05-02 20:41:46 +0000135 OutWrite ("\n", 1, NO_ASYNC);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000136 }
137 else
138 {
139 int cur_pos = 1;
140 char reply;
141 int got_char;
142 while (cur_pos < num_elements)
143 {
144 int endpoint = cur_pos + page_size;
145 if (endpoint > num_elements)
146 endpoint = num_elements;
147 for (; cur_pos < endpoint; cur_pos++)
148 {
Greg Claytonb1320972010-07-14 00:18:15 +0000149 completion_str = completions.GetStringAtIndex(cur_pos);
Caroline Tice969ed3d2011-05-02 20:41:46 +0000150 OutWrite("\n\t", 2, NO_ASYNC);
151 OutWrite(completion_str, strlen (completion_str), NO_ASYNC);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000152 }
153
154 if (cur_pos >= num_elements)
155 {
Caroline Tice969ed3d2011-05-02 20:41:46 +0000156 OutWrite("\n", 1, NO_ASYNC);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000157 break;
158 }
159
Caroline Tice969ed3d2011-05-02 20:41:46 +0000160 OutWrite("\nMore (Y/n/a): ", strlen ("\nMore (Y/n/a): "), NO_ASYNC);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000161 reply = 'n';
162 got_char = el_getc(m_edit_line, &reply);
163 if (got_char == -1 || reply == 'n')
164 break;
165 if (reply == 'a')
166 page_size = num_elements - cur_pos;
167 }
168 }
169
170 }
171
172 if (num_completions == 0)
173 return CC_REFRESH_BEEP;
174 else
175 return CC_REDISPLAY;
176}
177
178IOChannel::IOChannel
179(
Caroline Tice969ed3d2011-05-02 20:41:46 +0000180 FILE *editline_in,
181 FILE *editline_out,
182 FILE *out,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000183 FILE *err,
184 Driver *driver
185) :
186 SBBroadcaster ("IOChannel"),
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000187 m_output_mutex (),
188 m_enter_elgets_time (),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000189 m_driver (driver),
190 m_read_thread (LLDB_INVALID_HOST_THREAD),
191 m_read_thread_should_exit (false),
192 m_out_file (out),
193 m_err_file (err),
Greg Claytonc982c762010-07-09 20:39:50 +0000194 m_command_queue (),
195 m_completion_key ("\t"),
Caroline Tice969ed3d2011-05-02 20:41:46 +0000196 m_edit_line (::el_init (SBHostOS::GetProgramFileSpec().GetFilename(), editline_in, editline_out, editline_out)),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000197 m_history (history_init()),
Greg Claytonc982c762010-07-09 20:39:50 +0000198 m_history_event(),
Caroline Tice969ed3d2011-05-02 20:41:46 +0000199 m_getting_command (false),
200 m_expecting_prompt (false),
Caroline Tice86a73f92011-05-03 20:53:11 +0000201 m_prompt_str (),
202 m_refresh_request_pending (false)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000203{
204 assert (m_edit_line);
205 ::el_set (m_edit_line, EL_PROMPT, el_prompt);
206 ::el_set (m_edit_line, EL_EDITOR, "emacs");
207 ::el_set (m_edit_line, EL_HIST, history, m_history);
208
Caroline Tice0de8d452011-05-04 21:39:02 +0000209 el_set (m_edit_line, EL_ADDFN, "lldb_complete",
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000210 "LLDB completion function",
211 IOChannel::ElCompletionFn);
Caroline Tice0de8d452011-05-04 21:39:02 +0000212 el_set (m_edit_line, EL_BIND, m_completion_key, "lldb_complete", NULL);
213 el_set (m_edit_line, EL_BIND, "^r", "em-inc-search-prev", NULL); // Cycle through backwards search, entering string
Johnny Chen66b7c592012-05-05 04:44:12 +0000214 el_set (m_edit_line, EL_BIND, "^w", "ed-delete-prev-word", NULL); // Delete previous word, behave like bash does.
Sean Callanan9690a412012-07-11 22:55:32 +0000215 el_set (m_edit_line, EL_BIND, "\e[3~", "ed-delete-next-char", NULL); // Fix the delete key.
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000216 el_set (m_edit_line, EL_CLIENTDATA, this);
217
Johnny Chen5a4b4b82012-05-07 18:18:08 +0000218 // Source $PWD/.editrc then $HOME/.editrc
219 ::el_source (m_edit_line, NULL);
220
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000221 assert (m_history);
222 ::history (m_history, &m_history_event, H_SETSIZE, 800);
223 ::history (m_history, &m_history_event, H_SETUNIQUE, 1);
224 // Load history
225 HistorySaveLoad (false);
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000226
227 // Set up mutex to make sure OutErr, OutWrite and RefreshPrompt do not interfere
228 // with each other when writing.
229
230 int error;
231 ::pthread_mutexattr_t attr;
232 error = ::pthread_mutexattr_init (&attr);
233 assert (error == 0);
234 error = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
235 assert (error == 0);
236 error = ::pthread_mutex_init (&m_output_mutex, &attr);
237 assert (error == 0);
238 error = ::pthread_mutexattr_destroy (&attr);
239 assert (error == 0);
240
241 // Initialize time that ::el_gets was last called.
242
243 m_enter_elgets_time.tv_sec = 0;
244 m_enter_elgets_time.tv_usec = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000245}
246
247IOChannel::~IOChannel ()
248{
249 // Save history
250 HistorySaveLoad (true);
251
252 if (m_history != NULL)
253 {
254 ::history_end (m_history);
255 m_history = NULL;
256 }
257
258 if (m_edit_line != NULL)
259 {
260 ::el_end (m_edit_line);
261 m_edit_line = NULL;
262 }
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000263
264 ::pthread_mutex_destroy (&m_output_mutex);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000265}
266
267void
268IOChannel::HistorySaveLoad (bool save)
269{
270 if (m_history != NULL)
271 {
272 char history_path[PATH_MAX];
Johnny Chen23fd10c2010-08-27 22:35:26 +0000273 ::snprintf (history_path, sizeof(history_path), "~/.%s-history", SBHostOS::GetProgramFileSpec().GetFilename());
Greg Claytonc982c762010-07-09 20:39:50 +0000274 if ((size_t)SBFileSpec::ResolvePath (history_path, history_path, sizeof(history_path)) < sizeof(history_path) - 1)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000275 {
276 const char *path_ptr = history_path;
277 if (save)
278 ::history (m_history, &m_history_event, H_SAVE, path_ptr);
279 else
280 ::history (m_history, &m_history_event, H_LOAD, path_ptr);
281 }
282 }
283}
284
Caroline Tice969ed3d2011-05-02 20:41:46 +0000285void
286IOChannel::LibeditOutputBytesReceived (void *baton, const void *src, size_t src_len)
287{
288 // Make this a member variable.
289 // static std::string prompt_str;
290 IOChannel *io_channel = (IOChannel *) baton;
Caroline Tice86a73f92011-05-03 20:53:11 +0000291 IOLocker locker (io_channel->m_output_mutex);
Caroline Tice969ed3d2011-05-02 20:41:46 +0000292 const char *bytes = (const char *) src;
293
294 if (io_channel->IsGettingCommand() && io_channel->m_expecting_prompt)
295 {
296 io_channel->m_prompt_str.append (bytes, src_len);
297 // Log this to make sure the prompt is really what you think it is.
298 if (io_channel->m_prompt_str.find (el_prompt(io_channel->m_edit_line)) == 0)
299 {
300 io_channel->m_expecting_prompt = false;
Caroline Tice86a73f92011-05-03 20:53:11 +0000301 io_channel->m_refresh_request_pending = false;
Caroline Tice969ed3d2011-05-02 20:41:46 +0000302 io_channel->OutWrite (io_channel->m_prompt_str.c_str(),
303 io_channel->m_prompt_str.size(), NO_ASYNC);
304 io_channel->m_prompt_str.clear();
305 }
Caroline Tice969ed3d2011-05-02 20:41:46 +0000306 }
307 else
308 {
309 if (io_channel->m_prompt_str.size() > 0)
310 io_channel->m_prompt_str.clear();
Caroline Tice86a73f92011-05-03 20:53:11 +0000311 std::string tmp_str (bytes, src_len);
312 if (tmp_str.find (el_prompt (io_channel->m_edit_line)) == 0)
313 io_channel->m_refresh_request_pending = false;
Caroline Tice969ed3d2011-05-02 20:41:46 +0000314 io_channel->OutWrite (bytes, src_len, NO_ASYNC);
315 }
316}
317
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000318bool
319IOChannel::LibeditGetInput (std::string &new_line)
320{
321 if (m_edit_line != NULL)
322 {
323 int line_len = 0;
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000324
325 // Set boolean indicating whether or not el_gets is trying to get input (i.e. whether or not to attempt
326 // to refresh the prompt after writing data).
327 SetGettingCommand (true);
Caroline Tice969ed3d2011-05-02 20:41:46 +0000328 m_expecting_prompt = true;
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000329
330 // Call el_gets to prompt the user and read the user's input.
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000331 const char *line = ::el_gets (m_edit_line, &line_len);
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000332
333 // Re-set the boolean indicating whether or not el_gets is trying to get input.
334 SetGettingCommand (false);
335
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000336 if (line)
337 {
338 // strip any newlines off the end of the string...
339 while (line_len > 0 && (line[line_len - 1] == '\n' || line[line_len - 1] == '\r'))
340 --line_len;
341 if (line_len > 0)
342 {
343 ::history (m_history, &m_history_event, H_ENTER, line);
344 new_line.assign (line, line_len); // Omit the newline
345 }
346 else
347 {
348 // Someone just hit ENTER, return the empty string
349 new_line.clear();
350 }
351 // Return true to indicate success even if a string is empty
352 return true;
353 }
354 }
355 // Return false to indicate failure. This can happen when the file handle
356 // is closed (EOF).
357 new_line.clear();
358 return false;
359}
360
361void *
362IOChannel::IOReadThread (void *ptr)
363{
364 IOChannel *myself = static_cast<IOChannel *> (ptr);
365 myself->Run();
366 return NULL;
367}
368
369void
370IOChannel::Run ()
371{
372 SBListener listener("IOChannel::Run");
373 std::string new_line;
374
Greg Clayton66111032010-06-23 01:19:29 +0000375 SBBroadcaster interpreter_broadcaster (m_driver->GetDebugger().GetCommandInterpreter().GetBroadcaster());
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000376 listener.StartListeningForEvents (interpreter_broadcaster,
377 SBCommandInterpreter::eBroadcastBitResetPrompt |
378 SBCommandInterpreter::eBroadcastBitThreadShouldExit |
Caroline Tice86a73f92011-05-03 20:53:11 +0000379 SBCommandInterpreter::eBroadcastBitQuitCommandReceived);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000380
381 listener.StartListeningForEvents (*this,
382 IOChannel::eBroadcastBitThreadShouldExit);
383
384 listener.StartListeningForEvents (*m_driver,
385 Driver::eBroadcastBitReadyForInput |
386 Driver::eBroadcastBitThreadShouldExit);
387
388 // Let anyone know that the IO channel is up and listening and ready for events
389 BroadcastEventByType (eBroadcastBitThreadDidStart);
390 bool done = false;
391 while (!done)
392 {
393 SBEvent event;
394
395 listener.WaitForEvent (UINT32_MAX, event);
396 if (!event.IsValid())
397 continue;
398
399 const uint32_t event_type = event.GetType();
400
401 if (event.GetBroadcaster().IsValid())
402 {
403 if (event.BroadcasterMatchesPtr (m_driver))
404 {
405 if (event_type & Driver::eBroadcastBitReadyForInput)
406 {
407 std::string line;
408
409 if (CommandQueueIsEmpty())
410 {
411 if (LibeditGetInput(line) == false)
412 {
413 // EOF or some other file error occurred
414 done = true;
415 continue;
416 }
417 }
418 else
419 {
420 GetCommandFromQueue (line);
421 }
422
423 // TO BE DONE: FIGURE OUT WHICH COMMANDS SHOULD NOT BE REPEATED IF USER PRESSES PLAIN 'RETURN'
424 // AND TAKE CARE OF THAT HERE.
425
426 SBEvent line_event(IOChannel::eBroadcastBitHasUserInput,
427 line.c_str(),
428 line.size());
429 BroadcastEvent (line_event);
430 }
431 else if (event_type & Driver::eBroadcastBitThreadShouldExit)
432 {
433 done = true;
Johnny Chen25f3a3c2011-08-10 22:06:24 +0000434 continue;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000435 }
436 }
437 else if (event.BroadcasterMatchesRef (interpreter_broadcaster))
438 {
439 switch (event_type)
440 {
441 case SBCommandInterpreter::eBroadcastBitResetPrompt:
442 {
443 const char *new_prompt = SBEvent::GetCStringFromEvent (event);
444 if (new_prompt)
445 g_prompt_map[m_edit_line] = new_prompt;
446 }
447 break;
448
449 case SBCommandInterpreter::eBroadcastBitThreadShouldExit:
450 case SBCommandInterpreter::eBroadcastBitQuitCommandReceived:
451 done = true;
452 break;
453 }
454 }
455 else if (event.BroadcasterMatchesPtr (this))
456 {
457 if (event_type & IOChannel::eBroadcastBitThreadShouldExit)
458 {
459 done = true;
Johnny Chen25f3a3c2011-08-10 22:06:24 +0000460 continue;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000461 }
462 }
463 }
464 }
465 BroadcastEventByType (IOChannel::eBroadcastBitThreadDidExit);
466 m_driver = NULL;
467 m_read_thread = NULL;
468}
469
470bool
471IOChannel::Start ()
472{
Greg Clayton2da6d492011-02-08 01:34:25 +0000473 if (IS_VALID_LLDB_HOST_THREAD(m_read_thread))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000474 return true;
475
476 m_read_thread = SBHostOS::ThreadCreate ("<lldb.driver.commandline_io>", IOChannel::IOReadThread, this,
477 NULL);
478
Greg Clayton2da6d492011-02-08 01:34:25 +0000479 return (IS_VALID_LLDB_HOST_THREAD(m_read_thread));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000480}
481
482bool
483IOChannel::Stop ()
484{
Greg Clayton2da6d492011-02-08 01:34:25 +0000485 if (!IS_VALID_LLDB_HOST_THREAD(m_read_thread))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000486 return true;
487
488 BroadcastEventByType (eBroadcastBitThreadShouldExit);
489
490 // Don't call Host::ThreadCancel since el_gets won't respond to this
491 // function call -- the thread will just die and all local variables in
492 // IOChannel::Run() won't get destructed down which is bad since there is
493 // a local listener holding onto broadcasters... To ensure proper shutdown,
494 // a ^D (control-D) sequence (0x04) should be written to other end of the
495 // the "in" file handle that was passed into the contructor as closing the
496 // file handle doesn't seem to make el_gets() exit....
497 return SBHostOS::ThreadJoin (m_read_thread, NULL, NULL);
498}
499
500void
501IOChannel::RefreshPrompt ()
502{
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000503 // If we are not in the middle of getting input from the user, there is no need to
504 // refresh the prompt.
Caroline Tice86a73f92011-05-03 20:53:11 +0000505 IOLocker locker (m_output_mutex);
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000506 if (! IsGettingCommand())
507 return;
508
Caroline Tice969ed3d2011-05-02 20:41:46 +0000509 // If we haven't finished writing the prompt, there's no need to refresh it.
510 if (m_expecting_prompt)
511 return;
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000512
Caroline Tice86a73f92011-05-03 20:53:11 +0000513 if (m_refresh_request_pending)
514 return;
515
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000516 ::el_set (m_edit_line, EL_REFRESH);
Caroline Tice86a73f92011-05-03 20:53:11 +0000517 m_refresh_request_pending = true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000518}
519
520void
Caroline Tice969ed3d2011-05-02 20:41:46 +0000521IOChannel::OutWrite (const char *buffer, size_t len, bool asynchronous)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000522{
523 if (len == 0)
524 return;
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000525
Jason Molenda7efc7e92011-08-12 02:40:17 +0000526 // We're in the process of exiting -- IOChannel::Run() has already completed
527 // and set m_driver to NULL - it is time for us to leave now. We might not
528 // print the final ^D to stdout in this case. We need to do some re-work on
529 // how the I/O streams are managed at some point.
530 if (m_driver == NULL)
531 {
532 return;
533 }
534
Caroline Tice969ed3d2011-05-02 20:41:46 +0000535 // Use the mutex to make sure OutWrite and ErrWrite do not interfere with each other's output.
536 IOLocker locker (m_output_mutex);
Caroline Tice9088b062011-05-09 23:06:58 +0000537 if (m_driver->EditlineReaderIsTop() && asynchronous)
Caroline Ticefe1bdf22011-05-04 16:44:57 +0000538 ::fwrite (undo_prompt_string, 1, 4, m_out_file);
Caroline Tice969ed3d2011-05-02 20:41:46 +0000539 ::fwrite (buffer, 1, len, m_out_file);
540 if (asynchronous)
541 m_driver->GetDebugger().NotifyTopInputReader (eInputReaderAsynchronousOutputWritten);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000542}
543
544void
Caroline Tice969ed3d2011-05-02 20:41:46 +0000545IOChannel::ErrWrite (const char *buffer, size_t len, bool asynchronous)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000546{
547 if (len == 0)
548 return;
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000549
Caroline Tice969ed3d2011-05-02 20:41:46 +0000550 // Use the mutex to make sure OutWrite and ErrWrite do not interfere with each other's output.
551 IOLocker locker (m_output_mutex);
552 if (asynchronous)
Caroline Ticefe1bdf22011-05-04 16:44:57 +0000553 ::fwrite (undo_prompt_string, 1, 4, m_err_file);
Caroline Tice969ed3d2011-05-02 20:41:46 +0000554 ::fwrite (buffer, 1, len, m_err_file);
555 if (asynchronous)
556 m_driver->GetDebugger().NotifyTopInputReader (eInputReaderAsynchronousOutputWritten);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000557}
558
559void
560IOChannel::AddCommandToQueue (const char *command)
561{
562 m_command_queue.push (std::string(command));
563}
564
565bool
566IOChannel::GetCommandFromQueue (std::string &cmd)
567{
568 if (m_command_queue.empty())
569 return false;
570 cmd.swap(m_command_queue.front());
571 m_command_queue.pop ();
572 return true;
573}
574
575int
576IOChannel::CommandQueueSize () const
577{
578 return m_command_queue.size();
579}
580
581void
582IOChannel::ClearCommandQueue ()
583{
584 while (!m_command_queue.empty())
585 m_command_queue.pop();
586}
587
588bool
589IOChannel::CommandQueueIsEmpty () const
590{
591 return m_command_queue.empty();
592}
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000593
594bool
595IOChannel::IsGettingCommand () const
596{
597 return m_getting_command;
598}
599
600void
601IOChannel::SetGettingCommand (bool new_value)
602{
603 m_getting_command = new_value;
604}
605
Caroline Ticebd13b8d2010-09-29 18:35:42 +0000606IOLocker::IOLocker (pthread_mutex_t &mutex) :
607 m_mutex_ptr (&mutex)
608{
609 if (m_mutex_ptr)
610 ::pthread_mutex_lock (m_mutex_ptr);
611
612}
613
614IOLocker::~IOLocker ()
615{
616 if (m_mutex_ptr)
617 ::pthread_mutex_unlock (m_mutex_ptr);
618}