1 //===-- Editline.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 
11 #include "lldb/Host/Editline.h"
12 
13 #include "lldb/Core/Error.h"
14 #include "lldb/Core/StreamString.h"
15 #include "lldb/Core/StringList.h"
16 #include "lldb/Host/Host.h"
17 
18 #include <limits.h>
19 
20 using namespace lldb;
21 using namespace lldb_private;
22 
23 static const char k_prompt_escape_char = '\1';
24 
25 Editline::Editline (const char *prog,       // prog can't be NULL
26                     const char *prompt,     // can be NULL for no prompt
27                     FILE *fin,
28                     FILE *fout,
29                     FILE *ferr) :
30     m_editline (NULL),
31     m_history (NULL),
32     m_history_event (),
33     m_program (),
34     m_prompt (),
35     m_lines_prompt (),
36     m_getc_buffer (),
37     m_getc_mutex (Mutex::eMutexTypeNormal),
38     m_getc_cond (),
39 //    m_gets_mutex (Mutex::eMutexTypeNormal),
40     m_completion_callback (NULL),
41     m_completion_callback_baton (NULL),
42     m_line_complete_callback (NULL),
43     m_line_complete_callback_baton (NULL),
44     m_lines_command (Command::None),
45     m_lines_curr_line (0),
46     m_lines_max_line (0),
47     m_prompt_with_line_numbers (false),
48     m_getting_line (false),
49     m_got_eof (false),
50     m_interrupted (false)
51 {
52     if (prog && prog[0])
53     {
54         m_program = prog;
55         m_editline = ::el_init(prog, fin, fout, ferr);
56         m_history = ::history_init();
57     }
58     else
59     {
60         m_editline = ::el_init("lldb-tmp", fin, fout, ferr);
61     }
62     if (prompt && prompt[0])
63         SetPrompt (prompt);
64 
65     //::el_set (m_editline, EL_BIND, "^[[A", NULL); // Print binding for up arrow key
66     //::el_set (m_editline, EL_BIND, "^[[B", NULL); // Print binding for up down key
67 
68     assert (m_editline);
69     ::el_set (m_editline, EL_CLIENTDATA, this);
70     ::el_set (m_editline, EL_PROMPT_ESC, GetPromptCallback, k_prompt_escape_char);
71     ::el_set (m_editline, EL_EDITOR, "emacs");
72     if (m_history)
73     {
74         ::el_set (m_editline, EL_HIST, history, m_history);
75     }
76     ::el_set (m_editline, EL_ADDFN, "lldb-complete", "Editline completion function", Editline::CallbackComplete);
77     ::el_set (m_editline, EL_ADDFN, "lldb-edit-prev-line", "Editline edit prev line", Editline::CallbackEditPrevLine);
78     ::el_set (m_editline, EL_ADDFN, "lldb-edit-next-line", "Editline edit next line", Editline::CallbackEditNextLine);
79 
80     ::el_set (m_editline, EL_BIND, "^r", "em-inc-search-prev", NULL); // Cycle through backwards search, entering string
81     ::el_set (m_editline, EL_BIND, "^w", "ed-delete-prev-word", NULL); // Delete previous word, behave like bash does.
82     ::el_set (m_editline, EL_BIND, "\033[3~", "ed-delete-next-char", NULL); // Fix the delete key.
83     ::el_set (m_editline, EL_BIND, "\t", "lldb-complete", NULL); // Bind TAB to be autocompelte
84 
85     // Source $PWD/.editrc then $HOME/.editrc
86     ::el_source (m_editline, NULL);
87 
88     if (m_history)
89     {
90         ::history (m_history, &m_history_event, H_SETSIZE, 800);
91         ::history (m_history, &m_history_event, H_SETUNIQUE, 1);
92     }
93 
94     // Always read through our callback function so we don't read
95     // stuff we aren't supposed to. This also stops the extra echoing
96     // that can happen when you have more input than editline can handle
97     // at once.
98     SetGetCharCallback(GetCharFromInputFileCallback);
99 
100     LoadHistory();
101 }
102 
103 Editline::~Editline()
104 {
105     SaveHistory();
106 
107     if (m_history)
108     {
109         ::history_end (m_history);
110         m_history = NULL;
111     }
112 
113     // Disable edit mode to stop the terminal from flushing all input
114     // during the call to el_end() since we expect to have multiple editline
115     // instances in this program.
116     ::el_set (m_editline, EL_EDITMODE, 0);
117 
118     ::el_end(m_editline);
119     m_editline = NULL;
120 }
121 
122 void
123 Editline::SetGetCharCallback (GetCharCallbackType callback)
124 {
125     ::el_set (m_editline, EL_GETCFN, callback);
126 }
127 
128 FileSpec
129 Editline::GetHistoryFile()
130 {
131     char history_path[PATH_MAX];
132     ::snprintf (history_path, sizeof(history_path), "~/.%s-history", m_program.c_str());
133     return FileSpec(history_path, true);
134 }
135 
136 bool
137 Editline::LoadHistory ()
138 {
139     if (m_history)
140     {
141         FileSpec history_file(GetHistoryFile());
142         if (history_file.Exists())
143             ::history (m_history, &m_history_event, H_LOAD, history_file.GetPath().c_str());
144         return true;
145     }
146     return false;
147 }
148 
149 bool
150 Editline::SaveHistory ()
151 {
152     if (m_history)
153     {
154         std::string history_path = GetHistoryFile().GetPath();
155         ::history (m_history, &m_history_event, H_SAVE, history_path.c_str());
156         return true;
157     }
158     return false;
159 }
160 
161 
162 Error
163 Editline::PrivateGetLine(std::string &line)
164 {
165     Error error;
166     if (m_interrupted)
167     {
168         error.SetErrorString("interrupted");
169         return error;
170     }
171 
172     line.clear();
173     if (m_editline != NULL)
174     {
175         int line_len = 0;
176         const char *line_cstr = NULL;
177         // Call el_gets to prompt the user and read the user's input.
178 //        {
179 //            // Make sure we know when we are in el_gets() by using a mutex
180 //            Mutex::Locker locker (m_gets_mutex);
181             line_cstr = ::el_gets (m_editline, &line_len);
182 //        }
183 
184         static int save_errno = (line_len < 0) ? errno : 0;
185 
186         if (save_errno != 0)
187         {
188             error.SetError(save_errno, eErrorTypePOSIX);
189         }
190         else if (line_cstr)
191         {
192             // Decrement the length so we don't have newline characters in "line" for when
193             // we assign the cstr into the std::string
194             while (line_len > 0 &&
195                    (line_cstr[line_len - 1] == '\n' ||
196                     line_cstr[line_len - 1] == '\r'))
197                 --line_len;
198 
199             if (line_len > 0)
200             {
201                 // We didn't strip the newlines, we just adjusted the length, and
202                 // we want to add the history item with the newlines
203                 if (m_history)
204                     ::history (m_history, &m_history_event, H_ENTER, line_cstr);
205 
206                 // Copy the part of the c string that we want (removing the newline chars)
207                 line.assign(line_cstr, line_len);
208             }
209         }
210     }
211     else
212     {
213         error.SetErrorString("the EditLine instance has been deleted");
214     }
215     return error;
216 }
217 
218 
219 Error
220 Editline::GetLine(std::string &line)
221 {
222     Error error;
223     line.clear();
224 
225     // Set arrow key bindings for up and down arrows for single line
226     // mode where up and down arrows do prev/next history
227     ::el_set (m_editline, EL_BIND, "^[[A", "ed-prev-history", NULL); // Map up arrow
228     ::el_set (m_editline, EL_BIND, "^[[B", "ed-next-history", NULL); // Map down arrow
229     m_interrupted = false;
230 
231     if (!m_got_eof)
232     {
233         if (m_getting_line)
234         {
235             error.SetErrorString("already getting a line");
236             return error;
237         }
238         if (m_lines_curr_line > 0)
239         {
240             error.SetErrorString("already getting lines");
241             return error;
242         }
243         m_getting_line = true;
244         error = PrivateGetLine(line);
245         m_getting_line = false;
246     }
247 
248     if (m_got_eof && line.empty())
249     {
250         // Only set the error if we didn't get an error back from PrivateGetLine()
251         if (error.Success())
252             error.SetErrorString("end of file");
253     }
254 
255     return error;
256 }
257 
258 size_t
259 Editline::Push (const char *bytes, size_t len)
260 {
261     if (m_editline)
262     {
263         // Must NULL terminate the string for el_push() so we stick it
264         // into a std::string first
265         ::el_push(m_editline, std::string (bytes, len).c_str());
266         return len;
267     }
268     return 0;
269 }
270 
271 
272 Error
273 Editline::GetLines(const std::string &end_line, StringList &lines)
274 {
275     Error error;
276     if (m_getting_line)
277     {
278         error.SetErrorString("already getting a line");
279         return error;
280     }
281     if (m_lines_curr_line > 0)
282     {
283         error.SetErrorString("already getting lines");
284         return error;
285     }
286 
287     // Set arrow key bindings for up and down arrows for multiple line
288     // mode where up and down arrows do edit prev/next line
289     ::el_set (m_editline, EL_BIND, "^[[A", "lldb-edit-prev-line", NULL); // Map up arrow
290     ::el_set (m_editline, EL_BIND, "^[[B", "lldb-edit-next-line", NULL); // Map down arrow
291     ::el_set (m_editline, EL_BIND, "^b", "ed-prev-history", NULL);
292     ::el_set (m_editline, EL_BIND, "^n", "ed-next-history", NULL);
293     m_interrupted = false;
294 
295     LineStatus line_status = LineStatus::Success;
296 
297     lines.Clear();
298 
299     FILE *out_file = GetOutputFile();
300     FILE *err_file = GetErrorFile();
301     m_lines_curr_line = 1;
302     while (line_status != LineStatus::Done)
303     {
304         const uint32_t line_idx = m_lines_curr_line-1;
305         if (line_idx >= lines.GetSize())
306             lines.SetSize(m_lines_curr_line);
307         m_lines_max_line = lines.GetSize();
308         m_lines_command = Command::None;
309         assert(line_idx < m_lines_max_line);
310         std::string &line = lines[line_idx];
311         error = PrivateGetLine(line);
312         if (error.Fail())
313         {
314             line_status = LineStatus::Error;
315         }
316         else
317         {
318             switch (m_lines_command)
319             {
320                 case Command::None:
321                     if (m_line_complete_callback)
322                     {
323                         line_status = m_line_complete_callback (this,
324                                                                 lines,
325                                                                 line_idx,
326                                                                 error,
327                                                                 m_line_complete_callback_baton);
328                     }
329                     else if (line == end_line)
330                     {
331                         line_status = LineStatus::Done;
332                     }
333 
334                     if (line_status == LineStatus::Success)
335                     {
336                         ++m_lines_curr_line;
337                         // If we already have content for the next line because
338                         // we were editing previous lines, then populate the line
339                         // with the appropriate contents
340                         if (line_idx+1 < lines.GetSize() && !lines[line_idx+1].empty())
341                             ::el_push (m_editline, lines[line_idx+1].c_str());
342                     }
343                     else if (line_status == LineStatus::Error)
344                     {
345                         // Clear to end of line ("ESC[K"), then print the error,
346                         // then go to the next line ("\n") and then move cursor up
347                         // two lines ("ESC[2A").
348                         fprintf (err_file, "\033[Kerror: %s\n\033[2A", error.AsCString());
349                     }
350                     break;
351                 case Command::EditPrevLine:
352                     if (m_lines_curr_line > 1)
353                     {
354                         //::fprintf (out_file, "\033[1A\033[%uD\033[2K", (uint32_t)(m_lines_prompt.size() + lines[line_idx].size())); // Make cursor go up a line and clear that line
355                         ::fprintf (out_file, "\033[1A\033[1000D\033[2K");
356                         if (!lines[line_idx-1].empty())
357                             ::el_push (m_editline, lines[line_idx-1].c_str());
358                         --m_lines_curr_line;
359                     }
360                     break;
361                 case Command::EditNextLine:
362                     // Allow the down arrow to create a new line
363                     ++m_lines_curr_line;
364                     //::fprintf (out_file, "\033[1B\033[%uD\033[2K", (uint32_t)(m_lines_prompt.size() + lines[line_idx].size()));
365                     ::fprintf (out_file, "\033[1B\033[1000D\033[2K");
366                     if (line_idx+1 < lines.GetSize() && !lines[line_idx+1].empty())
367                         ::el_push (m_editline, lines[line_idx+1].c_str());
368                     break;
369             }
370         }
371     }
372     m_lines_curr_line = 0;
373     m_lines_command = Command::None;
374 
375     // If we have a callback, call it one more time to let the
376     // user know the lines are complete
377     if (m_line_complete_callback)
378         m_line_complete_callback (this,
379                                   lines,
380                                   UINT32_MAX,
381                                   error,
382                                   m_line_complete_callback_baton);
383 
384     return error;
385 }
386 
387 unsigned char
388 Editline::HandleCompletion (int ch)
389 {
390     if (m_completion_callback == NULL)
391         return CC_ERROR;
392 
393     const LineInfo *line_info  = ::el_line(m_editline);
394     StringList completions;
395     int page_size = 40;
396 
397     const int num_completions = m_completion_callback (line_info->buffer,
398                                                        line_info->cursor,
399                                                        line_info->lastchar,
400                                                        0,     // Don't skip any matches (start at match zero)
401                                                        -1,    // Get all the matches
402                                                        completions,
403                                                        m_completion_callback_baton);
404 
405     FILE *out_file = GetOutputFile();
406 
407 //    if (num_completions == -1)
408 //    {
409 //        ::el_insertstr (m_editline, m_completion_key);
410 //        return CC_REDISPLAY;
411 //    }
412 //    else
413     if (num_completions == -2)
414     {
415         // Replace the entire line with the first string...
416         ::el_deletestr (m_editline, line_info->cursor - line_info->buffer);
417         ::el_insertstr (m_editline, completions.GetStringAtIndex(0));
418         return CC_REDISPLAY;
419     }
420 
421     // If we get a longer match display that first.
422     const char *completion_str = completions.GetStringAtIndex(0);
423     if (completion_str != NULL && *completion_str != '\0')
424     {
425         el_insertstr (m_editline, completion_str);
426         return CC_REDISPLAY;
427     }
428 
429     if (num_completions > 1)
430     {
431         int num_elements = num_completions + 1;
432         ::fprintf (out_file, "\nAvailable completions:");
433         if (num_completions < page_size)
434         {
435             for (int i = 1; i < num_elements; i++)
436             {
437                 completion_str = completions.GetStringAtIndex(i);
438                 ::fprintf (out_file, "\n\t%s", completion_str);
439             }
440             ::fprintf (out_file, "\n");
441         }
442         else
443         {
444             int cur_pos = 1;
445             char reply;
446             int got_char;
447             while (cur_pos < num_elements)
448             {
449                 int endpoint = cur_pos + page_size;
450                 if (endpoint > num_elements)
451                     endpoint = num_elements;
452                 for (; cur_pos < endpoint; cur_pos++)
453                 {
454                     completion_str = completions.GetStringAtIndex(cur_pos);
455                     ::fprintf (out_file, "\n\t%s", completion_str);
456                 }
457 
458                 if (cur_pos >= num_elements)
459                 {
460                     ::fprintf (out_file, "\n");
461                     break;
462                 }
463 
464                 ::fprintf (out_file, "\nMore (Y/n/a): ");
465                 reply = 'n';
466                 got_char = el_getc(m_editline, &reply);
467                 if (got_char == -1 || reply == 'n')
468                     break;
469                 if (reply == 'a')
470                     page_size = num_elements - cur_pos;
471             }
472         }
473 
474     }
475 
476     if (num_completions == 0)
477         return CC_REFRESH_BEEP;
478     else
479         return CC_REDISPLAY;
480 }
481 
482 Editline *
483 Editline::GetClientData (::EditLine *e)
484 {
485     Editline *editline = NULL;
486     if (e && ::el_get(e, EL_CLIENTDATA, &editline) == 0)
487         return editline;
488     return NULL;
489 }
490 
491 FILE *
492 Editline::GetInputFile ()
493 {
494     return GetFilePointer (m_editline, 0);
495 }
496 
497 FILE *
498 Editline::GetOutputFile ()
499 {
500     return GetFilePointer (m_editline, 1);
501 }
502 
503 FILE *
504 Editline::GetErrorFile ()
505 {
506     return GetFilePointer (m_editline, 2);
507 }
508 
509 const char *
510 Editline::GetPrompt()
511 {
512     if (m_prompt_with_line_numbers && m_lines_curr_line > 0)
513     {
514         StreamString strm;
515         strm.Printf("%3u: ", m_lines_curr_line);
516         m_lines_prompt = std::move(strm.GetString());
517         return m_lines_prompt.c_str();
518     }
519     else
520     {
521         return m_prompt.c_str();
522     }
523 }
524 
525 void
526 Editline::SetPrompt (const char *p)
527 {
528     if (p && p[0])
529         m_prompt = p;
530     else
531         m_prompt.clear();
532     size_t start_pos = 0;
533     size_t escape_pos;
534     while ((escape_pos = m_prompt.find('\033', start_pos)) != std::string::npos)
535     {
536         m_prompt.insert(escape_pos, 1, k_prompt_escape_char);
537         start_pos += 2;
538     }
539 }
540 
541 FILE *
542 Editline::GetFilePointer (::EditLine *e, int fd)
543 {
544     FILE *file_ptr = NULL;
545     if (e && ::el_get(e, EL_GETFP, fd, &file_ptr) == 0)
546         return file_ptr;
547     return NULL;
548 }
549 
550 unsigned char
551 Editline::CallbackEditPrevLine (::EditLine *e, int ch)
552 {
553     Editline *editline = GetClientData (e);
554     if (editline->m_lines_curr_line > 1)
555     {
556         editline->m_lines_command = Command::EditPrevLine;
557         return CC_NEWLINE;
558     }
559     return CC_ERROR;
560 }
561 unsigned char
562 Editline::CallbackEditNextLine (::EditLine *e, int ch)
563 {
564     Editline *editline = GetClientData (e);
565     if (editline->m_lines_curr_line < editline->m_lines_max_line)
566     {
567         editline->m_lines_command = Command::EditNextLine;
568         return CC_NEWLINE;
569     }
570     return CC_ERROR;
571 }
572 
573 unsigned char
574 Editline::CallbackComplete (::EditLine *e, int ch)
575 {
576     Editline *editline = GetClientData (e);
577     if (editline)
578         return editline->HandleCompletion (ch);
579     return CC_ERROR;
580 }
581 
582 const char *
583 Editline::GetPromptCallback (::EditLine *e)
584 {
585     Editline *editline = GetClientData (e);
586     if (editline)
587         return editline->GetPrompt();
588     return "";
589 }
590 
591 size_t
592 Editline::SetInputBuffer (const char *c, size_t len)
593 {
594     if (c && len > 0)
595     {
596         Mutex::Locker locker(m_getc_mutex);
597         SetGetCharCallback(GetCharInputBufferCallback);
598         m_getc_buffer.append(c, len);
599         m_getc_cond.Broadcast();
600     }
601     return len;
602 }
603 
604 int
605 Editline::GetChar (char *c)
606 {
607     Mutex::Locker locker(m_getc_mutex);
608     if (m_getc_buffer.empty())
609         m_getc_cond.Wait(m_getc_mutex);
610     if (m_getc_buffer.empty())
611         return 0;
612     *c = m_getc_buffer[0];
613     m_getc_buffer.erase(0,1);
614     return 1;
615 }
616 
617 int
618 Editline::GetCharInputBufferCallback (EditLine *e, char *c)
619 {
620     Editline *editline = GetClientData (e);
621     if (editline)
622         return editline->GetChar(c);
623     return 0;
624 }
625 
626 int
627 Editline::GetCharFromInputFileCallback (EditLine *e, char *c)
628 {
629     Editline *editline = GetClientData (e);
630     if (editline && editline->m_got_eof == false)
631     {
632         char ch = ::fgetc(editline->GetInputFile());
633         if (ch == '\x04' || ch == EOF)
634         {
635             editline->m_got_eof = true;
636         }
637         else
638         {
639             *c = ch;
640             return 1;
641         }
642     }
643     return 0;
644 }
645 
646 void
647 Editline::Hide ()
648 {
649     FILE *out_file = GetOutputFile();
650     if (out_file)
651     {
652         const LineInfo *line_info  = ::el_line(m_editline);
653         if (line_info)
654             ::fprintf (out_file, "\033[%uD\033[K", (uint32_t)(strlen(GetPrompt()) + line_info->cursor - line_info->buffer));
655     }
656 }
657 
658 
659 void
660 Editline::Refresh()
661 {
662     ::el_set (m_editline, EL_REFRESH);
663 }
664 
665 void
666 Editline::Interrupt ()
667 {
668     m_interrupted = true;
669     if (m_getting_line || m_lines_curr_line > 0)
670         el_insertstr(m_editline, "\n"); // True to force the line to complete itself so we get exit from el_gets()
671 }
672