lawrence_danna created this revision.
lawrence_danna added reviewers: JDevlieghere, jasonmolenda, labath, lanza.
Herald added a project: LLDB.

IOHandler needs to read lines of input from a lldb::File.   
The way it currently does this using, FILE*, which is something
we want to avoid now.   I'd prefer to just replace the FILE* code
with calls to File::Read, but it contains an awkward and 
delicate workaround specific to ctrl-C handling on windows, and
it's not clear if or how that workaround would translate to 
lldb::File.

So in this patch, we use use the FILE* if it's available, and only
fall back on File::Read if that's the only option.

I think this is a reasonable approach here for two reasons.  First 
is that interactive terminal support is the one area where FILE*
can't be avoided.   We need them for libedit and curses anyway, 
and using them here as well is consistent with that pattern.

The second reason is that the comments express a hope that the 
underlying windows bug that's being worked around will be fixed one 
day, so hopefully when that happens, that whole path can be deleted.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D68622

Files:
  lldb/include/lldb/Core/IOHandler.h
  lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py
  lldb/source/Core/IOHandler.cpp

Index: lldb/source/Core/IOHandler.cpp
===================================================================
--- lldb/source/Core/IOHandler.cpp
+++ 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
Index: lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py
+++ 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()
Index: lldb/include/lldb/Core/IOHandler.h
===================================================================
--- lldb/include/lldb/Core/IOHandler.h
+++ 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
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to