labath created this revision.
labath added reviewers: clayborg, zturner.
labath added a subscriber: lldb-commits.

To implement wide character reading, editline was mixing FILE*-based access with
a Connection-based one (plus it did some selects on the raw FD), which is very
fragile. Here, I replace it with one which uses only a Connection-based reads.
The code is somewhat longer as I had to read characters one by one to detect the
end of the multibyte sequence.

I've verified that international characters still work in lldb command line on
OSX.


https://reviews.llvm.org/D28356

Files:
  include/lldb/Host/Editline.h
  source/Host/common/Editline.cpp


Index: source/Host/common/Editline.cpp
===================================================================
--- source/Host/common/Editline.cpp
+++ source/Host/common/Editline.cpp
@@ -526,17 +526,8 @@
     }
 
     if (read_count) {
-#if LLDB_EDITLINE_USE_WCHAR
-      // After the initial interruptible read, this is guaranteed not to block
-      ungetc(ch, m_input_file);
-      *c = fgetwc(m_input_file);
-      if (*c != WEOF)
-        return 1;
-#else
-      *c = ch;
-      if (ch != (char)EOF)
+      if (CompleteCharacter(ch, *c))
         return 1;
-#endif
     } else {
       switch (status) {
       case lldb::eConnectionStatusSuccess: // Success
@@ -1367,3 +1358,39 @@
     MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);
   }
 }
+
+bool Editline::CompleteCharacter(char ch, EditLineCharType &out) {
+#if !LLDB_EDITLINE_USE_WCHAR
+  if (ch == (char)EOF)
+    return false;
+
+  out = ch;
+  return true;
+#else
+  std::codecvt_utf8<wchar_t> cvt;
+  llvm::SmallString<4> input;
+  for (;;) {
+    const char *from_next;
+    wchar_t *to_next;
+    std::mbstate_t state = std::mbstate_t();
+    input.push_back(ch);
+    switch (cvt.in(state, input.begin(), input.end(), from_next, &out, &out + 
1,
+                   to_next)) {
+    case std::codecvt_base::ok:
+      return out != WEOF;
+
+    case std::codecvt_base::error:
+    case std::codecvt_base::noconv:
+      return false;
+
+    case std::codecvt_base::partial:
+      lldb::ConnectionStatus status;
+      size_t read_count = m_input_connection.Read(
+          &ch, 1, std::chrono::seconds(0), status, nullptr);
+      if (read_count == 0)
+        return false;
+      break;
+    }
+  }
+#endif
+}
Index: include/lldb/Host/Editline.h
===================================================================
--- include/lldb/Host/Editline.h
+++ include/lldb/Host/Editline.h
@@ -322,6 +322,8 @@
   /// single or multi-line editing.
   void ConfigureEditor(bool multiline);
 
+  bool CompleteCharacter(char ch, EditLineCharType &out);
+
 private:
 #if LLDB_EDITLINE_USE_WCHAR
   std::wstring_convert<std::codecvt_utf8<wchar_t>> m_utf8conv;


Index: source/Host/common/Editline.cpp
===================================================================
--- source/Host/common/Editline.cpp
+++ source/Host/common/Editline.cpp
@@ -526,17 +526,8 @@
     }
 
     if (read_count) {
-#if LLDB_EDITLINE_USE_WCHAR
-      // After the initial interruptible read, this is guaranteed not to block
-      ungetc(ch, m_input_file);
-      *c = fgetwc(m_input_file);
-      if (*c != WEOF)
-        return 1;
-#else
-      *c = ch;
-      if (ch != (char)EOF)
+      if (CompleteCharacter(ch, *c))
         return 1;
-#endif
     } else {
       switch (status) {
       case lldb::eConnectionStatusSuccess: // Success
@@ -1367,3 +1358,39 @@
     MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);
   }
 }
+
+bool Editline::CompleteCharacter(char ch, EditLineCharType &out) {
+#if !LLDB_EDITLINE_USE_WCHAR
+  if (ch == (char)EOF)
+    return false;
+
+  out = ch;
+  return true;
+#else
+  std::codecvt_utf8<wchar_t> cvt;
+  llvm::SmallString<4> input;
+  for (;;) {
+    const char *from_next;
+    wchar_t *to_next;
+    std::mbstate_t state = std::mbstate_t();
+    input.push_back(ch);
+    switch (cvt.in(state, input.begin(), input.end(), from_next, &out, &out + 1,
+                   to_next)) {
+    case std::codecvt_base::ok:
+      return out != WEOF;
+
+    case std::codecvt_base::error:
+    case std::codecvt_base::noconv:
+      return false;
+
+    case std::codecvt_base::partial:
+      lldb::ConnectionStatus status;
+      size_t read_count = m_input_connection.Read(
+          &ch, 1, std::chrono::seconds(0), status, nullptr);
+      if (read_count == 0)
+        return false;
+      break;
+    }
+  }
+#endif
+}
Index: include/lldb/Host/Editline.h
===================================================================
--- include/lldb/Host/Editline.h
+++ include/lldb/Host/Editline.h
@@ -322,6 +322,8 @@
   /// single or multi-line editing.
   void ConfigureEditor(bool multiline);
 
+  bool CompleteCharacter(char ch, EditLineCharType &out);
+
 private:
 #if LLDB_EDITLINE_USE_WCHAR
   std::wstring_convert<std::codecvt_utf8<wchar_t>> m_utf8conv;
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
  • [Lldb-commits] [PATCH] D2835... Pavel Labath via Phabricator via lldb-commits

Reply via email to