aboutsummaryrefslogtreecommitdiffstats
path: root/source/Core/IOHandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Core/IOHandler.cpp')
-rw-r--r--source/Core/IOHandler.cpp332
1 files changed, 143 insertions, 189 deletions
diff --git a/source/Core/IOHandler.cpp b/source/Core/IOHandler.cpp
index b30308490cca..46be29f6fbf9 100644
--- a/source/Core/IOHandler.cpp
+++ b/source/Core/IOHandler.cpp
@@ -52,7 +52,7 @@
#include "llvm/ADT/StringRef.h"
-#ifdef _MSC_VER
+#ifdef _WIN32
#include "lldb/Host/windows/windows.h"
#endif
@@ -70,10 +70,14 @@
using namespace lldb;
using namespace lldb_private;
+using llvm::None;
+using llvm::Optional;
+using llvm::StringRef;
+
IOHandler::IOHandler(Debugger &debugger, IOHandler::Type type)
: IOHandler(debugger, type,
- StreamFileSP(), // Adopt STDIN from top input reader
+ FileSP(), // Adopt STDIN from top input reader
StreamFileSP(), // Adopt STDOUT from top input reader
StreamFileSP(), // Adopt STDERR from top input reader
0, // Flags
@@ -81,7 +85,7 @@ IOHandler::IOHandler(Debugger &debugger, IOHandler::Type type)
) {}
IOHandler::IOHandler(Debugger &debugger, IOHandler::Type type,
- const lldb::StreamFileSP &input_sp,
+ const lldb::FileSP &input_sp,
const lldb::StreamFileSP &output_sp,
const lldb::StreamFileSP &error_sp, uint32_t flags,
repro::DataRecorder *data_recorder)
@@ -98,7 +102,7 @@ IOHandler::IOHandler(Debugger &debugger, IOHandler::Type type,
IOHandler::~IOHandler() = default;
int IOHandler::GetInputFD() {
- return (m_input_sp ? m_input_sp->GetFile().GetDescriptor() : -1);
+ return (m_input_sp ? m_input_sp->GetDescriptor() : -1);
}
int IOHandler::GetOutputFD() {
@@ -110,7 +114,7 @@ int IOHandler::GetErrorFD() {
}
FILE *IOHandler::GetInputFILE() {
- return (m_input_sp ? m_input_sp->GetFile().GetStream() : nullptr);
+ return (m_input_sp ? m_input_sp->GetStream() : nullptr);
}
FILE *IOHandler::GetOutputFILE() {
@@ -121,18 +125,18 @@ FILE *IOHandler::GetErrorFILE() {
return (m_error_sp ? m_error_sp->GetFile().GetStream() : nullptr);
}
-StreamFileSP &IOHandler::GetInputStreamFile() { return m_input_sp; }
+FileSP &IOHandler::GetInputFileSP() { return m_input_sp; }
-StreamFileSP &IOHandler::GetOutputStreamFile() { return m_output_sp; }
+StreamFileSP &IOHandler::GetOutputStreamFileSP() { return m_output_sp; }
-StreamFileSP &IOHandler::GetErrorStreamFile() { return m_error_sp; }
+StreamFileSP &IOHandler::GetErrorStreamFileSP() { return m_error_sp; }
bool IOHandler::GetIsInteractive() {
- return GetInputStreamFile()->GetFile().GetIsInteractive();
+ return GetInputFileSP() ? GetInputFileSP()->GetIsInteractive() : false;
}
bool IOHandler::GetIsRealTerminal() {
- return GetInputStreamFile()->GetFile().GetIsRealTerminal();
+ return GetInputFileSP() ? GetInputFileSP()->GetIsRealTerminal() : false;
}
void IOHandler::SetPopped(bool b) { m_popped.SetValue(b, eBroadcastOnChange); }
@@ -170,18 +174,11 @@ IOHandlerConfirm::IOHandlerConfirm(Debugger &debugger, llvm::StringRef prompt,
IOHandlerConfirm::~IOHandlerConfirm() = default;
-int IOHandlerConfirm::IOHandlerComplete(
- IOHandler &io_handler, const char *current_line, const char *cursor,
- const char *last_char, int skip_first_n_matches, int max_matches,
- StringList &matches, StringList &descriptions) {
- if (current_line == cursor) {
- if (m_default_response) {
- matches.AppendString("y");
- } else {
- matches.AppendString("n");
- }
- }
- return matches.GetSize();
+void IOHandlerConfirm::IOHandlerComplete(IOHandler &io_handler,
+ CompletionRequest &request) {
+ if (request.GetRawCursorPos() != 0)
+ return;
+ request.AddCompletion(m_default_response ? "y" : "n");
}
void IOHandlerConfirm::IOHandlerInputComplete(IOHandler &io_handler,
@@ -219,47 +216,20 @@ void IOHandlerConfirm::IOHandlerInputComplete(IOHandler &io_handler,
}
}
-int IOHandlerDelegate::IOHandlerComplete(
- IOHandler &io_handler, const char *current_line, const char *cursor,
- const char *last_char, int skip_first_n_matches, int max_matches,
- StringList &matches, StringList &descriptions) {
+void IOHandlerDelegate::IOHandlerComplete(IOHandler &io_handler,
+ CompletionRequest &request) {
switch (m_completion) {
case Completion::None:
break;
-
case Completion::LLDBCommand:
- return io_handler.GetDebugger().GetCommandInterpreter().HandleCompletion(
- current_line, cursor, last_char, skip_first_n_matches, max_matches,
- matches, descriptions);
- case Completion::Expression: {
- CompletionResult result;
- CompletionRequest request(current_line, current_line - cursor,
- skip_first_n_matches, max_matches, result);
+ io_handler.GetDebugger().GetCommandInterpreter().HandleCompletion(request);
+ break;
+ case Completion::Expression:
CommandCompletions::InvokeCommonCompletionCallbacks(
io_handler.GetDebugger().GetCommandInterpreter(),
CommandCompletions::eVariablePathCompletion, request, nullptr);
- result.GetMatches(matches);
- result.GetDescriptions(descriptions);
-
- size_t num_matches = request.GetNumberOfMatches();
- if (num_matches > 0) {
- std::string common_prefix;
- matches.LongestCommonPrefix(common_prefix);
- const size_t partial_name_len = request.GetCursorArgumentPrefix().size();
-
- // If we matched a unique single command, add a space... Only do this if
- // the completer told us this was a complete word, however...
- if (num_matches == 1 && request.GetWordComplete()) {
- common_prefix.push_back(' ');
- }
- common_prefix.erase(0, partial_name_len);
- matches.InsertStringAtIndex(0, std::move(common_prefix));
- }
- return num_matches;
- } break;
+ break;
}
-
- return 0;
}
IOHandlerEditline::IOHandlerEditline(
@@ -269,7 +239,7 @@ IOHandlerEditline::IOHandlerEditline(
bool multi_line, bool color_prompts, uint32_t line_number_start,
IOHandlerDelegate &delegate, repro::DataRecorder *data_recorder)
: IOHandlerEditline(debugger, type,
- StreamFileSP(), // Inherit input from top input reader
+ FileSP(), // Inherit input from top input reader
StreamFileSP(), // Inherit output from top input reader
StreamFileSP(), // Inherit error from top input reader
0, // Flags
@@ -278,9 +248,9 @@ IOHandlerEditline::IOHandlerEditline(
line_number_start, delegate, data_recorder) {}
IOHandlerEditline::IOHandlerEditline(
- Debugger &debugger, IOHandler::Type type,
- const lldb::StreamFileSP &input_sp, const lldb::StreamFileSP &output_sp,
- const lldb::StreamFileSP &error_sp, uint32_t flags,
+ Debugger &debugger, IOHandler::Type type, const lldb::FileSP &input_sp,
+ const lldb::StreamFileSP &output_sp, const lldb::StreamFileSP &error_sp,
+ uint32_t flags,
const char *editline_name, // Used for saving history files
llvm::StringRef prompt, llvm::StringRef continuation_prompt,
bool multi_line, bool color_prompts, uint32_t line_number_start,
@@ -300,7 +270,8 @@ IOHandlerEditline::IOHandlerEditline(
#ifndef LLDB_DISABLE_LIBEDIT
bool use_editline = false;
- use_editline = m_input_sp->GetFile().GetIsRealTerminal();
+ use_editline = GetInputFILE() && GetOutputFILE() && GetErrorFILE() &&
+ m_input_sp && m_input_sp->GetIsRealTerminal();
if (use_editline) {
m_editline_up.reset(new Editline(editline_name, GetInputFILE(),
@@ -339,92 +310,119 @@ void IOHandlerEditline::Deactivate() {
m_delegate.IOHandlerDeactivated(*this);
}
+// Split out a line from the buffer, if there is a full one to get.
+static Optional<std::string> SplitLine(std::string &line_buffer) {
+ size_t pos = line_buffer.find('\n');
+ if (pos == std::string::npos)
+ return None;
+ std::string line = StringRef(line_buffer.c_str(), pos).rtrim("\n\r");
+ line_buffer = line_buffer.substr(pos + 1);
+ return line;
+}
+
+// If the final line of the file ends without a end-of-line, return
+// it as a line anyway.
+static Optional<std::string> SplitLineEOF(std::string &line_buffer) {
+ if (llvm::all_of(line_buffer, isspace))
+ return None;
+ std::string line = std::move(line_buffer);
+ line_buffer.clear();
+ return line;
+}
+
bool IOHandlerEditline::GetLine(std::string &line, bool &interrupted) {
#ifndef LLDB_DISABLE_LIBEDIT
if (m_editline_up) {
bool b = m_editline_up->GetLine(line, interrupted);
- if (m_data_recorder)
+ if (b && m_data_recorder)
m_data_recorder->Record(line, true);
return b;
- } else {
+ }
#endif
- line.clear();
- FILE *in = GetInputFILE();
- if (in) {
- if (GetIsInteractive()) {
- const char *prompt = nullptr;
+ line.clear();
- if (m_multi_line && m_curr_line_idx > 0)
- prompt = GetContinuationPrompt();
+ if (GetIsInteractive()) {
+ const char *prompt = nullptr;
- if (prompt == nullptr)
- prompt = GetPrompt();
+ if (m_multi_line && m_curr_line_idx > 0)
+ prompt = GetContinuationPrompt();
- if (prompt && prompt[0]) {
- FILE *out = GetOutputFILE();
- if (out) {
- ::fprintf(out, "%s", prompt);
- ::fflush(out);
- }
- }
+ if (prompt == nullptr)
+ prompt = GetPrompt();
+
+ if (prompt && prompt[0]) {
+ if (m_output_sp) {
+ m_output_sp->Printf("%s", prompt);
+ m_output_sp->Flush();
}
- char buffer[256];
- bool done = false;
- bool got_line = false;
- m_editing = true;
- while (!done) {
+ }
+ }
+
+ Optional<std::string> got_line = SplitLine(m_line_buffer);
+
+ if (!got_line && !m_input_sp) {
+ // No more input file, we are done...
+ SetIsDone(true);
+ return false;
+ }
+
+ FILE *in = GetInputFILE();
+ char buffer[256];
+
+ if (!got_line && !in && m_input_sp) {
+ // there is no FILE*, fall back on just reading bytes from the stream.
+ while (!got_line) {
+ size_t bytes_read = sizeof(buffer);
+ Status error = m_input_sp->Read((void *)buffer, bytes_read);
+ if (error.Success() && !bytes_read) {
+ got_line = SplitLineEOF(m_line_buffer);
+ break;
+ }
+ if (error.Fail())
+ break;
+ m_line_buffer += StringRef(buffer, bytes_read);
+ got_line = SplitLine(m_line_buffer);
+ }
+ }
+
+ if (!got_line && in) {
+ m_editing = true;
+ while (!got_line) {
+ char *r = fgets(buffer, sizeof(buffer), in);
#ifdef _WIN32
- // ReadFile on Windows is supposed to set ERROR_OPERATION_ABORTED
- // according to the docs on MSDN. However, this has evidently been a
- // known bug since Windows 8. Therefore, we can't detect if a signal
- // interrupted in the fgets. So pressing ctrl-c causes the repl to end
- // and the process to exit. A temporary workaround is just to attempt to
- // fgets twice until this bug is fixed.
- if (fgets(buffer, sizeof(buffer), in) == nullptr &&
- fgets(buffer, sizeof(buffer), in) == nullptr) {
-#else
- if (fgets(buffer, sizeof(buffer), in) == nullptr) {
+ // ReadFile on Windows is supposed to set ERROR_OPERATION_ABORTED
+ // according to the docs on MSDN. However, this has evidently been a
+ // known bug since Windows 8. Therefore, we can't detect if a signal
+ // interrupted in the fgets. So pressing ctrl-c causes the repl to end
+ // and the process to exit. A temporary workaround is just to attempt to
+ // fgets twice until this bug is fixed.
+ if (r == nullptr)
+ r = fgets(buffer, sizeof(buffer), in);
+ // this is the equivalent of EINTR for Windows
+ if (r == nullptr && GetLastError() == ERROR_OPERATION_ABORTED)
+ continue;
#endif
- const int saved_errno = errno;
- if (feof(in))
- done = true;
- else if (ferror(in)) {
- if (saved_errno != EINTR)
- done = true;
- }
- } else {
- got_line = true;
- size_t buffer_len = strlen(buffer);
- assert(buffer[buffer_len] == '\0');
- char last_char = buffer[buffer_len - 1];
- if (last_char == '\r' || last_char == '\n') {
- done = true;
- // Strip trailing newlines
- while (last_char == '\r' || last_char == '\n') {
- --buffer_len;
- if (buffer_len == 0)
- break;
- last_char = buffer[buffer_len - 1];
- }
- }
- line.append(buffer, buffer_len);
- }
+ if (r == nullptr) {
+ if (ferror(in) && errno == EINTR)
+ continue;
+ if (feof(in))
+ got_line = SplitLineEOF(m_line_buffer);
+ break;
}
- m_editing = false;
- if (m_data_recorder && got_line)
- m_data_recorder->Record(line, true);
- // We might have gotten a newline on a line by itself make sure to return
- // true in this case.
- return got_line;
- } else {
- // No more input file, we are done...
- SetIsDone(true);
+ m_line_buffer += buffer;
+ got_line = SplitLine(m_line_buffer);
}
- return false;
-#ifndef LLDB_DISABLE_LIBEDIT
+ m_editing = false;
}
-#endif
+
+ if (got_line) {
+ line = got_line.getValue();
+ if (m_data_recorder)
+ m_data_recorder->Record(line, true);
+ }
+
+ return (bool)got_line;
}
#ifndef LLDB_DISABLE_LIBEDIT
@@ -445,16 +443,11 @@ int IOHandlerEditline::FixIndentationCallback(Editline *editline,
*editline_reader, lines, cursor_position);
}
-int IOHandlerEditline::AutoCompleteCallback(
- const char *current_line, const char *cursor, const char *last_char,
- int skip_first_n_matches, int max_matches, StringList &matches,
- StringList &descriptions, void *baton) {
+void IOHandlerEditline::AutoCompleteCallback(CompletionRequest &request,
+ void *baton) {
IOHandlerEditline *editline_reader = (IOHandlerEditline *)baton;
if (editline_reader)
- return editline_reader->m_delegate.IOHandlerComplete(
- *editline_reader, current_line, cursor, last_char, skip_first_n_matches,
- max_matches, matches, descriptions);
- return 0;
+ editline_reader->m_delegate.IOHandlerComplete(*editline_reader, request);
}
#endif
@@ -526,10 +519,11 @@ bool IOHandlerEditline::GetLines(StringList &lines, bool &interrupted) {
// Show line numbers if we are asked to
std::string line;
if (m_base_line_number > 0 && GetIsInteractive()) {
- FILE *out = GetOutputFILE();
- if (out)
- ::fprintf(out, "%u%s", m_base_line_number + (uint32_t)lines.GetSize(),
- GetPrompt() == nullptr ? " " : "");
+ if (m_output_sp) {
+ m_output_sp->Printf("%u%s",
+ m_base_line_number + (uint32_t)lines.GetSize(),
+ GetPrompt() == nullptr ? " " : "");
+ }
}
m_curr_line_idx = lines.GetSize();
@@ -615,7 +609,7 @@ void IOHandlerEditline::PrintAsync(Stream *stream, const char *s, size_t len) {
else
#endif
{
-#ifdef _MSC_VER
+#ifdef _WIN32
const char *prompt = GetPrompt();
if (prompt) {
// Back up over previous prompt using Windows API
@@ -630,9 +624,9 @@ void IOHandlerEditline::PrintAsync(Stream *stream, const char *s, size_t len) {
}
#endif
IOHandler::PrintAsync(stream, s, len);
-#ifdef _MSC_VER
+#ifdef _WIN32
if (prompt)
- IOHandler::PrintAsync(GetOutputStreamFile().get(), prompt,
+ IOHandler::PrintAsync(GetOutputStreamFileSP().get(), prompt,
strlen(prompt));
#endif
}
@@ -952,16 +946,9 @@ public:
}
void PutChar(int ch) { ::waddch(m_window, ch); }
void PutCString(const char *s, int len = -1) { ::waddnstr(m_window, s, len); }
- void Refresh() { ::wrefresh(m_window); }
- void DeferredRefresh() {
- // We are using panels, so we don't need to call this...
- //::wnoutrefresh(m_window);
- }
void SetBackground(int color_pair_idx) {
::wbkgd(m_window, COLOR_PAIR(color_pair_idx));
}
- void UnderlineOn() { AttributeOn(A_UNDERLINE); }
- void UnderlineOff() { AttributeOff(A_UNDERLINE); }
void PutCStringTruncated(const char *s, int right_pad) {
int bytes_left = GetWidth() - GetCursorX();
@@ -1213,19 +1200,6 @@ public:
return eKeyNotHandled;
}
- bool SetActiveWindow(Window *window) {
- const size_t num_subwindows = m_subwindows.size();
- for (size_t i = 0; i < num_subwindows; ++i) {
- if (m_subwindows[i].get() == window) {
- m_prev_active_window_idx = m_curr_active_window_idx;
- ::top_panel(window->m_panel);
- m_curr_active_window_idx = i;
- return true;
- }
- }
- return false;
- }
-
WindowSP GetActiveWindow() {
if (!m_subwindows.empty()) {
if (m_curr_active_window_idx >= m_subwindows.size()) {
@@ -1257,8 +1231,6 @@ public:
void SetCanBeActive(bool b) { m_can_activate = b; }
- const WindowDelegateSP &GetDelegate() const { return m_delegate_sp; }
-
void SetDelegate(const WindowDelegateSP &delegate_sp) {
m_delegate_sp = delegate_sp;
}
@@ -1410,12 +1382,8 @@ public:
int GetKeyValue() const { return m_key_value; }
- void SetKeyValue(int key_value) { m_key_value = key_value; }
-
std::string &GetName() { return m_name; }
- std::string &GetKeyName() { return m_key_name; }
-
int GetDrawWidth() const {
return m_max_submenu_name_length + m_max_submenu_key_name_length + 8;
}
@@ -1569,7 +1537,6 @@ bool Menu::WindowDelegateDraw(Window &window, bool force) {
menu->DrawMenuTitle(window, false);
}
window.PutCString(" |");
- window.DeferredRefresh();
} break;
case Menu::Type::Item: {
@@ -1592,7 +1559,6 @@ bool Menu::WindowDelegateDraw(Window &window, bool force) {
submenus[i]->DrawMenuTitle(window, is_selected);
}
window.MoveCursor(cursor_x, cursor_y);
- window.DeferredRefresh();
} break;
default:
@@ -1898,8 +1864,6 @@ public:
return m_window_sp;
}
- WindowDelegates &GetWindowDelegates() { return m_window_delegates; }
-
protected:
WindowSP m_window_sp;
WindowDelegates m_window_delegates;
@@ -1936,9 +1900,7 @@ struct Row {
return 0;
}
- void Expand() {
- expanded = true;
- }
+ void Expand() { expanded = true; }
std::vector<Row> &GetChildren() {
ProcessSP process_sp = value.GetProcessSP();
@@ -2293,8 +2255,6 @@ public:
m_selected_item = nullptr;
}
- window.DeferredRefresh();
-
return true; // Drawing handled
}
@@ -2644,14 +2604,12 @@ protected:
class ValueObjectListDelegate : public WindowDelegate {
public:
ValueObjectListDelegate()
- : m_rows(), m_selected_row(nullptr),
- m_selected_row_idx(0), m_first_visible_row(0), m_num_rows(0),
- m_max_x(0), m_max_y(0) {}
+ : m_rows(), m_selected_row(nullptr), m_selected_row_idx(0),
+ m_first_visible_row(0), m_num_rows(0), m_max_x(0), m_max_y(0) {}
ValueObjectListDelegate(ValueObjectList &valobj_list)
- : m_rows(), m_selected_row(nullptr),
- m_selected_row_idx(0), m_first_visible_row(0), m_num_rows(0),
- m_max_x(0), m_max_y(0) {
+ : m_rows(), m_selected_row(nullptr), m_selected_row_idx(0),
+ m_first_visible_row(0), m_num_rows(0), m_max_x(0), m_max_y(0) {
SetValues(valobj_list);
}
@@ -2694,8 +2652,6 @@ public:
DisplayRows(window, m_rows, g_options);
- window.DeferredRefresh();
-
// Get the selected row
m_selected_row = GetRowForRowIndex(m_selected_row_idx);
// Keep the cursor on the selected row so the highlight and the cursor are
@@ -3800,7 +3756,6 @@ public:
window.Printf(" with status = %i", exit_status);
}
}
- window.DeferredRefresh();
return true;
}
@@ -4258,7 +4213,6 @@ public:
}
}
}
- window.DeferredRefresh();
return true; // Drawing handled
}