mgorny updated this revision to Diff 377949.
mgorny added a comment.

Remove the changes to ConnectionFileDescriptorPosix from this patch. Now it's 
purely new Terminal API.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111030/new/

https://reviews.llvm.org/D111030

Files:
  lldb/include/lldb/Host/Terminal.h
  lldb/source/Host/common/Terminal.cpp
  lldb/unittests/Host/posix/TerminalTest.cpp

Index: lldb/unittests/Host/posix/TerminalTest.cpp
===================================================================
--- lldb/unittests/Host/posix/TerminalTest.cpp
+++ lldb/unittests/Host/posix/TerminalTest.cpp
@@ -68,6 +68,132 @@
   EXPECT_EQ(terminfo.c_lflag & ICANON, 0U);
 }
 
+TEST_F(TerminalTest, SetRaw) {
+  struct termios terminfo;
+  Terminal term{m_pty.GetPrimaryFileDescriptor()};
+
+  ASSERT_EQ(term.SetRaw(), true);
+  ASSERT_EQ(tcgetattr(m_pty.GetPrimaryFileDescriptor(), &terminfo), 0);
+  // NB: cfmakeraw() on glibc disables IGNBRK, on FreeBSD sets it
+  EXPECT_EQ(terminfo.c_iflag &
+                (BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON),
+            0U);
+  EXPECT_EQ(terminfo.c_oflag & OPOST, 0U);
+  EXPECT_EQ(terminfo.c_lflag & (ICANON | ECHO | ISIG | IEXTEN), 0U);
+  EXPECT_EQ(terminfo.c_cflag & (CSIZE | PARENB), 0U | CS8);
+  EXPECT_EQ(terminfo.c_cc[VMIN], 1);
+  EXPECT_EQ(terminfo.c_cc[VTIME], 0);
+}
+
+TEST_F(TerminalTest, SetBaudRate) {
+  struct termios terminfo;
+  Terminal term{m_pty.GetPrimaryFileDescriptor()};
+
+  ASSERT_EQ(term.SetBaudRate(38400), true);
+  ASSERT_EQ(tcgetattr(m_pty.GetPrimaryFileDescriptor(), &terminfo), 0);
+  EXPECT_EQ(cfgetispeed(&terminfo), static_cast<speed_t>(B38400));
+  EXPECT_EQ(cfgetospeed(&terminfo), static_cast<speed_t>(B38400));
+
+  ASSERT_EQ(term.SetBaudRate(115200), true);
+  ASSERT_EQ(tcgetattr(m_pty.GetPrimaryFileDescriptor(), &terminfo), 0);
+  EXPECT_EQ(cfgetispeed(&terminfo), static_cast<speed_t>(B115200));
+  EXPECT_EQ(cfgetospeed(&terminfo), static_cast<speed_t>(B115200));
+
+  // uncommon value
+#if defined(B153600)
+  ASSERT_EQ(term.SetBaudRate(153600), true);
+  ASSERT_EQ(tcgetattr(m_pty.GetPrimaryFileDescriptor(), &terminfo), 0);
+  EXPECT_EQ(cfgetispeed(&terminfo), static_cast<speed_t>(B153600));
+  EXPECT_EQ(cfgetospeed(&terminfo), static_cast<speed_t>(B153600));
+#else
+  EXPECT_EQ(term.SetBaudRate(153600), false);
+#endif
+}
+
+TEST_F(TerminalTest, SetStopBits) {
+  struct termios terminfo;
+  Terminal term{m_pty.GetPrimaryFileDescriptor()};
+
+  ASSERT_EQ(term.SetStopBits(1), true);
+  ASSERT_EQ(tcgetattr(m_pty.GetPrimaryFileDescriptor(), &terminfo), 0);
+  EXPECT_EQ(terminfo.c_cflag & CSTOPB, 0U);
+
+  ASSERT_EQ(term.SetStopBits(2), true);
+  ASSERT_EQ(tcgetattr(m_pty.GetPrimaryFileDescriptor(), &terminfo), 0);
+  EXPECT_NE(terminfo.c_cflag & CSTOPB, 0U);
+
+  ASSERT_EQ(term.SetStopBits(0), false);
+  ASSERT_EQ(term.SetStopBits(3), false);
+}
+
+TEST_F(TerminalTest, SetParity) {
+  struct termios terminfo;
+  Terminal term{m_pty.GetPrimaryFileDescriptor()};
+
+  ASSERT_EQ(term.SetParity(TerminalParity::No), true);
+  ASSERT_EQ(tcgetattr(m_pty.GetPrimaryFileDescriptor(), &terminfo), 0);
+  EXPECT_EQ(terminfo.c_cflag & PARENB, 0U);
+
+  ASSERT_EQ(term.SetParity(TerminalParity::Even), true);
+  ASSERT_EQ(tcgetattr(m_pty.GetPrimaryFileDescriptor(), &terminfo), 0);
+#if !defined(__linux__) // Linux pty devices strip PARENB
+  EXPECT_NE(terminfo.c_cflag & PARENB, 0U);
+#endif
+  EXPECT_EQ(terminfo.c_cflag & PARODD, 0U);
+#if defined(CMSPAR)
+  EXPECT_EQ(terminfo.c_cflag & CMSPAR, 0U);
+#endif
+
+  ASSERT_EQ(term.SetParity(TerminalParity::Odd), true);
+  ASSERT_EQ(tcgetattr(m_pty.GetPrimaryFileDescriptor(), &terminfo), 0);
+#if !defined(__linux__) // Linux pty devices strip PARENB
+  EXPECT_NE(terminfo.c_cflag & PARENB, 0U);
+#endif
+  EXPECT_NE(terminfo.c_cflag & PARODD, 0U);
+#if defined(CMSPAR)
+  EXPECT_EQ(terminfo.c_cflag & CMSPAR, 0U);
+#endif
+
+#if defined(CMSPAR)
+  ASSERT_EQ(term.SetParity(TerminalParity::Space), true);
+  ASSERT_EQ(tcgetattr(m_pty.GetPrimaryFileDescriptor(), &terminfo), 0);
+#if !defined(__linux__) // Linux pty devices strip PARENB
+  EXPECT_NE(terminfo.c_cflag & PARENB, 0U);
+#endif
+  EXPECT_EQ(terminfo.c_cflag & PARODD, 0U);
+  EXPECT_NE(terminfo.c_cflag & CMSPAR, 0U);
+
+  ASSERT_EQ(term.SetParity(TerminalParity::Mark), true);
+  ASSERT_EQ(tcgetattr(m_pty.GetPrimaryFileDescriptor(), &terminfo), 0);
+#if !defined(__linux__) // Linux pty devices strip PARENB
+  EXPECT_NE(terminfo.c_cflag & PARENB, 0U);
+#endif
+  EXPECT_NE(terminfo.c_cflag & PARODD, 0U);
+  EXPECT_NE(terminfo.c_cflag & CMSPAR, 0U);
+#else
+  EXPECT_EQ(term.SetParity(TerminalParity::Space), false);
+  EXPECT_EQ(term.SetParity(TerminalParity::Mark), false);
+#endif
+}
+
+TEST_F(TerminalTest, SetHardwareFlowControl) {
+  struct termios terminfo;
+  Terminal term{m_pty.GetPrimaryFileDescriptor()};
+
+#if defined(CRTSCTS)
+  ASSERT_EQ(term.SetHardwareFlowControl(true), true);
+  ASSERT_EQ(tcgetattr(m_pty.GetPrimaryFileDescriptor(), &terminfo), 0);
+  EXPECT_NE(terminfo.c_cflag & CRTSCTS, 0U);
+
+  ASSERT_EQ(term.SetHardwareFlowControl(false), true);
+  ASSERT_EQ(tcgetattr(m_pty.GetPrimaryFileDescriptor(), &terminfo), 0);
+  EXPECT_EQ(terminfo.c_cflag & CRTSCTS, 0U);
+#else
+  ASSERT_EQ(term.SetHardwareFlowControl(true), false);
+  ASSERT_EQ(term.SetHardwareFlowControl(false), true);
+#endif
+}
+
 TEST_F(TerminalTest, SaveRestoreRAII) {
   struct termios orig_terminfo;
   struct termios terminfo;
Index: lldb/source/Host/common/Terminal.cpp
===================================================================
--- lldb/source/Host/common/Terminal.cpp
+++ lldb/source/Host/common/Terminal.cpp
@@ -81,6 +81,299 @@
   return false;
 }
 
+bool Terminal::SetRaw() {
+#if LLDB_ENABLE_TERMIOS
+  if (IsATerminal()) {
+    struct termios fd_termios;
+    if (::tcgetattr(m_fd, &fd_termios) == 0) {
+      ::cfmakeraw(&fd_termios);
+
+      // Make sure only one character is needed to return from a read
+      // (cfmakeraw() doesn't do this on NetBSD)
+      fd_termios.c_cc[VMIN] = 1;
+      fd_termios.c_cc[VTIME] = 0;
+
+      return ::tcsetattr(m_fd, TCSANOW, &fd_termios) == 0;
+    }
+  }
+#endif // #if LLDB_ENABLE_TERMIOS
+  return false;
+}
+
+static llvm::Optional<speed_t> baudRateToConst(unsigned int baud_rate) {
+  switch (baud_rate) {
+#if defined(B0)
+  case 0:
+    return B0;
+#endif
+#if defined(B50)
+  case 50:
+    return B50;
+#endif
+#if defined(B75)
+  case 75:
+    return B75;
+#endif
+#if defined(B110)
+  case 110:
+    return B110;
+#endif
+#if defined(B134)
+  case 134:
+    return B134;
+#endif
+#if defined(B150)
+  case 150:
+    return B150;
+#endif
+#if defined(B200)
+  case 200:
+    return B200;
+#endif
+#if defined(B300)
+  case 300:
+    return B300;
+#endif
+#if defined(B600)
+  case 600:
+    return B600;
+#endif
+#if defined(B1200)
+  case 1200:
+    return B1200;
+#endif
+#if defined(B1800)
+  case 1800:
+    return B1800;
+#endif
+#if defined(B2400)
+  case 2400:
+    return B2400;
+#endif
+#if defined(B4800)
+  case 4800:
+    return B4800;
+#endif
+#if defined(B9600)
+  case 9600:
+    return B9600;
+#endif
+#if defined(B19200)
+  case 19200:
+    return B19200;
+#endif
+#if defined(B38400)
+  case 38400:
+    return B38400;
+#endif
+#if defined(B57600)
+  case 57600:
+    return B57600;
+#endif
+#if defined(B115200)
+  case 115200:
+    return B115200;
+#endif
+#if defined(B230400)
+  case 230400:
+    return B230400;
+#endif
+#if defined(B460800)
+  case 460800:
+    return B460800;
+#endif
+#if defined(B500000)
+  case 500000:
+    return B500000;
+#endif
+#if defined(B576000)
+  case 576000:
+    return B576000;
+#endif
+#if defined(B921600)
+  case 921600:
+    return B921600;
+#endif
+#if defined(B1000000)
+  case 1000000:
+    return B1000000;
+#endif
+#if defined(B1152000)
+  case 1152000:
+    return B1152000;
+#endif
+#if defined(B1500000)
+  case 1500000:
+    return B1500000;
+#endif
+#if defined(B2000000)
+  case 2000000:
+    return B2000000;
+#endif
+#if defined(B76800)
+  case 76800:
+    return B76800;
+#endif
+#if defined(B153600)
+  case 153600:
+    return B153600;
+#endif
+#if defined(B307200)
+  case 307200:
+    return B307200;
+#endif
+#if defined(B614400)
+  case 614400:
+    return B614400;
+#endif
+#if defined(B2500000)
+  case 2500000:
+    return B2500000;
+#endif
+#if defined(B3000000)
+  case 3000000:
+    return B3000000;
+#endif
+#if defined(B3500000)
+  case 3500000:
+    return B3500000;
+#endif
+#if defined(B4000000)
+  case 4000000:
+    return B4000000;
+#endif
+  default:
+    return llvm::None;
+  }
+}
+
+bool Terminal::SetBaudRate(unsigned int baud_rate) {
+#if LLDB_ENABLE_TERMIOS
+  if (IsATerminal()) {
+    struct termios fd_termios;
+    if (::tcgetattr(m_fd, &fd_termios) == 0) {
+      llvm::Optional<speed_t> val = baudRateToConst(baud_rate);
+      if (!val) // invalid value
+        return false;
+      if (::cfsetispeed(&fd_termios, val.getValue()) != 0)
+        return false;
+      if (::cfsetospeed(&fd_termios, val.getValue()) != 0)
+        return false;
+      return ::tcsetattr(m_fd, TCSANOW, &fd_termios) == 0;
+    }
+  }
+#endif // #if LLDB_ENABLE_TERMIOS
+  return false;
+}
+
+bool Terminal::SetStopBits(unsigned int stop_bits) {
+#if LLDB_ENABLE_TERMIOS
+  if (IsATerminal()) {
+    struct termios fd_termios;
+    if (::tcgetattr(m_fd, &fd_termios) == 0) {
+      switch (stop_bits) {
+      case 1:
+        fd_termios.c_cflag &= ~CSTOPB;
+        break;
+      case 2:
+        fd_termios.c_cflag |= CSTOPB;
+        break;
+      default:
+        return false;
+      }
+      return ::tcsetattr(m_fd, TCSANOW, &fd_termios) == 0;
+    }
+  }
+#endif // #if LLDB_ENABLE_TERMIOS
+  return false;
+}
+
+bool Terminal::SetParity(TerminalParity parity) {
+#if LLDB_ENABLE_TERMIOS
+  if (IsATerminal()) {
+    struct termios fd_termios;
+    if (::tcgetattr(m_fd, &fd_termios) == 0) {
+      bool parity_bit = true;
+      bool odd_bit = false;
+      bool stick_bit = false;
+
+      switch (parity) {
+      case TerminalParity::No:
+        parity_bit = false;
+        break;
+      case TerminalParity::Even:
+        break;
+      case TerminalParity::Odd:
+        odd_bit = true;
+        break;
+      case TerminalParity::Space:
+        stick_bit = true;
+        break;
+      case TerminalParity::Mark:
+        stick_bit = true;
+        odd_bit = true;
+        break;
+      }
+
+      if (!parity_bit)
+        fd_termios.c_cflag &= ~PARENB;
+      else {
+        fd_termios.c_cflag |= PARENB;
+        if (odd_bit)
+          fd_termios.c_cflag |= PARODD;
+        else
+          fd_termios.c_cflag &= ~PARODD;
+#if defined(CMSPAR)
+        if (stick_bit)
+          fd_termios.c_cflag |= CMSPAR;
+        else
+          fd_termios.c_cflag &= ~CMSPAR;
+#else
+        if (stick_bit)
+          return false;
+#endif
+      }
+
+      return ::tcsetattr(m_fd, TCSANOW, &fd_termios) == 0;
+    }
+  }
+#endif // #if LLDB_ENABLE_TERMIOS
+  return false;
+}
+
+bool Terminal::SetHardwareFlowControl(bool enabled) {
+  if (FileDescriptorIsValid()) {
+#if LLDB_ENABLE_TERMIOS
+    if (IsATerminal()) {
+#if defined(CRTSCTS)
+      struct termios fd_termios;
+      if (::tcgetattr(m_fd, &fd_termios) == 0) {
+        bool set_corectly = false;
+        if (enabled) {
+          if (fd_termios.c_cflag & CRTSCTS)
+            set_corectly = true;
+          else
+            fd_termios.c_cflag |= CRTSCTS;
+        } else {
+          if (fd_termios.c_cflag & CRTSCTS)
+            fd_termios.c_cflag &= ~CRTSCTS;
+          else
+            set_corectly = true;
+        }
+
+        if (set_corectly)
+          return true;
+        return ::tcsetattr(m_fd, TCSANOW, &fd_termios) == 0;
+      }
+#else // !defined(CRTSCTS)
+      return !enabled;
+#endif
+    }
+#endif // #if LLDB_ENABLE_TERMIOS
+  }
+  return false;
+}
+
 struct TerminalState::Data {
 #if LLDB_ENABLE_TERMIOS
   struct termios m_termios; ///< Cached terminal state information.
Index: lldb/include/lldb/Host/Terminal.h
===================================================================
--- lldb/include/lldb/Host/Terminal.h
+++ lldb/include/lldb/Host/Terminal.h
@@ -15,6 +15,14 @@
 
 namespace lldb_private {
 
+enum class TerminalParity {
+  No,
+  Even,
+  Odd,
+  Space,
+  Mark,
+};
+
 class Terminal {
 public:
   Terminal(int fd = -1) : m_fd(fd) {}
@@ -35,6 +43,16 @@
 
   bool SetCanonical(bool enabled);
 
+  bool SetRaw();
+
+  bool SetBaudRate(unsigned int baud_rate);
+
+  bool SetStopBits(unsigned int stop_bits);
+
+  bool SetParity(TerminalParity parity);
+
+  bool SetHardwareFlowControl(bool enabled);
+
 protected:
   int m_fd; // This may or may not be a terminal file descriptor
 };
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to