summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/include/lldb/Core/IOHandler.h1
-rw-r--r--lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py7
-rw-r--r--lldb/source/Core/IOHandler.cpp171
3 files changed, 105 insertions, 74 deletions
diff --git a/lldb/include/lldb/Core/IOHandler.h b/lldb/include/lldb/Core/IOHandler.h
index 0c50a2d80a9..37142a5a839 100644
--- a/lldb/include/lldb/Core/IOHandler.h
+++ b/lldb/include/lldb/Core/IOHandler.h
@@ -431,6 +431,7 @@ protected:
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
index a977ec95965..577c6b3e88f 100644
--- a/lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py
+++ b/lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py
@@ -399,9 +399,9 @@ class FileHandleTestCase(lldbtest.TestBase):
@add_test_categories(['pyapi'])
- @expectedFailureAll() # 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())
@@ -412,10 +412,11 @@ class FileHandleTestCase(lldbtest.TestBase):
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'])
- @expectedFailureAll() # 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
index d3152981a56..46be29f6fbf 100644
--- a/lldb/source/Core/IOHandler.cpp
+++ b/lldb/source/Core/IOHandler.cpp
@@ -70,6 +70,10 @@
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,
@@ -306,94 +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]) {
- if (m_output_sp) {
- m_output_sp->Printf("%s", prompt);
- m_output_sp->Flush();
- }
- }
+ if (prompt == nullptr)
+ prompt = GetPrompt();
+
+ if (prompt && prompt[0]) {
+ if (m_output_sp) {
+ m_output_sp->Printf("%s", prompt);
+ m_output_sp->Flush();
+ }
+ }
+ }
+
+ 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;
}
- char buffer[256];
- bool done = false;
- bool got_line = false;
- m_editing = true;
- while (!done) {
+ 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) {
- // this is the equivalent of EINTR for Windows
- if (GetLastError() == ERROR_OPERATION_ABORTED)
- continue;
-#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
OpenPOWER on IntegriCloud