IOChannel.cpp revision abd370a4be26a5fc288ca090e80b12c1bc14ac8b
1//===-- 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
14#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"
22
23#include <string.h>
24#include <limits.h>
25
26using namespace lldb;
27
28typedef std::map<EditLine *, std::string> PromptMap;
29const char *g_default_prompt = "(lldb) ";
30PromptMap g_prompt_map;
31
32// 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
35static 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
53unsigned char
54IOChannel::ElCompletionFn (EditLine *e, int ch)
55{
56    IOChannel *io_channel;
57    if (el_get(e, EL_CLIENTDATA, &io_channel) == 0)
58    {
59        return io_channel->HandleCompletion (e, ch);
60    }
61    else
62    {
63        return CC_ERROR;
64    }
65}
66
67unsigned char
68IOChannel::HandleCompletion (EditLine *e, int ch)
69{
70    assert (e == m_edit_line);
71
72    const LineInfo *line_info  = el_line(m_edit_line);
73    SBStringList completions;
74    int page_size = 40;
75
76    int num_completions = m_driver->GetDebugger().GetCommandInterpreter().HandleCompletion (line_info->buffer,
77                                                                                            line_info->cursor,
78                                                                                            line_info->lastchar,
79                                                                                            0,
80                                                                                            -1,
81                                                                                            completions);
82
83    if (num_completions == -1)
84    {
85        el_insertstr (m_edit_line, m_completion_key);
86        return CC_REDISPLAY;
87    }
88    else if (num_completions == -2)
89    {
90        el_deletestr (m_edit_line, line_info->cursor - line_info->buffer);
91        el_insertstr (m_edit_line, completions.GetStringAtIndex(0));
92        return CC_REDISPLAY;
93    }
94
95    // If we get a longer match display that first.
96    const char *completion_str = completions.GetStringAtIndex(0);
97    if (completion_str != NULL && *completion_str != '\0')
98    {
99        el_insertstr (m_edit_line, completion_str);
100        return CC_REDISPLAY;
101    }
102
103    if (num_completions > 1)
104    {
105        const char *comment = "\nAvailable completions:";
106
107        int num_elements = num_completions + 1;
108        OutWrite(comment,  strlen (comment), NO_ASYNC);
109        if (num_completions < page_size)
110        {
111            for (int i = 1; i < num_elements; i++)
112            {
113                completion_str = completions.GetStringAtIndex(i);
114                OutWrite("\n\t", 2, NO_ASYNC);
115                OutWrite(completion_str, strlen (completion_str), NO_ASYNC);
116            }
117            OutWrite ("\n", 1, NO_ASYNC);
118        }
119        else
120        {
121            int cur_pos = 1;
122            char reply;
123            int got_char;
124            while (cur_pos < num_elements)
125            {
126                int endpoint = cur_pos + page_size;
127                if (endpoint > num_elements)
128                    endpoint = num_elements;
129                for (; cur_pos < endpoint; cur_pos++)
130                {
131                    completion_str = completions.GetStringAtIndex(cur_pos);
132                    OutWrite("\n\t", 2, NO_ASYNC);
133                    OutWrite(completion_str, strlen (completion_str), NO_ASYNC);
134                }
135
136                if (cur_pos >= num_elements)
137                {
138                    OutWrite("\n", 1, NO_ASYNC);
139                    break;
140                }
141
142                OutWrite("\nMore (Y/n/a): ", strlen ("\nMore (Y/n/a): "), NO_ASYNC);
143                reply = 'n';
144                got_char = el_getc(m_edit_line, &reply);
145                if (got_char == -1 || reply == 'n')
146                    break;
147                if (reply == 'a')
148                    page_size = num_elements - cur_pos;
149            }
150        }
151
152    }
153
154    if (num_completions == 0)
155        return CC_REFRESH_BEEP;
156    else
157        return CC_REDISPLAY;
158}
159
160IOChannel::IOChannel
161(
162    FILE *editline_in,
163    FILE *editline_out,
164    FILE *out,
165    FILE *err,
166    Driver *driver
167) :
168    SBBroadcaster ("IOChannel"),
169    m_output_mutex (),
170    m_enter_elgets_time (),
171    m_driver (driver),
172    m_read_thread (LLDB_INVALID_HOST_THREAD),
173    m_read_thread_should_exit (false),
174    m_out_file (out),
175    m_err_file (err),
176    m_command_queue (),
177    m_completion_key ("\t"),
178    m_edit_line (::el_init (SBHostOS::GetProgramFileSpec().GetFilename(), editline_in, editline_out,  editline_out)),
179    m_history (history_init()),
180    m_history_event(),
181    m_getting_command (false),
182    m_expecting_prompt (false),
183	m_prompt_str (),
184    m_refresh_request_pending (false)
185{
186    assert (m_edit_line);
187    ::el_set (m_edit_line, EL_PROMPT, el_prompt);
188    ::el_set (m_edit_line, EL_EDITOR, "emacs");
189    ::el_set (m_edit_line, EL_HIST, history, m_history);
190
191    // Source $PWD/.editrc then $HOME/.editrc
192    ::el_source (m_edit_line, NULL);
193
194    el_set (m_edit_line, EL_ADDFN, "lldb_complete",
195            "LLDB completion function",
196            IOChannel::ElCompletionFn);
197    el_set (m_edit_line, EL_BIND, m_completion_key, "lldb_complete", NULL);
198    el_set (m_edit_line, EL_BIND, "^r", "em-inc-search-prev", NULL);  // Cycle through backwards search, entering string
199    el_set (m_edit_line, EL_BIND, "^w", "ed-delete-prev-word", NULL); // Delete previous word, behave like bash does.
200    el_set (m_edit_line, EL_CLIENTDATA, this);
201
202    assert (m_history);
203    ::history (m_history, &m_history_event, H_SETSIZE, 800);
204    ::history (m_history, &m_history_event, H_SETUNIQUE, 1);
205    // Load history
206    HistorySaveLoad (false);
207
208    // Set up mutex to make sure OutErr, OutWrite and RefreshPrompt do not interfere
209    // with each other when writing.
210
211    int error;
212    ::pthread_mutexattr_t attr;
213    error = ::pthread_mutexattr_init (&attr);
214    assert (error == 0);
215    error = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
216    assert (error == 0);
217    error = ::pthread_mutex_init (&m_output_mutex, &attr);
218    assert (error == 0);
219    error = ::pthread_mutexattr_destroy (&attr);
220    assert (error == 0);
221
222    // Initialize time that ::el_gets was last called.
223
224    m_enter_elgets_time.tv_sec = 0;
225    m_enter_elgets_time.tv_usec = 0;
226}
227
228IOChannel::~IOChannel ()
229{
230    // Save history
231    HistorySaveLoad (true);
232
233    if (m_history != NULL)
234    {
235        ::history_end (m_history);
236        m_history = NULL;
237    }
238
239    if (m_edit_line != NULL)
240    {
241        ::el_end (m_edit_line);
242        m_edit_line = NULL;
243    }
244
245    ::pthread_mutex_destroy (&m_output_mutex);
246}
247
248void
249IOChannel::HistorySaveLoad (bool save)
250{
251    if (m_history != NULL)
252    {
253        char history_path[PATH_MAX];
254        ::snprintf (history_path, sizeof(history_path), "~/.%s-history", SBHostOS::GetProgramFileSpec().GetFilename());
255        if ((size_t)SBFileSpec::ResolvePath (history_path, history_path, sizeof(history_path)) < sizeof(history_path) - 1)
256        {
257            const char *path_ptr = history_path;
258            if (save)
259                ::history (m_history, &m_history_event, H_SAVE, path_ptr);
260            else
261                ::history (m_history, &m_history_event, H_LOAD, path_ptr);
262        }
263    }
264}
265
266void
267IOChannel::LibeditOutputBytesReceived (void *baton, const void *src, size_t src_len)
268{
269	// Make this a member variable.
270    // static std::string prompt_str;
271    IOChannel *io_channel = (IOChannel *) baton;
272    IOLocker locker (io_channel->m_output_mutex);
273    const char *bytes = (const char *) src;
274
275    if (io_channel->IsGettingCommand() && io_channel->m_expecting_prompt)
276    {
277        io_channel->m_prompt_str.append (bytes, src_len);
278		// Log this to make sure the prompt is really what you think it is.
279        if (io_channel->m_prompt_str.find (el_prompt(io_channel->m_edit_line)) == 0)
280        {
281            io_channel->m_expecting_prompt = false;
282            io_channel->m_refresh_request_pending = false;
283            io_channel->OutWrite (io_channel->m_prompt_str.c_str(),
284                                  io_channel->m_prompt_str.size(), NO_ASYNC);
285            io_channel->m_prompt_str.clear();
286        }
287    }
288    else
289    {
290        if (io_channel->m_prompt_str.size() > 0)
291            io_channel->m_prompt_str.clear();
292        std::string tmp_str (bytes, src_len);
293        if (tmp_str.find (el_prompt (io_channel->m_edit_line)) == 0)
294            io_channel->m_refresh_request_pending = false;
295        io_channel->OutWrite (bytes, src_len, NO_ASYNC);
296    }
297}
298
299bool
300IOChannel::LibeditGetInput (std::string &new_line)
301{
302    if (m_edit_line != NULL)
303    {
304        int line_len = 0;
305
306        // Set boolean indicating whether or not el_gets is trying to get input (i.e. whether or not to attempt
307        // to refresh the prompt after writing data).
308        SetGettingCommand (true);
309        m_expecting_prompt = true;
310
311        // Call el_gets to prompt the user and read the user's input.
312        const char *line = ::el_gets (m_edit_line, &line_len);
313
314        // Re-set the boolean indicating whether or not el_gets is trying to get input.
315        SetGettingCommand (false);
316
317        if (line)
318        {
319            // strip any newlines off the end of the string...
320            while (line_len > 0 && (line[line_len - 1] == '\n' || line[line_len - 1] == '\r'))
321                --line_len;
322            if (line_len > 0)
323            {
324                ::history (m_history, &m_history_event, H_ENTER, line);
325                new_line.assign (line, line_len);   // Omit the newline
326            }
327            else
328            {
329                // Someone just hit ENTER, return the empty string
330                new_line.clear();
331            }
332            // Return true to indicate success even if a string is empty
333            return true;
334        }
335    }
336    // Return false to indicate failure. This can happen when the file handle
337    // is closed (EOF).
338    new_line.clear();
339    return false;
340}
341
342void *
343IOChannel::IOReadThread (void *ptr)
344{
345    IOChannel *myself = static_cast<IOChannel *> (ptr);
346    myself->Run();
347    return NULL;
348}
349
350void
351IOChannel::Run ()
352{
353    SBListener listener("IOChannel::Run");
354    std::string new_line;
355
356    SBBroadcaster interpreter_broadcaster (m_driver->GetDebugger().GetCommandInterpreter().GetBroadcaster());
357    listener.StartListeningForEvents (interpreter_broadcaster,
358                                      SBCommandInterpreter::eBroadcastBitResetPrompt |
359                                      SBCommandInterpreter::eBroadcastBitThreadShouldExit |
360                                      SBCommandInterpreter::eBroadcastBitQuitCommandReceived);
361
362    listener.StartListeningForEvents (*this,
363                                      IOChannel::eBroadcastBitThreadShouldExit);
364
365    listener.StartListeningForEvents (*m_driver,
366                                      Driver::eBroadcastBitReadyForInput |
367                                      Driver::eBroadcastBitThreadShouldExit);
368
369    // Let anyone know that the IO channel is up and listening and ready for events
370    BroadcastEventByType (eBroadcastBitThreadDidStart);
371    bool done = false;
372    while (!done)
373    {
374        SBEvent event;
375
376        listener.WaitForEvent (UINT32_MAX, event);
377        if (!event.IsValid())
378            continue;
379
380        const uint32_t event_type = event.GetType();
381
382        if (event.GetBroadcaster().IsValid())
383        {
384            if (event.BroadcasterMatchesPtr (m_driver))
385            {
386                if (event_type & Driver::eBroadcastBitReadyForInput)
387                {
388                    std::string line;
389
390                    if (CommandQueueIsEmpty())
391                    {
392                        if (LibeditGetInput(line) == false)
393                        {
394                            // EOF or some other file error occurred
395                            done = true;
396                            continue;
397                        }
398                    }
399                    else
400                    {
401                        GetCommandFromQueue (line);
402                    }
403
404                    // TO BE DONE: FIGURE OUT WHICH COMMANDS SHOULD NOT BE REPEATED IF USER PRESSES PLAIN 'RETURN'
405                    // AND TAKE CARE OF THAT HERE.
406
407                    SBEvent line_event(IOChannel::eBroadcastBitHasUserInput,
408                             line.c_str(),
409                             line.size());
410                    BroadcastEvent (line_event);
411                }
412                else if (event_type & Driver::eBroadcastBitThreadShouldExit)
413                {
414                    done = true;
415                    continue;
416                }
417            }
418            else if (event.BroadcasterMatchesRef (interpreter_broadcaster))
419            {
420                switch (event_type)
421                {
422                case SBCommandInterpreter::eBroadcastBitResetPrompt:
423                    {
424                        const char *new_prompt = SBEvent::GetCStringFromEvent (event);
425                        if (new_prompt)
426                            g_prompt_map[m_edit_line] = new_prompt;
427                    }
428                    break;
429
430                case SBCommandInterpreter::eBroadcastBitThreadShouldExit:
431                case SBCommandInterpreter::eBroadcastBitQuitCommandReceived:
432                    done = true;
433                    break;
434                }
435            }
436            else if (event.BroadcasterMatchesPtr (this))
437            {
438                if (event_type & IOChannel::eBroadcastBitThreadShouldExit)
439                {
440                    done = true;
441                    continue;
442                }
443            }
444        }
445    }
446    BroadcastEventByType (IOChannel::eBroadcastBitThreadDidExit);
447    m_driver = NULL;
448    m_read_thread = NULL;
449}
450
451bool
452IOChannel::Start ()
453{
454    if (IS_VALID_LLDB_HOST_THREAD(m_read_thread))
455        return true;
456
457    m_read_thread = SBHostOS::ThreadCreate ("<lldb.driver.commandline_io>", IOChannel::IOReadThread, this,
458                                            NULL);
459
460    return (IS_VALID_LLDB_HOST_THREAD(m_read_thread));
461}
462
463bool
464IOChannel::Stop ()
465{
466    if (!IS_VALID_LLDB_HOST_THREAD(m_read_thread))
467        return true;
468
469    BroadcastEventByType (eBroadcastBitThreadShouldExit);
470
471    // Don't call Host::ThreadCancel since el_gets won't respond to this
472    // function call -- the thread will just die and all local variables in
473    // IOChannel::Run() won't get destructed down which is bad since there is
474    // a local listener holding onto broadcasters... To ensure proper shutdown,
475    // a ^D (control-D) sequence (0x04) should be written to other end of the
476    // the "in" file handle that was passed into the contructor as closing the
477    // file handle doesn't seem to make el_gets() exit....
478    return SBHostOS::ThreadJoin (m_read_thread, NULL, NULL);
479}
480
481void
482IOChannel::RefreshPrompt ()
483{
484    // If we are not in the middle of getting input from the user, there is no need to
485    // refresh the prompt.
486    IOLocker locker (m_output_mutex);
487    if (! IsGettingCommand())
488        return;
489
490	// If we haven't finished writing the prompt, there's no need to refresh it.
491    if (m_expecting_prompt)
492        return;
493
494    if (m_refresh_request_pending)
495        return;
496
497    ::el_set (m_edit_line, EL_REFRESH);
498    m_refresh_request_pending = true;
499}
500
501void
502IOChannel::OutWrite (const char *buffer, size_t len, bool asynchronous)
503{
504    if (len == 0)
505        return;
506
507    // We're in the process of exiting -- IOChannel::Run() has already completed
508    // and set m_driver to NULL - it is time for us to leave now.  We might not
509    // print the final ^D to stdout in this case.  We need to do some re-work on
510    // how the I/O streams are managed at some point.
511    if (m_driver == NULL)
512    {
513        return;
514    }
515
516    // Use the mutex to make sure OutWrite and ErrWrite do not interfere with each other's output.
517    IOLocker locker (m_output_mutex);
518    if (m_driver->EditlineReaderIsTop() && asynchronous)
519        ::fwrite (undo_prompt_string, 1, 4, m_out_file);
520    ::fwrite (buffer, 1, len, m_out_file);
521    if (asynchronous)
522        m_driver->GetDebugger().NotifyTopInputReader (eInputReaderAsynchronousOutputWritten);
523}
524
525void
526IOChannel::ErrWrite (const char *buffer, size_t len, bool asynchronous)
527{
528    if (len == 0)
529        return;
530
531    // Use the mutex to make sure OutWrite and ErrWrite do not interfere with each other's output.
532    IOLocker locker (m_output_mutex);
533    if (asynchronous)
534        ::fwrite (undo_prompt_string, 1, 4, m_err_file);
535    ::fwrite (buffer, 1, len, m_err_file);
536    if (asynchronous)
537        m_driver->GetDebugger().NotifyTopInputReader (eInputReaderAsynchronousOutputWritten);
538}
539
540void
541IOChannel::AddCommandToQueue (const char *command)
542{
543    m_command_queue.push (std::string(command));
544}
545
546bool
547IOChannel::GetCommandFromQueue (std::string &cmd)
548{
549    if (m_command_queue.empty())
550        return false;
551    cmd.swap(m_command_queue.front());
552    m_command_queue.pop ();
553    return true;
554}
555
556int
557IOChannel::CommandQueueSize () const
558{
559    return m_command_queue.size();
560}
561
562void
563IOChannel::ClearCommandQueue ()
564{
565    while (!m_command_queue.empty())
566        m_command_queue.pop();
567}
568
569bool
570IOChannel::CommandQueueIsEmpty () const
571{
572    return m_command_queue.empty();
573}
574
575bool
576IOChannel::IsGettingCommand () const
577{
578    return m_getting_command;
579}
580
581void
582IOChannel::SetGettingCommand (bool new_value)
583{
584    m_getting_command = new_value;
585}
586
587IOLocker::IOLocker (pthread_mutex_t &mutex) :
588    m_mutex_ptr (&mutex)
589{
590    if (m_mutex_ptr)
591        ::pthread_mutex_lock (m_mutex_ptr);
592
593}
594
595IOLocker::~IOLocker ()
596{
597    if (m_mutex_ptr)
598        ::pthread_mutex_unlock (m_mutex_ptr);
599}
600