diff --git a/lldb/include/lldb/Core/IOHandler.h b/lldb/include/lldb/Core/IOHandler.h --- a/lldb/include/lldb/Core/IOHandler.h +++ b/lldb/include/lldb/Core/IOHandler.h @@ -431,6 +431,7 @@ bool m_interrupt_exits; bool m_editing; // Set to true when fetching a line manually (not using // libedit) + std::string m_line_buffer; }; // The order of base classes is important. Look at the constructor of diff --git a/lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py b/lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py --- a/lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py +++ b/lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py @@ -400,9 +400,9 @@ @add_test_categories(['pyapi']) - @expectedFailure # FIXME IOHandler still using FILE* + @skipIf(py_version=['<', (3,)]) def test_string_inout(self): - inf = io.StringIO("help help\n") + inf = io.StringIO("help help\np/x ~0\n") outf = io.StringIO() status = self.debugger.SetOutputFile(lldb.SBFile(outf)) self.assertTrue(status.Success()) @@ -413,10 +413,11 @@ self.debugger.GetOutputFile().Flush() output = outf.getvalue() self.assertIn('Show a list of all debugger commands', output) + self.assertIn('0xfff', output) @add_test_categories(['pyapi']) - @expectedFailure # FIXME IOHandler still using FILE* + @skipIf(py_version=['<', (3,)]) def test_bytes_inout(self): inf = io.BytesIO(b"help help\nhelp b\n") outf = io.BytesIO() diff --git a/lldb/source/Core/IOHandler.cpp b/lldb/source/Core/IOHandler.cpp --- a/lldb/source/Core/IOHandler.cpp +++ b/lldb/source/Core/IOHandler.cpp @@ -316,27 +316,71 @@ #endif line.clear(); + if (GetIsInteractive()) { + const char *prompt = nullptr; + + if (m_multi_line && m_curr_line_idx > 0) + prompt = GetContinuationPrompt(); + + if (prompt == nullptr) + prompt = GetPrompt(); + + if (prompt && prompt[0]) { + if (m_output_sp) { + m_output_sp->Printf("%s", prompt); + m_output_sp->Flush(); + } + } + } + FILE *in = GetInputFILE(); - if (in) { - if (GetIsInteractive()) { - const char *prompt = nullptr; + char buffer[256]; + bool done = false; + bool got_line = false; - if (m_multi_line && m_curr_line_idx > 0) - prompt = GetContinuationPrompt(); + if (!in && m_input_sp) { + // there is no FILE*, fall back on just reading bytes from the stream. - if (prompt == nullptr) - prompt = GetPrompt(); + size_t pos = m_line_buffer.find('\n'); + if (pos != std::string::npos) { + size_t end = pos; + while (end > 0 && + (m_line_buffer[end] == '\n' || m_line_buffer[end] == '\r')) + end--; + line = m_line_buffer.substr(0, end + 1); + m_line_buffer = m_line_buffer.substr(pos + 1); + done = true; + got_line = true; + } - if (prompt && prompt[0]) { - if (m_output_sp) { - m_output_sp->Printf("%s", prompt); - m_output_sp->Flush(); + while (!done) { + size_t bytes_read = sizeof(buffer); + m_input_sp->Read((void *)buffer, bytes_read); + if (bytes_read) { + auto bytes = llvm::StringRef(buffer, bytes_read); + size_t pos = bytes.find('\n'); + if (pos != llvm::StringRef::npos) { + size_t end = pos; + while (end > 0 && (bytes[end] == '\n' || bytes[end] == '\r')) + end--; + line = m_line_buffer; + line.append(bytes.substr(0, end + 1)); + m_line_buffer = bytes.substr(pos + 1); + done = true; + got_line = true; + } else { + m_line_buffer.append(bytes); } + } else { + // No more input file, we are done... + SetIsDone(true); + done = true; } } - char buffer[256]; - bool done = false; - bool got_line = false; + return got_line; + } + + if (in) { m_editing = true; while (!done) { #ifdef _WIN32