blob: d8175cbb757d712b2b948405ebeeac8d964bfc47 [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
23using namespace lldb;
24
25typedef std::map<EditLine *, std::string> PromptMap;
26const char *g_default_prompt = "(lldb) ";
27PromptMap g_prompt_map;
28
29static const char*
30el_prompt(EditLine *el)
31{
32 PromptMap::const_iterator pos = g_prompt_map.find (el);
33 if (pos == g_prompt_map.end())
34 return g_default_prompt;
35 return pos->second.c_str();
36}
37
38const char *
39IOChannel::GetPrompt ()
40{
41 PromptMap::const_iterator pos = g_prompt_map.find (m_edit_line);
42 if (pos == g_prompt_map.end())
43 return g_default_prompt;
44 return pos->second.c_str();
45}
46
47unsigned char
48IOChannel::ElCompletionFn (EditLine *e, int ch)
49{
50 IOChannel *io_channel;
51 if (el_get(e, EL_CLIENTDATA, &io_channel) == 0)
52 {
53 return io_channel->HandleCompletion (e, ch);
54 }
55 else
56 {
57 return CC_ERROR;
58 }
59}
60
61unsigned char
62IOChannel::HandleCompletion (EditLine *e, int ch)
63{
64 assert (e == m_edit_line);
65
66 const LineInfo *line_info = el_line(m_edit_line);
67 SBStringList completions;
68 size_t page_size = 40;
69
70 int num_completions
71 = SBDebugger::GetCommandInterpreter().HandleCompletion (line_info->buffer,
72 line_info->cursor,
73 line_info->lastchar,
74 0,
75 -1,
76 completions);
77
78 if (num_completions == -1)
79 {
80 el_insertstr (m_edit_line, m_completion_key);
81 return CC_REDISPLAY;
82 }
83
84 // If we get a longer match display that first.
85 const char *completion_str = completions.GetStringAtIndex(0);
86 if (completion_str != NULL && *completion_str != '\0')
87 {
88 el_insertstr (m_edit_line, completion_str);
89 return CC_REDISPLAY;
90 }
91
92 if (num_completions > 1)
93 {
94 const char *comment = "\nAvailable completions:";
95
96 int num_elements = num_completions + 1;
97 OutWrite(comment, strlen (comment));
98 if (num_completions < page_size)
99 {
100 for (int i = 1; i < num_elements; i++)
101 {
102 const char *completion_str = completions.GetStringAtIndex(i);
103 OutWrite("\n\t", 2);
104 OutWrite(completion_str, strlen (completion_str));
105 }
106 OutWrite ("\n", 1);
107 }
108 else
109 {
110 int cur_pos = 1;
111 char reply;
112 int got_char;
113 while (cur_pos < num_elements)
114 {
115 int endpoint = cur_pos + page_size;
116 if (endpoint > num_elements)
117 endpoint = num_elements;
118 for (; cur_pos < endpoint; cur_pos++)
119 {
120 const char *completion_str = completions.GetStringAtIndex(cur_pos);
121 OutWrite("\n\t", 2);
122 OutWrite(completion_str, strlen (completion_str));
123 }
124
125 if (cur_pos >= num_elements)
126 {
127 OutWrite("\n", 1);
128 break;
129 }
130
131 OutWrite("\nMore (Y/n/a): ", strlen ("\nMore (Y/n/a): "));
132 reply = 'n';
133 got_char = el_getc(m_edit_line, &reply);
134 if (got_char == -1 || reply == 'n')
135 break;
136 if (reply == 'a')
137 page_size = num_elements - cur_pos;
138 }
139 }
140
141 }
142
143 if (num_completions == 0)
144 return CC_REFRESH_BEEP;
145 else
146 return CC_REDISPLAY;
147}
148
149IOChannel::IOChannel
150(
151 FILE *in,
152 FILE *out,
153 FILE *err,
154 Driver *driver
155) :
156 SBBroadcaster ("IOChannel"),
157 m_driver (driver),
158 m_read_thread (LLDB_INVALID_HOST_THREAD),
159 m_read_thread_should_exit (false),
160 m_out_file (out),
161 m_err_file (err),
162 m_edit_line (::el_init (SBHostOS::GetProgramFileSpec().GetFileName(), in, out, err)),
163 m_history (history_init()),
164 m_completion_key ("\t")
165{
166 assert (m_edit_line);
167 ::el_set (m_edit_line, EL_PROMPT, el_prompt);
168 ::el_set (m_edit_line, EL_EDITOR, "emacs");
169 ::el_set (m_edit_line, EL_HIST, history, m_history);
170
171 // Source $PWD/.editrc then $HOME/.editrc
172 ::el_source (m_edit_line, NULL);
173
174 el_set(m_edit_line, EL_ADDFN, "lldb_complete",
175 "LLDB completion function",
176 IOChannel::ElCompletionFn);
177 el_set(m_edit_line, EL_BIND, m_completion_key, "lldb_complete", NULL);
178 el_set (m_edit_line, EL_CLIENTDATA, this);
179
180 assert (m_history);
181 ::history (m_history, &m_history_event, H_SETSIZE, 800);
182 ::history (m_history, &m_history_event, H_SETUNIQUE, 1);
183 // Load history
184 HistorySaveLoad (false);
185}
186
187IOChannel::~IOChannel ()
188{
189 // Save history
190 HistorySaveLoad (true);
191
192 if (m_history != NULL)
193 {
194 ::history_end (m_history);
195 m_history = NULL;
196 }
197
198 if (m_edit_line != NULL)
199 {
200 ::el_end (m_edit_line);
201 m_edit_line = NULL;
202 }
203}
204
205void
206IOChannel::HistorySaveLoad (bool save)
207{
208 if (m_history != NULL)
209 {
210 char history_path[PATH_MAX];
211 ::snprintf (history_path, sizeof(history_path), "~/.%s-history", SBHostOS::GetProgramFileSpec().GetFileName());
212 if (SBFileSpec::ResolvePath (history_path, history_path, sizeof(history_path)) < sizeof(history_path) - 1)
213 {
214 const char *path_ptr = history_path;
215 if (save)
216 ::history (m_history, &m_history_event, H_SAVE, path_ptr);
217 else
218 ::history (m_history, &m_history_event, H_LOAD, path_ptr);
219 }
220 }
221}
222
223bool
224IOChannel::LibeditGetInput (std::string &new_line)
225{
226 if (m_edit_line != NULL)
227 {
228 int line_len = 0;
229 const char *line = ::el_gets (m_edit_line, &line_len);
230 if (line)
231 {
232 // strip any newlines off the end of the string...
233 while (line_len > 0 && (line[line_len - 1] == '\n' || line[line_len - 1] == '\r'))
234 --line_len;
235 if (line_len > 0)
236 {
237 ::history (m_history, &m_history_event, H_ENTER, line);
238 new_line.assign (line, line_len); // Omit the newline
239 }
240 else
241 {
242 // Someone just hit ENTER, return the empty string
243 new_line.clear();
244 }
245 // Return true to indicate success even if a string is empty
246 return true;
247 }
248 }
249 // Return false to indicate failure. This can happen when the file handle
250 // is closed (EOF).
251 new_line.clear();
252 return false;
253}
254
255void *
256IOChannel::IOReadThread (void *ptr)
257{
258 IOChannel *myself = static_cast<IOChannel *> (ptr);
259 myself->Run();
260 return NULL;
261}
262
263void
264IOChannel::Run ()
265{
266 SBListener listener("IOChannel::Run");
267 std::string new_line;
268
269 SBBroadcaster interpreter_broadcaster (SBDebugger::GetCommandInterpreter().GetBroadcaster());
270 listener.StartListeningForEvents (interpreter_broadcaster,
271 SBCommandInterpreter::eBroadcastBitResetPrompt |
272 SBCommandInterpreter::eBroadcastBitThreadShouldExit |
273 SBCommandInterpreter::eBroadcastBitQuitCommandReceived);
274
275 listener.StartListeningForEvents (*this,
276 IOChannel::eBroadcastBitThreadShouldExit);
277
278 listener.StartListeningForEvents (*m_driver,
279 Driver::eBroadcastBitReadyForInput |
280 Driver::eBroadcastBitThreadShouldExit);
281
282 // Let anyone know that the IO channel is up and listening and ready for events
283 BroadcastEventByType (eBroadcastBitThreadDidStart);
284 bool done = false;
285 while (!done)
286 {
287 SBEvent event;
288
289 listener.WaitForEvent (UINT32_MAX, event);
290 if (!event.IsValid())
291 continue;
292
293 const uint32_t event_type = event.GetType();
294
295 if (event.GetBroadcaster().IsValid())
296 {
297 if (event.BroadcasterMatchesPtr (m_driver))
298 {
299 if (event_type & Driver::eBroadcastBitReadyForInput)
300 {
301 std::string line;
302
303 if (CommandQueueIsEmpty())
304 {
305 if (LibeditGetInput(line) == false)
306 {
307 // EOF or some other file error occurred
308 done = true;
309 continue;
310 }
311 }
312 else
313 {
314 GetCommandFromQueue (line);
315 }
316
317 // TO BE DONE: FIGURE OUT WHICH COMMANDS SHOULD NOT BE REPEATED IF USER PRESSES PLAIN 'RETURN'
318 // AND TAKE CARE OF THAT HERE.
319
320 SBEvent line_event(IOChannel::eBroadcastBitHasUserInput,
321 line.c_str(),
322 line.size());
323 BroadcastEvent (line_event);
324 }
325 else if (event_type & Driver::eBroadcastBitThreadShouldExit)
326 {
327 done = true;
328 break;
329 }
330 }
331 else if (event.BroadcasterMatchesRef (interpreter_broadcaster))
332 {
333 switch (event_type)
334 {
335 case SBCommandInterpreter::eBroadcastBitResetPrompt:
336 {
337 const char *new_prompt = SBEvent::GetCStringFromEvent (event);
338 if (new_prompt)
339 g_prompt_map[m_edit_line] = new_prompt;
340 }
341 break;
342
343 case SBCommandInterpreter::eBroadcastBitThreadShouldExit:
344 case SBCommandInterpreter::eBroadcastBitQuitCommandReceived:
345 done = true;
346 break;
347 }
348 }
349 else if (event.BroadcasterMatchesPtr (this))
350 {
351 if (event_type & IOChannel::eBroadcastBitThreadShouldExit)
352 {
353 done = true;
354 break;
355 }
356 }
357 }
358 }
359 BroadcastEventByType (IOChannel::eBroadcastBitThreadDidExit);
360 m_driver = NULL;
361 m_read_thread = NULL;
362}
363
364bool
365IOChannel::Start ()
366{
367 if (m_read_thread != LLDB_INVALID_HOST_THREAD)
368 return true;
369
370 m_read_thread = SBHostOS::ThreadCreate ("<lldb.driver.commandline_io>", IOChannel::IOReadThread, this,
371 NULL);
372
373 return (m_read_thread != LLDB_INVALID_HOST_THREAD);
374}
375
376bool
377IOChannel::Stop ()
378{
379 if (m_read_thread == NULL)
380 return true;
381
382 BroadcastEventByType (eBroadcastBitThreadShouldExit);
383
384 // Don't call Host::ThreadCancel since el_gets won't respond to this
385 // function call -- the thread will just die and all local variables in
386 // IOChannel::Run() won't get destructed down which is bad since there is
387 // a local listener holding onto broadcasters... To ensure proper shutdown,
388 // a ^D (control-D) sequence (0x04) should be written to other end of the
389 // the "in" file handle that was passed into the contructor as closing the
390 // file handle doesn't seem to make el_gets() exit....
391 return SBHostOS::ThreadJoin (m_read_thread, NULL, NULL);
392}
393
394void
395IOChannel::RefreshPrompt ()
396{
397 ::el_set (m_edit_line, EL_REFRESH);
398}
399
400void
401IOChannel::OutWrite (const char *buffer, size_t len)
402{
403 if (len == 0)
404 return;
405 ::fwrite (buffer, 1, len, m_out_file);
406}
407
408void
409IOChannel::ErrWrite (const char *buffer, size_t len)
410{
411 if (len == 0)
412 return;
413 ::fwrite (buffer, 1, len, m_err_file);
414}
415
416void
417IOChannel::AddCommandToQueue (const char *command)
418{
419 m_command_queue.push (std::string(command));
420}
421
422bool
423IOChannel::GetCommandFromQueue (std::string &cmd)
424{
425 if (m_command_queue.empty())
426 return false;
427 cmd.swap(m_command_queue.front());
428 m_command_queue.pop ();
429 return true;
430}
431
432int
433IOChannel::CommandQueueSize () const
434{
435 return m_command_queue.size();
436}
437
438void
439IOChannel::ClearCommandQueue ()
440{
441 while (!m_command_queue.empty())
442 m_command_queue.pop();
443}
444
445bool
446IOChannel::CommandQueueIsEmpty () const
447{
448 return m_command_queue.empty();
449}