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