This revision was automatically updated to reflect the committed changes.
Closed by commit rG92fb574c9f20: [lldb] [Host] Add setters for common teletype 
properties to Terminal (authored by mgorny).
Herald added a project: LLDB.

Changed prior to commit:
  https://reviews.llvm.org/D111030?vs=380943&id=381173#toc

Repository:
  rG LLVM Github Monorepo

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
@@ -72,6 +72,149 @@
   EXPECT_EQ(terminfo.c_lflag & ICANON, 0U);
 }
 
+TEST_F(TerminalTest, SetRaw) {
+  struct termios terminfo;
+
+  ASSERT_THAT_ERROR(m_term.SetRaw(), llvm::Succeeded());
+  ASSERT_EQ(tcgetattr(m_fd, &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;
+
+  ASSERT_THAT_ERROR(m_term.SetBaudRate(38400), llvm::Succeeded());
+  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);
+  EXPECT_EQ(cfgetispeed(&terminfo), static_cast<speed_t>(B38400));
+  EXPECT_EQ(cfgetospeed(&terminfo), static_cast<speed_t>(B38400));
+
+  ASSERT_THAT_ERROR(m_term.SetBaudRate(115200), llvm::Succeeded());
+  ASSERT_EQ(tcgetattr(m_fd, &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_THAT_ERROR(m_term.SetBaudRate(153600), llvm::Succeeded());
+  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);
+  EXPECT_EQ(cfgetispeed(&terminfo), static_cast<speed_t>(B153600));
+  EXPECT_EQ(cfgetospeed(&terminfo), static_cast<speed_t>(B153600));
+#else
+  ASSERT_THAT_ERROR(m_term.SetBaudRate(153600),
+                    llvm::Failed<llvm::ErrorInfoBase>(testing::Property(
+                        &llvm::ErrorInfoBase::message,
+                        "baud rate 153600 unsupported by the platform")));
+#endif
+}
+
+TEST_F(TerminalTest, SetStopBits) {
+  struct termios terminfo;
+
+  ASSERT_THAT_ERROR(m_term.SetStopBits(1), llvm::Succeeded());
+  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);
+  EXPECT_EQ(terminfo.c_cflag & CSTOPB, 0U);
+
+  ASSERT_THAT_ERROR(m_term.SetStopBits(2), llvm::Succeeded());
+  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);
+  EXPECT_NE(terminfo.c_cflag & CSTOPB, 0U);
+
+  ASSERT_THAT_ERROR(m_term.SetStopBits(0),
+                    llvm::Failed<llvm::ErrorInfoBase>(testing::Property(
+                        &llvm::ErrorInfoBase::message,
+                        "invalid stop bit count: 0 (must be 1 or 2)")));
+  ASSERT_THAT_ERROR(m_term.SetStopBits(3),
+                    llvm::Failed<llvm::ErrorInfoBase>(testing::Property(
+                        &llvm::ErrorInfoBase::message,
+                        "invalid stop bit count: 3 (must be 1 or 2)")));
+}
+
+TEST_F(TerminalTest, SetParity) {
+  struct termios terminfo;
+
+  ASSERT_THAT_ERROR(m_term.SetParity(Terminal::Parity::No), llvm::Succeeded());
+  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);
+  EXPECT_EQ(terminfo.c_cflag & PARENB, 0U);
+
+  ASSERT_THAT_ERROR(m_term.SetParity(Terminal::Parity::Even),
+                    llvm::Succeeded());
+  ASSERT_EQ(tcgetattr(m_fd, &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_THAT_ERROR(m_term.SetParity(Terminal::Parity::Odd), llvm::Succeeded());
+  ASSERT_EQ(tcgetattr(m_fd, &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_THAT_ERROR(m_term.SetParity(Terminal::Parity::Space),
+                    llvm::Succeeded());
+  ASSERT_EQ(tcgetattr(m_fd, &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_THAT_ERROR(m_term.SetParity(Terminal::Parity::Mark),
+                    llvm::Succeeded());
+  ASSERT_EQ(tcgetattr(m_fd, &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
+  ASSERT_THAT_ERROR(m_term.SetParity(Terminal::Parity::Space),
+                    llvm::Failed<llvm::ErrorInfoBase>(testing::Property(
+                        &llvm::ErrorInfoBase::message,
+                        "space/mark parity is not supported by the platform")));
+  ASSERT_THAT_ERROR(m_term.SetParity(Terminal::Parity::Mark),
+                    llvm::Failed<llvm::ErrorInfoBase>(testing::Property(
+                        &llvm::ErrorInfoBase::message,
+                        "space/mark parity is not supported by the platform")));
+#endif
+}
+
+TEST_F(TerminalTest, SetHardwareFlowControl) {
+#if defined(CRTSCTS)
+  struct termios terminfo;
+
+  ASSERT_THAT_ERROR(m_term.SetHardwareFlowControl(true), llvm::Succeeded());
+  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);
+  EXPECT_NE(terminfo.c_cflag & CRTSCTS, 0U);
+
+  ASSERT_THAT_ERROR(m_term.SetHardwareFlowControl(false), llvm::Succeeded());
+  ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);
+  EXPECT_EQ(terminfo.c_cflag & CRTSCTS, 0U);
+#else
+  ASSERT_THAT_ERROR(
+      m_term.SetHardwareFlowControl(true),
+      llvm::Failed<llvm::ErrorInfoBase>(testing::Property(
+          &llvm::ErrorInfoBase::message,
+          "hardware flow control is not supported by the platform")));
+  ASSERT_THAT_ERROR(m_term.SetHardwareFlowControl(false), llvm::Succeeded());
+#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
@@ -94,6 +94,267 @@
 #endif // LLDB_ENABLE_TERMIOS
 }
 
+llvm::Error Terminal::SetRaw() {
+  llvm::Expected<Data> data = GetData();
+  if (!data)
+    return data.takeError();
+
+#if LLDB_ENABLE_TERMIOS
+  struct termios &fd_termios = data->m_termios;
+  ::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 SetData(data.get());
+#endif // #if LLDB_ENABLE_TERMIOS
+}
+
+static llvm::Optional<speed_t> baudRateToConst(unsigned int baud_rate) {
+  switch (baud_rate) {
+#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;
+  }
+}
+
+llvm::Error Terminal::SetBaudRate(unsigned int baud_rate) {
+  llvm::Expected<Data> data = GetData();
+  if (!data)
+    return data.takeError();
+
+#if LLDB_ENABLE_TERMIOS
+  struct termios &fd_termios = data->m_termios;
+  llvm::Optional<speed_t> val = baudRateToConst(baud_rate);
+  if (!val) // invalid value
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "baud rate %d unsupported by the platform",
+                                   baud_rate);
+  if (::cfsetispeed(&fd_termios, val.getValue()) != 0)
+    return llvm::createStringError(
+        std::error_code(errno, std::generic_category()),
+        "setting input baud rate failed");
+  if (::cfsetospeed(&fd_termios, val.getValue()) != 0)
+    return llvm::createStringError(
+        std::error_code(errno, std::generic_category()),
+        "setting output baud rate failed");
+  return SetData(data.get());
+#endif // #if LLDB_ENABLE_TERMIOS
+}
+
+llvm::Error Terminal::SetStopBits(unsigned int stop_bits) {
+  llvm::Expected<Data> data = GetData();
+  if (!data)
+    return data.takeError();
+
+#if LLDB_ENABLE_TERMIOS
+  struct termios &fd_termios = data->m_termios;
+  switch (stop_bits) {
+  case 1:
+    fd_termios.c_cflag &= ~CSTOPB;
+    break;
+  case 2:
+    fd_termios.c_cflag |= CSTOPB;
+    break;
+  default:
+    return llvm::createStringError(
+        llvm::inconvertibleErrorCode(),
+        "invalid stop bit count: %d (must be 1 or 2)", stop_bits);
+  }
+  return SetData(data.get());
+#endif // #if LLDB_ENABLE_TERMIOS
+}
+
+llvm::Error Terminal::SetParity(Terminal::Parity parity) {
+  llvm::Expected<Data> data = GetData();
+  if (!data)
+    return data.takeError();
+
+#if LLDB_ENABLE_TERMIOS
+  struct termios &fd_termios = data->m_termios;
+  fd_termios.c_cflag &= ~(
+#if defined(CMSPAR)
+      CMSPAR |
+#endif
+      PARENB | PARODD);
+
+  if (parity != Parity::No) {
+    fd_termios.c_cflag |= PARENB;
+    if (parity == Parity::Odd || parity == Parity::Mark)
+      fd_termios.c_cflag |= PARODD;
+    if (parity == Parity::Mark || parity == Parity::Space) {
+#if defined(CMSPAR)
+      fd_termios.c_cflag |= CMSPAR;
+#else
+      return llvm::createStringError(
+          llvm::inconvertibleErrorCode(),
+          "space/mark parity is not supported by the platform");
+#endif
+    }
+  }
+  return SetData(data.get());
+#endif // #if LLDB_ENABLE_TERMIOS
+}
+
+llvm::Error Terminal::SetHardwareFlowControl(bool enabled) {
+  llvm::Expected<Data> data = GetData();
+  if (!data)
+    return data.takeError();
+
+#if LLDB_ENABLE_TERMIOS
+#if defined(CRTSCTS)
+  struct termios &fd_termios = data->m_termios;
+  fd_termios.c_cflag &= ~CRTSCTS;
+  if (enabled)
+    fd_termios.c_cflag |= CRTSCTS;
+  return SetData(data.get());
+#else  // !defined(CRTSCTS)
+  if (enabled)
+    return llvm::createStringError(
+        llvm::inconvertibleErrorCode(),
+        "hardware flow control is not supported by the platform");
+  return llvm::Error::success();
+#endif // defined(CRTSCTS)
+#endif // #if LLDB_ENABLE_TERMIOS
+}
+
 TerminalState::TerminalState(Terminal term, bool save_process_group)
     : m_tty(term) {
   Save(term, save_process_group);
Index: lldb/include/lldb/Host/Terminal.h
===================================================================
--- lldb/include/lldb/Host/Terminal.h
+++ lldb/include/lldb/Host/Terminal.h
@@ -20,6 +20,14 @@
 
 class Terminal {
 public:
+  enum class Parity {
+    No,
+    Even,
+    Odd,
+    Space,
+    Mark,
+  };
+
   Terminal(int fd = -1) : m_fd(fd) {}
 
   ~Terminal() = default;
@@ -38,6 +46,16 @@
 
   llvm::Error SetCanonical(bool enabled);
 
+  llvm::Error SetRaw();
+
+  llvm::Error SetBaudRate(unsigned int baud_rate);
+
+  llvm::Error SetStopBits(unsigned int stop_bits);
+
+  llvm::Error SetParity(Parity parity);
+
+  llvm::Error SetHardwareFlowControl(bool enabled);
+
 protected:
   struct Data;
 
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to