summaryrefslogtreecommitdiffstats
path: root/vendor/rustix/src/termios
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:19 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:19 +0000
commita0b8f38ab54ac451646aa00cd5e91b6c76f22a84 (patch)
treefc451898ccaf445814e26b46664d78702178101d /vendor/rustix/src/termios
parentAdding debian version 1.71.1+dfsg1-2. (diff)
downloadrustc-a0b8f38ab54ac451646aa00cd5e91b6c76f22a84.tar.xz
rustc-a0b8f38ab54ac451646aa00cd5e91b6c76f22a84.zip
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/rustix/src/termios')
-rw-r--r--vendor/rustix/src/termios/cf.rs40
-rw-r--r--vendor/rustix/src/termios/constants.rs101
-rw-r--r--vendor/rustix/src/termios/ioctl.rs42
-rw-r--r--vendor/rustix/src/termios/mod.rs20
-rw-r--r--vendor/rustix/src/termios/tc.rs95
-rw-r--r--vendor/rustix/src/termios/tty.rs45
-rw-r--r--vendor/rustix/src/termios/types.rs1273
7 files changed, 1363 insertions, 253 deletions
diff --git a/vendor/rustix/src/termios/cf.rs b/vendor/rustix/src/termios/cf.rs
deleted file mode 100644
index d79eab5c8..000000000
--- a/vendor/rustix/src/termios/cf.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-use crate::termios::{Speed, Termios};
-use crate::{backend, io};
-
-/// `cfgetospeed(termios)`
-#[inline]
-#[must_use]
-pub fn cfgetospeed(termios: &Termios) -> Speed {
- backend::termios::syscalls::cfgetospeed(termios)
-}
-
-/// `cfgetispeed(termios)`
-#[inline]
-#[must_use]
-pub fn cfgetispeed(termios: &Termios) -> Speed {
- backend::termios::syscalls::cfgetispeed(termios)
-}
-
-/// `cfmakeraw(termios)`
-#[inline]
-pub fn cfmakeraw(termios: &mut Termios) {
- backend::termios::syscalls::cfmakeraw(termios)
-}
-
-/// `cfsetospeed(termios, speed)`
-#[inline]
-pub fn cfsetospeed(termios: &mut Termios, speed: Speed) -> io::Result<()> {
- backend::termios::syscalls::cfsetospeed(termios, speed)
-}
-
-/// `cfsetispeed(termios, speed)`
-#[inline]
-pub fn cfsetispeed(termios: &mut Termios, speed: Speed) -> io::Result<()> {
- backend::termios::syscalls::cfsetispeed(termios, speed)
-}
-
-/// `cfsetspeed(termios, speed)`
-#[inline]
-pub fn cfsetspeed(termios: &mut Termios, speed: Speed) -> io::Result<()> {
- backend::termios::syscalls::cfsetspeed(termios, speed)
-}
diff --git a/vendor/rustix/src/termios/constants.rs b/vendor/rustix/src/termios/constants.rs
deleted file mode 100644
index 99b75c06e..000000000
--- a/vendor/rustix/src/termios/constants.rs
+++ /dev/null
@@ -1,101 +0,0 @@
-use crate::backend;
-
-pub use backend::termios::types::*;
-
-/// Translate from a `Speed` code to a speed value `u32`.
-///
-/// ```
-/// let speed = rustix::termios::speed_value(rustix::termios::B57600);
-/// assert_eq!(speed, Some(57600));
-/// ```
-pub fn speed_value(speed: backend::termios::types::Speed) -> Option<u32> {
- match speed {
- backend::termios::types::B0 => Some(0),
- backend::termios::types::B50 => Some(50),
- backend::termios::types::B75 => Some(75),
- backend::termios::types::B110 => Some(110),
- backend::termios::types::B134 => Some(134),
- backend::termios::types::B150 => Some(150),
- backend::termios::types::B200 => Some(200),
- backend::termios::types::B300 => Some(300),
- backend::termios::types::B600 => Some(600),
- backend::termios::types::B1200 => Some(1200),
- backend::termios::types::B1800 => Some(1800),
- backend::termios::types::B2400 => Some(2400),
- backend::termios::types::B4800 => Some(4800),
- backend::termios::types::B9600 => Some(9600),
- backend::termios::types::B19200 => Some(19200),
- backend::termios::types::B38400 => Some(38400),
- #[cfg(not(target_os = "aix"))]
- backend::termios::types::B57600 => Some(57600),
- #[cfg(not(target_os = "aix"))]
- backend::termios::types::B115200 => Some(115_200),
- #[cfg(not(target_os = "aix"))]
- backend::termios::types::B230400 => Some(230_400),
- #[cfg(not(any(
- apple,
- target_os = "aix",
- target_os = "dragonfly",
- target_os = "haiku",
- target_os = "openbsd"
- )))]
- backend::termios::types::B460800 => Some(460_800),
- #[cfg(not(any(bsd, solarish, target_os = "aix", target_os = "haiku")))]
- backend::termios::types::B500000 => Some(500_000),
- #[cfg(not(any(bsd, solarish, target_os = "aix", target_os = "haiku")))]
- backend::termios::types::B576000 => Some(576_000),
- #[cfg(not(any(
- apple,
- target_os = "aix",
- target_os = "dragonfly",
- target_os = "haiku",
- target_os = "openbsd"
- )))]
- backend::termios::types::B921600 => Some(921_600),
- #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))]
- backend::termios::types::B1000000 => Some(1_000_000),
- #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))]
- backend::termios::types::B1152000 => Some(1_152_000),
- #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))]
- backend::termios::types::B1500000 => Some(1_500_000),
- #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))]
- backend::termios::types::B2000000 => Some(2_000_000),
- #[cfg(not(any(
- target_arch = "sparc",
- target_arch = "sparc64",
- bsd,
- target_os = "aix",
- target_os = "haiku",
- target_os = "solaris",
- )))]
- backend::termios::types::B2500000 => Some(2_500_000),
- #[cfg(not(any(
- target_arch = "sparc",
- target_arch = "sparc64",
- bsd,
- target_os = "aix",
- target_os = "haiku",
- target_os = "solaris",
- )))]
- backend::termios::types::B3000000 => Some(3_000_000),
- #[cfg(not(any(
- target_arch = "sparc",
- target_arch = "sparc64",
- bsd,
- target_os = "aix",
- target_os = "haiku",
- target_os = "solaris",
- )))]
- backend::termios::types::B3500000 => Some(3_500_000),
- #[cfg(not(any(
- target_arch = "sparc",
- target_arch = "sparc64",
- bsd,
- target_os = "aix",
- target_os = "haiku",
- target_os = "solaris",
- )))]
- backend::termios::types::B4000000 => Some(4_000_000),
- _ => None,
- }
-}
diff --git a/vendor/rustix/src/termios/ioctl.rs b/vendor/rustix/src/termios/ioctl.rs
new file mode 100644
index 000000000..2e8a28ed6
--- /dev/null
+++ b/vendor/rustix/src/termios/ioctl.rs
@@ -0,0 +1,42 @@
+//! Terminal-related `ioctl` functions.
+
+use crate::fd::AsFd;
+use crate::{backend, io};
+
+/// `ioctl(fd, TIOCEXCL)`—Enables exclusive mode on a terminal.
+///
+/// # References
+/// - [Linux]
+/// - [FreeBSD]
+/// - [NetBSD]
+/// - [OpenBSD]
+///
+/// [Linux]: https://man7.org/linux/man-pages/man4/tty_ioctl.4.html
+/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=tty&sektion=4
+/// [NetBSD]: https://man.netbsd.org/tty.4
+/// [OpenBSD]: https://man.openbsd.org/tty.4
+#[cfg(not(any(windows, target_os = "haiku", target_os = "redox", target_os = "wasi")))]
+#[inline]
+#[doc(alias = "TIOCEXCL")]
+pub fn ioctl_tiocexcl<Fd: AsFd>(fd: Fd) -> io::Result<()> {
+ backend::termios::syscalls::ioctl_tiocexcl(fd.as_fd())
+}
+
+/// `ioctl(fd, TIOCNXCL)`—Disables exclusive mode on a terminal.
+///
+/// # References
+/// - [Linux]
+/// - [FreeBSD]
+/// - [NetBSD]
+/// - [OpenBSD]
+///
+/// [Linux]: https://man7.org/linux/man-pages/man4/tty_ioctl.4.html
+/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=tty&sektion=4
+/// [NetBSD]: https://man.netbsd.org/tty.4
+/// [OpenBSD]: https://man.openbsd.org/tty.4
+#[cfg(not(any(windows, target_os = "haiku", target_os = "redox", target_os = "wasi")))]
+#[inline]
+#[doc(alias = "TIOCNXCL")]
+pub fn ioctl_tiocnxcl<Fd: AsFd>(fd: Fd) -> io::Result<()> {
+ backend::termios::syscalls::ioctl_tiocnxcl(fd.as_fd())
+}
diff --git a/vendor/rustix/src/termios/mod.rs b/vendor/rustix/src/termios/mod.rs
index ffbb1b663..28abc0488 100644
--- a/vendor/rustix/src/termios/mod.rs
+++ b/vendor/rustix/src/termios/mod.rs
@@ -1,19 +1,27 @@
//! Terminal I/O stream operations.
+//!
+//! This API automatically supports setting arbitrary I/O speeds, on any
+//! platform that supports them, including Linux and the BSDs.
+//!
+//! The [`speed`] module contains various predefined speed constants which
+//! are more likely to be portable, however any `u32` value can be passed to
+//! [`Termios::set_input_speed`], and it will simply fail if the speed is not
+//! supported by the platform.
#[cfg(not(target_os = "wasi"))]
-mod cf;
-#[cfg(not(target_os = "wasi"))]
-mod constants;
+mod ioctl;
#[cfg(not(target_os = "wasi"))]
mod tc;
#[cfg(not(windows))]
mod tty;
-
#[cfg(not(target_os = "wasi"))]
-pub use cf::*;
+mod types;
+
#[cfg(not(target_os = "wasi"))]
-pub use constants::*;
+pub use ioctl::*;
#[cfg(not(target_os = "wasi"))]
pub use tc::*;
#[cfg(not(windows))]
pub use tty::*;
+#[cfg(not(target_os = "wasi"))]
+pub use types::*;
diff --git a/vendor/rustix/src/termios/tc.rs b/vendor/rustix/src/termios/tc.rs
index 12f7f543c..9deb7798c 100644
--- a/vendor/rustix/src/termios/tc.rs
+++ b/vendor/rustix/src/termios/tc.rs
@@ -1,28 +1,11 @@
use crate::fd::AsFd;
-use crate::process::Pid;
+use crate::pid::Pid;
+use crate::termios::{Action, OptionalActions, QueueSelector, Termios, Winsize};
use crate::{backend, io};
-#[cfg(all(
- any(target_os = "android", target_os = "linux"),
- any(
- target_arch = "x86",
- target_arch = "x86_64",
- target_arch = "x32",
- target_arch = "riscv64",
- target_arch = "aarch64",
- target_arch = "arm",
- target_arch = "mips",
- target_arch = "mips64",
- )
-))]
-pub use backend::termios::types::Termios2;
-pub use backend::termios::types::{
- Action, OptionalActions, QueueSelector, Speed, Tcflag, Termios, Winsize,
-};
-
/// `tcgetattr(fd)`—Get terminal attributes.
///
-/// Also known as the `TCGETS` operation with `ioctl`.
+/// Also known as the `TCGETS` (or `TCGETS2` on Linux) operation with `ioctl`.
///
/// # References
/// - [POSIX `tcgetattr`]
@@ -35,41 +18,12 @@ pub use backend::termios::types::{
#[cfg(not(any(windows, target_os = "wasi")))]
#[inline]
#[doc(alias = "TCGETS")]
+#[doc(alias = "TCGETS2")]
+#[doc(alias = "tcgetattr2")]
pub fn tcgetattr<Fd: AsFd>(fd: Fd) -> io::Result<Termios> {
backend::termios::syscalls::tcgetattr(fd.as_fd())
}
-/// `tcgetattr2(fd)`—Get terminal attributes.
-///
-/// Also known as the `TCGETS2` operation with `ioctl`.
-///
-/// # References
-/// - [POSIX `tcgetattr`]
-/// - [Linux `ioctl_tty`]
-/// - [Linux `termios`]
-///
-/// [POSIX `tcgetattr`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetattr.html
-/// [Linux `ioctl_tty`]: https://man7.org/linux/man-pages/man4/tty_ioctl.4.html
-/// [Linux `termios`]: https://man7.org/linux/man-pages/man3/termios.3.html
-#[inline]
-#[doc(alias = "TCGETS2")]
-#[cfg(all(
- any(target_os = "android", target_os = "linux"),
- any(
- target_arch = "x86",
- target_arch = "x86_64",
- target_arch = "x32",
- target_arch = "riscv64",
- target_arch = "aarch64",
- target_arch = "arm",
- target_arch = "mips",
- target_arch = "mips64",
- )
-))]
-pub fn tcgetattr2<Fd: AsFd>(fd: Fd) -> io::Result<Termios2> {
- backend::termios::syscalls::tcgetattr2(fd.as_fd())
-}
-
/// `tcgetwinsize(fd)`—Get the current terminal window size.
///
/// Also known as the `TIOCGWINSZ` operation with `ioctl`.
@@ -121,7 +75,7 @@ pub fn tcsetpgrp<Fd: AsFd>(fd: Fd, pid: Pid) -> io::Result<()> {
/// `tcsetattr(fd)`—Set terminal attributes.
///
-/// Also known as the `TCSETS` operation with `ioctl`.
+/// Also known as the `TCSETS` (or `TCSETS2 on Linux) operation with `ioctl`.
///
/// # References
/// - [POSIX `tcsetattr`]
@@ -133,6 +87,8 @@ pub fn tcsetpgrp<Fd: AsFd>(fd: Fd, pid: Pid) -> io::Result<()> {
/// [Linux `termios`]: https://man7.org/linux/man-pages/man3/termios.3.html
#[inline]
#[doc(alias = "TCSETS")]
+#[doc(alias = "TCSETS2")]
+#[doc(alias = "tcsetattr2")]
pub fn tcsetattr<Fd: AsFd>(
fd: Fd,
optional_actions: OptionalActions,
@@ -141,41 +97,6 @@ pub fn tcsetattr<Fd: AsFd>(
backend::termios::syscalls::tcsetattr(fd.as_fd(), optional_actions, termios)
}
-/// `tcsetattr2(fd)`—Set terminal attributes.
-///
-/// Also known as the `TCSETS2` operation with `ioctl`.
-///
-/// # References
-/// - [POSIX `tcsetattr`]
-/// - [Linux `ioctl_tty`]
-/// - [Linux `termios`]
-///
-/// [POSIX `tcsetattr`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetattr.html
-/// [Linux `ioctl_tty`]: https://man7.org/linux/man-pages/man4/tty_ioctl.4.html
-/// [Linux `termios`]: https://man7.org/linux/man-pages/man3/termios.3.html
-#[inline]
-#[doc(alias = "TCSETS2")]
-#[cfg(all(
- any(target_os = "android", target_os = "linux"),
- any(
- target_arch = "x86",
- target_arch = "x86_64",
- target_arch = "x32",
- target_arch = "riscv64",
- target_arch = "aarch64",
- target_arch = "arm",
- target_arch = "mips",
- target_arch = "mips64",
- )
-))]
-pub fn tcsetattr2<Fd: AsFd>(
- fd: Fd,
- optional_actions: OptionalActions,
- termios: &Termios2,
-) -> io::Result<()> {
- backend::termios::syscalls::tcsetattr2(fd.as_fd(), optional_actions, termios)
-}
-
/// `tcsendbreak(fd, 0)`—Transmit zero-valued bits.
///
/// Also known as the `TCSBRK` operation with `ioctl`, with a duration of 0.
diff --git a/vendor/rustix/src/termios/tty.rs b/vendor/rustix/src/termios/tty.rs
index 76ffd8609..00787a568 100644
--- a/vendor/rustix/src/termios/tty.rs
+++ b/vendor/rustix/src/termios/tty.rs
@@ -1,18 +1,11 @@
//! Functions which operate on file descriptors which might be terminals.
use crate::backend;
-#[cfg(any(
- all(linux_raw, feature = "procfs"),
- all(libc, not(any(target_os = "fuchsia", target_os = "wasi"))),
-))]
-use crate::io;
use backend::fd::AsFd;
-#[cfg(any(
- all(linux_raw, feature = "procfs"),
- all(libc, not(any(target_os = "fuchsia", target_os = "wasi"))),
-))]
+#[cfg(feature = "procfs")]
+#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))]
use {
- crate::ffi::CString, crate::path::SMALL_PATH_BUFFER_SIZE, alloc::vec::Vec,
+ crate::ffi::CString, crate::io, crate::path::SMALL_PATH_BUFFER_SIZE, alloc::vec::Vec,
backend::fd::BorrowedFd,
};
@@ -31,7 +24,7 @@ pub fn isatty<Fd: AsFd>(fd: Fd) -> bool {
/// `ttyname_r(fd)`
///
-/// If `reuse` is non-empty, reuse its buffer to store the result if possible.
+/// If `reuse` already has available capacity, reuse it if possible.
///
/// # References
/// - [POSIX]
@@ -50,22 +43,36 @@ pub fn ttyname<Fd: AsFd, B: Into<Vec<u8>>>(dirfd: Fd, reuse: B) -> io::Result<CS
#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))]
#[cfg(feature = "procfs")]
+#[allow(unsafe_code)]
fn _ttyname(dirfd: BorrowedFd<'_>, mut buffer: Vec<u8>) -> io::Result<CString> {
- // This code would benefit from having a better way to read into
- // uninitialized memory, but that requires `unsafe`.
buffer.clear();
buffer.reserve(SMALL_PATH_BUFFER_SIZE);
- buffer.resize(buffer.capacity(), 0_u8);
loop {
- match backend::termios::syscalls::ttyname(dirfd, &mut buffer) {
+ match backend::termios::syscalls::ttyname(dirfd, buffer.spare_capacity_mut()) {
Err(io::Errno::RANGE) => {
- buffer.reserve(1); // use `Vec` reallocation strategy to grow capacity exponentially
- buffer.resize(buffer.capacity(), 0_u8);
+ buffer.reserve(buffer.capacity() + 1); // use `Vec` reallocation strategy to grow capacity exponentially
}
Ok(len) => {
- buffer.resize(len, 0_u8);
- return Ok(CString::new(buffer).unwrap());
+ // SAFETY: assume the backend returns the length of the string
+ unsafe {
+ buffer.set_len(len);
+ }
+
+ // SAFETY:
+ // - "ttyname_r stores this pathname in the buffer buf"
+ // - [POSIX definition 3.271: Pathname]: "A string that is used to identify a
+ // file."
+ // - [POSIX definition 3.375: String]: "A contiguous sequence of bytes
+ // terminated by and including the first null byte."
+ //
+ // Thus, there will be a single NUL byte at the end of the string.
+ //
+ // [POSIX definition 3.271: Pathname]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_271
+ // [POSIX definition 3.375: String]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_375
+ unsafe {
+ return Ok(CString::from_vec_with_nul_unchecked(buffer));
+ }
}
Err(errno) => return Err(errno),
}
diff --git a/vendor/rustix/src/termios/types.rs b/vendor/rustix/src/termios/types.rs
new file mode 100644
index 000000000..d978bfcca
--- /dev/null
+++ b/vendor/rustix/src/termios/types.rs
@@ -0,0 +1,1273 @@
+use crate::backend::c;
+use crate::{backend, io};
+use bitflags::bitflags;
+
+/// `struct termios` for use with [`tcgetattr`] and [`tcsetattr`].
+///
+/// [`tcgetattr`]: crate::termios::tcgetattr
+/// [`tcsetattr`]: crate::termios::tcsetattr
+#[repr(C)]
+#[derive(Clone)]
+pub struct Termios {
+ /// How is input interpreted?
+ #[doc(alias = "c_iflag")]
+ pub input_modes: InputModes,
+
+ /// How is output translated?
+ #[doc(alias = "c_oflag")]
+ pub output_modes: OutputModes,
+
+ /// Low-level configuration flags.
+ #[doc(alias = "c_cflag")]
+ pub control_modes: ControlModes,
+
+ /// High-level configuration flags.
+ #[doc(alias = "c_lflag")]
+ pub local_modes: LocalModes,
+
+ /// Line discipline.
+ #[doc(alias = "c_line")]
+ #[cfg(not(all(linux_raw, any(target_arch = "powerpc", target_arch = "powerpc64"))))]
+ #[cfg(any(
+ linux_like,
+ target_env = "newlib",
+ target_os = "haiku",
+ target_os = "fuchsia",
+ target_os = "redox"
+ ))]
+ pub line_discipline: c::cc_t,
+
+ /// How are various special control codes handled?
+ #[doc(alias = "c_cc")]
+ pub special_codes: SpecialCodes,
+
+ /// Line discipline.
+ // On PowerPC, this field comes after `c_cc`.
+ #[doc(alias = "c_line")]
+ #[cfg(all(linux_raw, any(target_arch = "powerpc", target_arch = "powerpc64")))]
+ pub line_discipline: c::cc_t,
+
+ /// See the `input_speed` and `set_input_seed` functions.
+ ///
+ /// On Linux and BSDs, this is the arbitrary integer speed value. On all
+ /// other platforms, this is the encoded speed value.
+ pub(crate) input_speed: c::speed_t,
+
+ /// See the `output_speed` and `set_output_seed` functions.
+ ///
+ /// On Linux and BSDs, this is the integer speed value. On all other
+ /// platforms, this is the encoded speed value.
+ pub(crate) output_speed: c::speed_t,
+}
+
+impl Termios {
+ /// `cfmakeraw(self)`—Set a `Termios` value to the settings for "raw" mode.
+ ///
+ /// In raw mode, input is available a byte at a time, echoing is disabled,
+ /// and special terminal input and output codes are disabled.
+ #[doc(alias = "cfmakeraw")]
+ #[inline]
+ pub fn make_raw(&mut self) {
+ backend::termios::syscalls::cfmakeraw(self)
+ }
+
+ /// Return the input communication speed.
+ ///
+ /// Unlike the `c_ispeed` field in GLIBC and others, this returns the
+ /// integer value of the speed, rather than the `B*` encoded constant
+ /// value.
+ #[doc(alias = "c_ispeed")]
+ #[doc(alias = "cfgetispeed")]
+ #[doc(alias = "cfgetspeed")]
+ #[inline]
+ pub fn input_speed(&self) -> u32 {
+ // On Linux and BSDs, `input_speed` is the arbitrary integer speed.
+ #[cfg(any(linux_kernel, bsd))]
+ {
+ debug_assert!(u32::try_from(self.input_speed).is_ok());
+ self.input_speed as u32
+ }
+
+ // On other platforms, it's the encoded speed.
+ #[cfg(not(any(linux_kernel, bsd)))]
+ {
+ speed::decode(self.input_speed).unwrap()
+ }
+ }
+
+ /// Return the output communication speed.
+ ///
+ /// Unlike the `c_ospeed` field in GLIBC and others, this returns the
+ /// arbitrary integer value of the speed, rather than the `B*` encoded
+ /// constant value.
+ #[inline]
+ pub fn output_speed(&self) -> u32 {
+ // On Linux and BSDs, `input_speed` is the arbitrary integer speed.
+ #[cfg(any(linux_kernel, bsd))]
+ {
+ debug_assert!(u32::try_from(self.output_speed).is_ok());
+ self.output_speed as u32
+ }
+
+ // On other platforms, it's the encoded speed.
+ #[cfg(not(any(linux_kernel, bsd)))]
+ {
+ speed::decode(self.output_speed).unwrap()
+ }
+ }
+
+ /// Set the input and output communication speeds.
+ ///
+ /// Unlike the `c_ispeed` and `c_ospeed` fields in GLIBC and others, this
+ /// takes the arbitrary integer value of the speed, rather than the `B*`
+ /// encoded constant value. Not all implementations support all integer
+ /// values; use the constants in the [`speed`] module for likely-supported
+ /// speeds.
+ #[doc(alias = "cfsetspeed")]
+ #[doc(alias = "CBAUD")]
+ #[doc(alias = "CBAUDEX")]
+ #[doc(alias = "CIBAUD")]
+ #[doc(alias = "CIBAUDEX")]
+ #[inline]
+ pub fn set_speed(&mut self, new_speed: u32) -> io::Result<()> {
+ backend::termios::syscalls::set_speed(self, new_speed)
+ }
+
+ /// Set the input communication speed.
+ ///
+ /// Unlike the `c_ispeed` field in GLIBC and others, this takes the
+ /// arbitrary integer value of the speed, rather than the `B*` encoded
+ /// constant value. Not all implementations support all integer values; use
+ /// the constants in the [`speed`] module for known-supported speeds.
+ ///
+ /// On some platforms, changing the input speed changes the output speed
+ /// to the same speed.
+ #[doc(alias = "c_ispeed")]
+ #[doc(alias = "cfsetispeed")]
+ #[doc(alias = "CIBAUD")]
+ #[doc(alias = "CIBAUDEX")]
+ #[inline]
+ pub fn set_input_speed(&mut self, new_speed: u32) -> io::Result<()> {
+ backend::termios::syscalls::set_input_speed(self, new_speed)
+ }
+
+ /// Set the output communication speed.
+ ///
+ /// Unlike the `c_ospeed` field in GLIBC and others, this takes the
+ /// arbitrary integer value of the speed, rather than the `B*` encoded
+ /// constant value. Not all implementations support all integer values; use
+ /// the constants in the [`speed`] module for known-supported speeds.
+ ///
+ /// On some platforms, changing the output speed changes the input speed
+ /// to the same speed.
+ #[doc(alias = "c_ospeed")]
+ #[doc(alias = "cfsetospeed")]
+ #[doc(alias = "CBAUD")]
+ #[doc(alias = "CBAUDEX")]
+ #[inline]
+ pub fn set_output_speed(&mut self, new_speed: u32) -> io::Result<()> {
+ backend::termios::syscalls::set_output_speed(self, new_speed)
+ }
+}
+
+impl core::fmt::Debug for Termios {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ let mut d = f.debug_struct("Termios");
+ d.field("input_modes", &self.input_modes);
+ d.field("output_modes", &self.output_modes);
+ d.field("control_modes", &self.control_modes);
+ d.field("local_modes", &self.local_modes);
+ #[cfg(any(
+ linux_like,
+ target_env = "newlib",
+ target_os = "haiku",
+ target_os = "fuchsia",
+ target_os = "redox"
+ ))]
+ {
+ d.field("line_discipline", &self.line_discipline);
+ }
+ d.field("special_codes", &self.special_codes);
+ d.field("input_speed", &self.input_speed());
+ d.field("output_speed", &self.output_speed());
+ d.finish()
+ }
+}
+
+bitflags! {
+ /// Flags controlling terminal input.
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct InputModes: c::tcflag_t {
+ /// `IGNBRK`
+ const IGNBRK = c::IGNBRK;
+
+ /// `BRKINT`
+ const BRKINT = c::BRKINT;
+
+ /// `IGNPAR`
+ const IGNPAR = c::IGNPAR;
+
+ /// `PARMRK`
+ const PARMRK = c::PARMRK;
+
+ /// `INPCK`
+ const INPCK = c::INPCK;
+
+ /// `ISTRIP`
+ const ISTRIP = c::ISTRIP;
+
+ /// `INLCR`
+ const INLCR = c::INLCR;
+
+ /// `IGNCR`
+ const IGNCR = c::IGNCR;
+
+ /// `ICRNL`
+ const ICRNL = c::ICRNL;
+
+ /// `IUCLC`
+ #[cfg(any(linux_kernel, solarish, target_os = "haiku"))]
+ const IUCLC = c::IUCLC;
+
+ /// `IXON`
+ const IXON = c::IXON;
+
+ /// `IXANY`
+ #[cfg(not(target_os = "redox"))]
+ const IXANY = c::IXANY;
+
+ /// `IXOFF`
+ const IXOFF = c::IXOFF;
+
+ /// `IMAXBEL`
+ #[cfg(not(any(target_os = "haiku", target_os = "redox")))]
+ const IMAXBEL = c::IMAXBEL;
+
+ /// `IUTF8`
+ #[cfg(not(any(
+ solarish,
+ target_os = "aix",
+ target_os = "dragonfly",
+ target_os = "emscripten",
+ target_os = "freebsd",
+ target_os = "haiku",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "redox",
+ )))]
+ const IUTF8 = c::IUTF8;
+ }
+}
+
+bitflags! {
+ /// Flags controlling terminal output.
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct OutputModes: c::tcflag_t {
+ /// `OPOST`
+ const OPOST = c::OPOST;
+
+ /// `OLCUC`
+ #[cfg(not(any(
+ apple,
+ target_os = "aix",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "redox",
+ )))]
+ const OLCUC = c::OLCUC;
+
+ /// `ONLCR`
+ const ONLCR = c::ONLCR;
+
+ /// `OCRNL`
+ const OCRNL = c::OCRNL;
+
+ /// `ONOCR`
+ const ONOCR = c::ONOCR;
+
+ /// `ONLRET`
+ const ONLRET = c::ONLRET;
+
+ /// `OFILL`
+ #[cfg(not(bsd))]
+ const OFILL = c::OFILL;
+
+ /// `OFDEL`
+ #[cfg(not(bsd))]
+ const OFDEL = c::OFDEL;
+
+ /// `NLDLY`
+ #[cfg(not(any(bsd, solarish, target_os = "redox")))]
+ const NLDLY = c::NLDLY;
+
+ /// `NL0`
+ #[cfg(not(any(bsd, solarish, target_os = "fuchsia", target_os = "redox")))]
+ const NL0 = c::NL0;
+
+ /// `NL1`
+ #[cfg(not(any(bsd, solarish, target_os = "fuchsia", target_os = "redox")))]
+ const NL1 = c::NL1;
+
+ /// `CRDLY`
+ #[cfg(not(any(bsd, solarish, target_os = "redox")))]
+ const CRDLY = c::CRDLY;
+
+ /// `CR0`
+ #[cfg(not(any(bsd, solarish, target_os = "fuchsia", target_os = "redox")))]
+ const CR0 = c::CR0;
+
+ /// `CR1`
+ #[cfg(not(any(
+ target_env = "musl",
+ bsd,
+ solarish,
+ target_os = "emscripten",
+ target_os = "fuchsia",
+ target_os = "redox",
+ )))]
+ const CR1 = c::CR1;
+
+ /// `CR2`
+ #[cfg(not(any(
+ target_env = "musl",
+ bsd,
+ solarish,
+ target_os = "emscripten",
+ target_os = "fuchsia",
+ target_os = "redox",
+ )))]
+ const CR2 = c::CR2;
+
+ /// `CR3`
+ #[cfg(not(any(
+ target_env = "musl",
+ bsd,
+ solarish,
+ target_os = "emscripten",
+ target_os = "fuchsia",
+ target_os = "redox",
+ )))]
+ const CR3 = c::CR3;
+
+ /// `TABDLY`
+ #[cfg(not(any(
+ netbsdlike,
+ solarish,
+ target_os = "dragonfly",
+ target_os = "redox",
+ )))]
+ const TABDLY = c::TABDLY;
+
+ /// `TAB0`
+ #[cfg(not(any(
+ netbsdlike,
+ solarish,
+ target_os = "dragonfly",
+ target_os = "fuchsia",
+ target_os = "redox",
+ )))]
+ const TAB0 = c::TAB0;
+
+ /// `TAB1`
+ #[cfg(not(any(
+ target_env = "musl",
+ bsd,
+ solarish,
+ target_os = "emscripten",
+ target_os = "fuchsia",
+ target_os = "redox",
+ )))]
+ const TAB1 = c::TAB1;
+
+ /// `TAB2`
+ #[cfg(not(any(
+ target_env = "musl",
+ bsd,
+ solarish,
+ target_os = "emscripten",
+ target_os = "fuchsia",
+ target_os = "redox",
+ )))]
+ const TAB2 = c::TAB2;
+
+ /// `TAB3`
+ #[cfg(not(any(
+ target_env = "musl",
+ bsd,
+ solarish,
+ target_os = "emscripten",
+ target_os = "fuchsia",
+ target_os = "redox",
+ )))]
+ const TAB3 = c::TAB3;
+
+ /// `XTABS`
+ #[cfg(not(any(
+ bsd,
+ solarish,
+ target_os = "aix",
+ target_os = "haiku",
+ target_os = "redox",
+ )))]
+ const XTABS = c::XTABS;
+
+ /// `BSDLY`
+ #[cfg(not(any(bsd, solarish, target_os = "redox")))]
+ const BSDLY = c::BSDLY;
+
+ /// `BS0`
+ #[cfg(not(any(bsd, solarish, target_os = "fuchsia", target_os = "redox")))]
+ const BS0 = c::BS0;
+
+ /// `BS1`
+ #[cfg(not(any(
+ target_env = "musl",
+ bsd,
+ solarish,
+ target_os = "emscripten",
+ target_os = "fuchsia",
+ target_os = "redox",
+ )))]
+ const BS1 = c::BS1;
+
+ /// `FFDLY`
+ #[cfg(not(any(bsd, solarish, target_os = "redox")))]
+ const FFDLY = c::FFDLY;
+
+ /// `FF0`
+ #[cfg(not(any(bsd, solarish, target_os = "fuchsia", target_os = "redox")))]
+ const FF0 = c::FF0;
+
+ /// `FF1`
+ #[cfg(not(any(
+ target_env = "musl",
+ bsd,
+ solarish,
+ target_os = "emscripten",
+ target_os = "fuchsia",
+ target_os = "redox",
+ )))]
+ const FF1 = c::FF1;
+
+ /// `VTDLY`
+ #[cfg(not(any(bsd, solarish, target_os = "redox")))]
+ const VTDLY = c::VTDLY;
+
+ /// `VT0`
+ #[cfg(not(any(bsd, solarish, target_os = "fuchsia", target_os = "redox")))]
+ const VT0 = c::VT0;
+
+ /// `VT1`
+ #[cfg(not(any(
+ target_env = "musl",
+ bsd,
+ solarish,
+ target_os = "emscripten",
+ target_os = "fuchsia",
+ target_os = "redox",
+ )))]
+ const VT1 = c::VT1;
+ }
+}
+
+bitflags! {
+ /// Flags controlling special terminal modes.
+ ///
+ /// `CBAUD`, `CBAUDEX`, `CIBAUD`, and `CIBAUDEX` are not defined here,
+ /// because they're handled automatically by [`Termios::set_speed`] and
+ /// related functions.
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct ControlModes: c::tcflag_t {
+ /// `CSIZE`
+ const CSIZE = c::CSIZE;
+
+ /// `CS5`
+ const CS5 = c::CS5;
+
+ /// `CS6`
+ const CS6 = c::CS6;
+
+ /// `CS7`
+ const CS7 = c::CS7;
+
+ /// `CS8`
+ const CS8 = c::CS8;
+
+ /// `CSTOPB`
+ const CSTOPB = c::CSTOPB;
+
+ /// `CREAD`
+ const CREAD = c::CREAD;
+
+ /// `PARENB`
+ const PARENB = c::PARENB;
+
+ /// `PARODD`
+ const PARODD = c::PARODD;
+
+ /// `HUPCL`
+ const HUPCL = c::HUPCL;
+
+ /// `CLOCAL`
+ const CLOCAL = c::CLOCAL;
+
+ /// `CRTSCTS`
+ #[cfg(not(any(target_os = "aix", target_os = "redox")))]
+ const CRTSCTS = c::CRTSCTS;
+
+ /// `CMSPAR`
+ #[cfg(not(any(
+ bsd,
+ solarish,
+ target_os = "aix",
+ target_os = "emscripten",
+ target_os = "haiku",
+ target_os = "redox",
+ )))]
+ const CMSPAR = c::CMSPAR;
+ }
+}
+
+bitflags! {
+ /// Flags controlling "local" terminal modes.
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct LocalModes: c::tcflag_t {
+ /// `XCASE`
+ #[cfg(any(linux_kernel, target_arch = "s390x", target_os = "haiku"))]
+ const XCASE = c::XCASE;
+
+ /// `ECHOCTL`
+ #[cfg(not(target_os = "redox"))]
+ const ECHOCTL = c::ECHOCTL;
+
+ /// `ECHOPRT`
+ #[cfg(not(target_os = "redox"))]
+ const ECHOPRT = c::ECHOPRT;
+
+ /// `ECHOKE`
+ #[cfg(not(target_os = "redox"))]
+ const ECHOKE = c::ECHOKE;
+
+ /// `FLUSHO`
+ #[cfg(not(target_os = "redox"))]
+ const FLUSHO = c::FLUSHO;
+
+ /// `PENDIN`
+ #[cfg(not(target_os = "redox"))]
+ const PENDIN = c::PENDIN;
+
+ /// `EXTPROC`
+ #[cfg(not(any(target_os = "aix", target_os = "haiku", target_os = "redox")))]
+ const EXTPROC = c::EXTPROC;
+
+ /// `ISIG`
+ const ISIG = c::ISIG;
+
+ /// `ICANON`—A flag for the `c_lflag` field of [`Termios`] indicating
+ /// canonical mode.
+ const ICANON = c::ICANON;
+
+ /// `ECHO`
+ const ECHO = c::ECHO;
+
+ /// `ECHOE`
+ const ECHOE = c::ECHOE;
+
+ /// `ECHOK`
+ const ECHOK = c::ECHOK;
+
+ /// `ECHONL`
+ const ECHONL = c::ECHONL;
+
+ /// `NOFLSH`
+ const NOFLSH = c::NOFLSH;
+
+ /// `TOSTOP`
+ const TOSTOP = c::TOSTOP;
+
+ /// `IEXTEN`
+ const IEXTEN = c::IEXTEN;
+ }
+}
+
+/// Speeds for use with [`Termios::set_input_speed`] and
+/// [`Termios::set_output_speed`].
+///
+/// Unlike in some platforms' libc APIs, these always have the same numerical
+/// value as their names; for example, `B50` has the value `50`, and so on.
+/// Consequently, it's not necessary to use them. They are provided here
+/// because they help identify speeds which are likely to be supported, on
+/// platforms which don't support arbitrary speeds.
+pub mod speed {
+ #[cfg(not(bsd))]
+ use crate::backend::c;
+
+ /// `B0`
+ pub const B0: u32 = 0;
+
+ /// `B50`
+ pub const B50: u32 = 50;
+
+ /// `B75`
+ pub const B75: u32 = 75;
+
+ /// `B110`
+ pub const B110: u32 = 110;
+
+ /// `B134`
+ pub const B134: u32 = 134;
+
+ /// `B150`
+ pub const B150: u32 = 150;
+
+ /// `B200`
+ pub const B200: u32 = 200;
+
+ /// `B300`
+ pub const B300: u32 = 300;
+
+ /// `B600`
+ pub const B600: u32 = 600;
+
+ /// `B1200`
+ pub const B1200: u32 = 1200;
+
+ /// `B1800`
+ pub const B1800: u32 = 1800;
+
+ /// `B2400`
+ pub const B2400: u32 = 2400;
+
+ /// `B4800`
+ pub const B4800: u32 = 4800;
+
+ /// `B9600`
+ pub const B9600: u32 = 9600;
+
+ /// `B19200`
+ #[doc(alias = "EXTA")]
+ pub const B19200: u32 = 19200;
+
+ /// `B38400`
+ #[doc(alias = "EXTB")]
+ pub const B38400: u32 = 38400;
+
+ /// `B57600`
+ #[cfg(not(target_os = "aix"))]
+ pub const B57600: u32 = 57600;
+
+ /// `B115200`
+ #[cfg(not(target_os = "aix"))]
+ pub const B115200: u32 = 115_200;
+
+ /// `B230400`
+ #[cfg(not(target_os = "aix"))]
+ pub const B230400: u32 = 230_400;
+
+ /// `B460800`
+ #[cfg(not(any(
+ apple,
+ target_os = "aix",
+ target_os = "dragonfly",
+ target_os = "haiku",
+ target_os = "openbsd"
+ )))]
+ pub const B460800: u32 = 460_800;
+
+ /// `B500000`
+ #[cfg(not(any(bsd, solarish, target_os = "aix", target_os = "haiku")))]
+ pub const B500000: u32 = 500_000;
+
+ /// `B576000`
+ #[cfg(not(any(bsd, solarish, target_os = "aix", target_os = "haiku")))]
+ pub const B576000: u32 = 576_000;
+
+ /// `B921600`
+ #[cfg(not(any(
+ apple,
+ target_os = "aix",
+ target_os = "dragonfly",
+ target_os = "haiku",
+ target_os = "openbsd"
+ )))]
+ pub const B921600: u32 = 921_600;
+
+ /// `B1000000`
+ #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))]
+ pub const B1000000: u32 = 1_000_000;
+
+ /// `B1152000`
+ #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))]
+ pub const B1152000: u32 = 1_152_000;
+
+ /// `B1500000`
+ #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))]
+ pub const B1500000: u32 = 1_500_000;
+
+ /// `B2000000`
+ #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))]
+ pub const B2000000: u32 = 2_000_000;
+
+ /// `B2500000`
+ #[cfg(not(any(
+ target_arch = "sparc",
+ target_arch = "sparc64",
+ bsd,
+ target_os = "aix",
+ target_os = "haiku",
+ target_os = "solaris",
+ )))]
+ pub const B2500000: u32 = 2_500_000;
+
+ /// `B3000000`
+ #[cfg(not(any(
+ target_arch = "sparc",
+ target_arch = "sparc64",
+ bsd,
+ target_os = "aix",
+ target_os = "haiku",
+ target_os = "solaris",
+ )))]
+ pub const B3000000: u32 = 3_000_000;
+
+ /// `B3500000`
+ #[cfg(not(any(
+ target_arch = "sparc",
+ target_arch = "sparc64",
+ bsd,
+ target_os = "aix",
+ target_os = "haiku",
+ target_os = "solaris",
+ )))]
+ pub const B3500000: u32 = 3_500_000;
+
+ /// `B4000000`
+ #[cfg(not(any(
+ target_arch = "sparc",
+ target_arch = "sparc64",
+ bsd,
+ target_os = "aix",
+ target_os = "haiku",
+ target_os = "solaris",
+ )))]
+ pub const B4000000: u32 = 4_000_000;
+
+ /// Translate from a `c::speed_t` code to an arbitrary integer speed value
+ /// `u32`.
+ #[cfg(not(any(linux_kernel, bsd)))]
+ pub(crate) fn decode(encoded_speed: c::speed_t) -> Option<u32> {
+ match encoded_speed {
+ c::B0 => Some(0),
+ c::B50 => Some(50),
+ c::B75 => Some(75),
+ c::B110 => Some(110),
+ c::B134 => Some(134),
+ c::B150 => Some(150),
+ c::B200 => Some(200),
+ c::B300 => Some(300),
+ c::B600 => Some(600),
+ c::B1200 => Some(1200),
+ c::B1800 => Some(1800),
+ c::B2400 => Some(2400),
+ c::B4800 => Some(4800),
+ c::B9600 => Some(9600),
+ c::B19200 => Some(19200),
+ c::B38400 => Some(38400),
+ #[cfg(not(target_os = "aix"))]
+ c::B57600 => Some(57600),
+ #[cfg(not(target_os = "aix"))]
+ c::B115200 => Some(115_200),
+ #[cfg(not(target_os = "aix"))]
+ c::B230400 => Some(230_400),
+ #[cfg(not(any(
+ apple,
+ target_os = "aix",
+ target_os = "dragonfly",
+ target_os = "haiku",
+ target_os = "openbsd"
+ )))]
+ c::B460800 => Some(460_800),
+ #[cfg(not(any(bsd, solarish, target_os = "aix", target_os = "haiku")))]
+ c::B500000 => Some(500_000),
+ #[cfg(not(any(bsd, solarish, target_os = "aix", target_os = "haiku")))]
+ c::B576000 => Some(576_000),
+ #[cfg(not(any(
+ apple,
+ target_os = "aix",
+ target_os = "dragonfly",
+ target_os = "haiku",
+ target_os = "openbsd"
+ )))]
+ c::B921600 => Some(921_600),
+ #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))]
+ c::B1000000 => Some(1_000_000),
+ #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))]
+ c::B1152000 => Some(1_152_000),
+ #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))]
+ c::B1500000 => Some(1_500_000),
+ #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))]
+ c::B2000000 => Some(2_000_000),
+ #[cfg(not(any(
+ target_arch = "sparc",
+ target_arch = "sparc64",
+ bsd,
+ target_os = "aix",
+ target_os = "haiku",
+ target_os = "solaris",
+ )))]
+ c::B2500000 => Some(2_500_000),
+ #[cfg(not(any(
+ target_arch = "sparc",
+ target_arch = "sparc64",
+ bsd,
+ target_os = "aix",
+ target_os = "haiku",
+ target_os = "solaris",
+ )))]
+ c::B3000000 => Some(3_000_000),
+ #[cfg(not(any(
+ target_arch = "sparc",
+ target_arch = "sparc64",
+ bsd,
+ target_os = "aix",
+ target_os = "haiku",
+ target_os = "solaris",
+ )))]
+ c::B3500000 => Some(3_500_000),
+ #[cfg(not(any(
+ target_arch = "sparc",
+ target_arch = "sparc64",
+ bsd,
+ target_os = "aix",
+ target_os = "haiku",
+ target_os = "solaris",
+ )))]
+ c::B4000000 => Some(4_000_000),
+ _ => None,
+ }
+ }
+
+ /// Translate from an arbitrary `u32` arbitrary integer speed value to a
+ /// `c::speed_t` code.
+ #[cfg(not(bsd))]
+ pub(crate) fn encode(speed: u32) -> Option<c::speed_t> {
+ match speed {
+ 0 => Some(c::B0),
+ 50 => Some(c::B50),
+ 75 => Some(c::B75),
+ 110 => Some(c::B110),
+ 134 => Some(c::B134),
+ 150 => Some(c::B150),
+ 200 => Some(c::B200),
+ 300 => Some(c::B300),
+ 600 => Some(c::B600),
+ 1200 => Some(c::B1200),
+ 1800 => Some(c::B1800),
+ 2400 => Some(c::B2400),
+ 4800 => Some(c::B4800),
+ 9600 => Some(c::B9600),
+ 19200 => Some(c::B19200),
+ 38400 => Some(c::B38400),
+ #[cfg(not(target_os = "aix"))]
+ 57600 => Some(c::B57600),
+ #[cfg(not(target_os = "aix"))]
+ 115_200 => Some(c::B115200),
+ #[cfg(not(target_os = "aix"))]
+ 230_400 => Some(c::B230400),
+ #[cfg(not(any(
+ apple,
+ target_os = "aix",
+ target_os = "dragonfly",
+ target_os = "haiku",
+ target_os = "openbsd"
+ )))]
+ 460_800 => Some(c::B460800),
+ #[cfg(not(any(bsd, solarish, target_os = "aix", target_os = "haiku")))]
+ 500_000 => Some(c::B500000),
+ #[cfg(not(any(bsd, solarish, target_os = "aix", target_os = "haiku")))]
+ 576_000 => Some(c::B576000),
+ #[cfg(not(any(
+ apple,
+ target_os = "aix",
+ target_os = "dragonfly",
+ target_os = "haiku",
+ target_os = "openbsd"
+ )))]
+ 921_600 => Some(c::B921600),
+ #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))]
+ 1_000_000 => Some(c::B1000000),
+ #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))]
+ 1_152_000 => Some(c::B1152000),
+ #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))]
+ 1_500_000 => Some(c::B1500000),
+ #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))]
+ 2_000_000 => Some(c::B2000000),
+ #[cfg(not(any(
+ target_arch = "sparc",
+ target_arch = "sparc64",
+ bsd,
+ target_os = "aix",
+ target_os = "haiku",
+ target_os = "solaris",
+ )))]
+ 2_500_000 => Some(c::B2500000),
+ #[cfg(not(any(
+ target_arch = "sparc",
+ target_arch = "sparc64",
+ bsd,
+ target_os = "aix",
+ target_os = "haiku",
+ target_os = "solaris",
+ )))]
+ 3_000_000 => Some(c::B3000000),
+ #[cfg(not(any(
+ target_arch = "sparc",
+ target_arch = "sparc64",
+ bsd,
+ target_os = "aix",
+ target_os = "haiku",
+ target_os = "solaris",
+ )))]
+ 3_500_000 => Some(c::B3500000),
+ #[cfg(not(any(
+ target_arch = "sparc",
+ target_arch = "sparc64",
+ bsd,
+ target_os = "aix",
+ target_os = "haiku",
+ target_os = "solaris",
+ )))]
+ 4_000_000 => Some(c::B4000000),
+ _ => None,
+ }
+ }
+}
+
+/// An array indexed by [`SpecialCodeIndex`] indicating the current values
+/// of various special control codes.
+#[repr(transparent)]
+#[derive(Clone, Debug)]
+pub struct SpecialCodes(pub(crate) [c::cc_t; c::NCCS as usize]);
+
+impl core::ops::Index<SpecialCodeIndex> for SpecialCodes {
+ type Output = c::cc_t;
+
+ fn index(&self, index: SpecialCodeIndex) -> &Self::Output {
+ &self.0[index.0]
+ }
+}
+
+impl core::ops::IndexMut<SpecialCodeIndex> for SpecialCodes {
+ fn index_mut(&mut self, index: SpecialCodeIndex) -> &mut Self::Output {
+ &mut self.0[index.0]
+ }
+}
+
+/// Indices for use with [`Termios::special_codes`].
+pub struct SpecialCodeIndex(usize);
+
+#[rustfmt::skip]
+impl SpecialCodeIndex {
+ /// `VINTR`
+ pub const VINTR: Self = Self(c::VINTR as usize);
+
+ /// `VQUIT`
+ pub const VQUIT: Self = Self(c::VQUIT as usize);
+
+ /// `VERASE`
+ pub const VERASE: Self = Self(c::VERASE as usize);
+
+ /// `VKILL`
+ pub const VKILL: Self = Self(c::VKILL as usize);
+
+ /// `VEOF`
+ pub const VEOF: Self = Self(c::VEOF as usize);
+
+ /// `VTIME`
+ pub const VTIME: Self = Self(c::VTIME as usize);
+
+ /// `VMIN`
+ pub const VMIN: Self = Self(c::VMIN as usize);
+
+ /// `VSWTC`
+ #[cfg(not(any(
+ apple,
+ solarish,
+ target_os = "aix",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "haiku",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ )))]
+ pub const VSWTC: Self = Self(c::VSWTC as usize);
+
+ /// `VSTART`
+ pub const VSTART: Self = Self(c::VSTART as usize);
+
+ /// `VSTOP`
+ pub const VSTOP: Self = Self(c::VSTOP as usize);
+
+ /// `VSUSP`
+ pub const VSUSP: Self = Self(c::VSUSP as usize);
+
+ /// `VEOL`
+ pub const VEOL: Self = Self(c::VEOL as usize);
+
+ /// `VREPRINT`
+ #[cfg(not(target_os = "haiku"))]
+ pub const VREPRINT: Self = Self(c::VREPRINT as usize);
+
+ /// `VDISCARD`
+ #[cfg(not(any(target_os = "aix", target_os = "haiku")))]
+ pub const VDISCARD: Self = Self(c::VDISCARD as usize);
+
+ /// `VWERASE`
+ #[cfg(not(any(target_os = "aix", target_os = "haiku")))]
+ pub const VWERASE: Self = Self(c::VWERASE as usize);
+
+ /// `VLNEXT`
+ #[cfg(not(target_os = "haiku"))]
+ pub const VLNEXT: Self = Self(c::VLNEXT as usize);
+
+ /// `VEOL2`
+ pub const VEOL2: Self = Self(c::VEOL2 as usize);
+}
+
+/// `TCSA*` values for use with [`tcsetattr`].
+///
+/// [`tcsetattr`]: crate::termios::tcsetattr
+#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
+#[repr(u32)]
+pub enum OptionalActions {
+ /// `TCSANOW`—Make the change immediately.
+ #[doc(alias = "TCSANOW")]
+ Now = c::TCSANOW as u32,
+
+ /// `TCSADRAIN`—Make the change after all output has been transmitted.
+ #[doc(alias = "TCSADRAIN")]
+ Drain = c::TCSADRAIN as u32,
+
+ /// `TCSAFLUSH`—Discard any pending input and then make the change
+ /// after all output has been transmitted.
+ #[doc(alias = "TCSAFLUSH")]
+ Flush = c::TCSAFLUSH as u32,
+}
+
+/// `TC*` values for use with [`tcflush`].
+///
+/// [`tcflush`]: crate::termios::tcflush
+#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
+#[repr(u32)]
+pub enum QueueSelector {
+ /// `TCIFLUSH`—Flush data received but not read.
+ #[doc(alias = "TCIFLUSH")]
+ IFlush = c::TCIFLUSH as u32,
+
+ /// `TCOFLUSH`—Flush data written but not transmitted.
+ #[doc(alias = "TCOFLUSH")]
+ OFlush = c::TCOFLUSH as u32,
+
+ /// `TCIOFLUSH`—`IFlush` and `OFlush` combined.
+ #[doc(alias = "TCIOFLUSH")]
+ IOFlush = c::TCIOFLUSH as u32,
+}
+
+/// `TC*` values for use with [`tcflow`].
+///
+/// [`tcflow`]: crate::termios::tcflow
+#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
+#[repr(u32)]
+pub enum Action {
+ /// `TCOOFF`—Suspend output.
+ #[doc(alias = "TCOOFF")]
+ OOff = c::TCOOFF as u32,
+
+ /// `TCOON`—Restart suspended output.
+ #[doc(alias = "TCOON")]
+ OOn = c::TCOON as u32,
+
+ /// `TCIOFF`—Transmits a STOP byte.
+ #[doc(alias = "TCIOFF")]
+ IOff = c::TCIOFF as u32,
+
+ /// `TCION`—Transmits a START byte.
+ #[doc(alias = "TCION")]
+ IOn = c::TCION as u32,
+}
+
+/// `struct winsize` for use with [`tcgetwinsize`].
+///
+/// [`tcgetwinsize`]: crate::termios::tcgetwinsize
+#[doc(alias = "winsize")]
+pub type Winsize = c::winsize;
+
+#[test]
+fn termios_layouts() {
+ check_renamed_type!(InputModes, tcflag_t);
+ check_renamed_type!(OutputModes, tcflag_t);
+ check_renamed_type!(ControlModes, tcflag_t);
+ check_renamed_type!(LocalModes, tcflag_t);
+
+ // On platforms with a termios/termios2 split, check `termios`.
+ #[cfg(linux_raw)]
+ {
+ check_renamed_type!(Termios, termios2);
+ check_renamed_struct_renamed_field!(Termios, termios2, input_modes, c_iflag);
+ check_renamed_struct_renamed_field!(Termios, termios2, output_modes, c_oflag);
+ check_renamed_struct_renamed_field!(Termios, termios2, control_modes, c_cflag);
+ check_renamed_struct_renamed_field!(Termios, termios2, local_modes, c_lflag);
+ check_renamed_struct_renamed_field!(Termios, termios2, line_discipline, c_line);
+ check_renamed_struct_renamed_field!(Termios, termios2, special_codes, c_cc);
+ check_renamed_struct_renamed_field!(Termios, termios2, input_speed, c_ispeed);
+ check_renamed_struct_renamed_field!(Termios, termios2, output_speed, c_ospeed);
+
+ // We assume that `termios` has the same layout as `termios2` minus the
+ // `c_ispeed` and `c_ospeed` fields.
+ check_renamed_struct_renamed_field!(Termios, termios, input_modes, c_iflag);
+ check_renamed_struct_renamed_field!(Termios, termios, output_modes, c_oflag);
+ check_renamed_struct_renamed_field!(Termios, termios, control_modes, c_cflag);
+ check_renamed_struct_renamed_field!(Termios, termios, local_modes, c_lflag);
+ check_renamed_struct_renamed_field!(Termios, termios, special_codes, c_cc);
+
+ // On everything except PowerPC, `termios` matches `termios2` except for
+ // the addition of `c_ispeed` and `c_ospeed`.
+ #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
+ assert_eq!(
+ memoffset::offset_of!(Termios, input_speed),
+ core::mem::size_of::<c::termios>()
+ );
+
+ // On PowerPC, `termios2` is `termios`.
+ #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
+ assert_eq!(
+ core::mem::size_of::<c::termios2>(),
+ core::mem::size_of::<c::termios>()
+ );
+ }
+
+ #[cfg(not(linux_raw))]
+ {
+ #[cfg(not(all(
+ target_env = "gnu",
+ any(
+ target_arch = "sparc",
+ target_arch = "sparc64",
+ target_arch = "mips",
+ target_arch = "mips64"
+ )
+ )))]
+ check_renamed_type!(Termios, termios);
+ check_renamed_struct_renamed_field!(Termios, termios, input_modes, c_iflag);
+ check_renamed_struct_renamed_field!(Termios, termios, output_modes, c_oflag);
+ check_renamed_struct_renamed_field!(Termios, termios, control_modes, c_cflag);
+ check_renamed_struct_renamed_field!(Termios, termios, local_modes, c_lflag);
+ #[cfg(any(
+ linux_like,
+ target_env = "newlib",
+ target_os = "haiku",
+ target_os = "fuchsia",
+ target_os = "redox"
+ ))]
+ check_renamed_struct_renamed_field!(Termios, termios, line_discipline, c_line);
+ check_renamed_struct_renamed_field!(Termios, termios, special_codes, c_cc);
+ #[cfg(not(any(
+ linux_kernel,
+ solarish,
+ target_os = "emscripten",
+ target_os = "fuchsia"
+ )))]
+ {
+ check_renamed_struct_renamed_field!(Termios, termios, input_speed, c_ispeed);
+ check_renamed_struct_renamed_field!(Termios, termios, output_speed, c_ospeed);
+ }
+ #[cfg(any(target_env = "musl", target_os = "fuchsia"))]
+ {
+ check_renamed_struct_renamed_field!(Termios, termios, input_speed, __c_ispeed);
+ check_renamed_struct_renamed_field!(Termios, termios, output_speed, __c_ospeed);
+ }
+ }
+
+ check_renamed_type!(OptionalActions, c_int);
+ check_renamed_type!(QueueSelector, c_int);
+ check_renamed_type!(Action, c_int);
+}
+
+#[test]
+#[cfg(not(any(solarish, target_os = "emscripten")))]
+fn termios_legacy() {
+ // Check that our doc aliases above are correct.
+ assert_eq!(c::EXTA, c::B19200);
+ assert_eq!(c::EXTB, c::B38400);
+}
+
+#[cfg(bsd)]
+#[test]
+fn termios_bsd() {
+ // On BSD platforms we can assume that the `B*` constants have their
+ // arbitrary integer speed value. Confirm this.
+ assert_eq!(c::B0, 0);
+ assert_eq!(c::B50, 50);
+ assert_eq!(c::B19200, 19200);
+ assert_eq!(c::B38400, 38400);
+}
+
+#[test]
+#[cfg(not(bsd))]
+fn termios_speed_encoding() {
+ assert_eq!(speed::encode(0), Some(c::B0));
+ assert_eq!(speed::encode(50), Some(c::B50));
+ assert_eq!(speed::encode(19200), Some(c::B19200));
+ assert_eq!(speed::encode(38400), Some(c::B38400));
+ assert_eq!(speed::encode(1), None);
+ assert_eq!(speed::encode(!0), None);
+
+ #[cfg(not(linux_kernel))]
+ {
+ assert_eq!(speed::decode(c::B0), Some(0));
+ assert_eq!(speed::decode(c::B50), Some(50));
+ assert_eq!(speed::decode(c::B19200), Some(19200));
+ assert_eq!(speed::decode(c::B38400), Some(38400));
+ }
+}
+
+#[cfg(linux_kernel)]
+#[test]
+fn termios_ioctl_contiguity() {
+ // When using `termios2`, we assume that we can add the optional actions
+ // value to the ioctl request code. Test this assumption.
+
+ assert_eq!(c::TCSETS2, c::TCSETS2 + 0);
+ assert_eq!(c::TCSETSW2, c::TCSETS2 + 1);
+ assert_eq!(c::TCSETSF2, c::TCSETS2 + 2);
+
+ assert_eq!(c::TCSANOW - c::TCSANOW, 0);
+ assert_eq!(c::TCSADRAIN - c::TCSANOW, 1);
+ assert_eq!(c::TCSAFLUSH - c::TCSANOW, 2);
+
+ // MIPS is different here.
+ #[cfg(any(target_arch = "mips", target_arch = "mips64"))]
+ {
+ assert_eq!(i128::from(c::TCSANOW) - i128::from(c::TCSETS), 0);
+ assert_eq!(i128::from(c::TCSADRAIN) - i128::from(c::TCSETS), 1);
+ assert_eq!(i128::from(c::TCSAFLUSH) - i128::from(c::TCSETS), 2);
+ }
+ #[cfg(not(any(target_arch = "mips", target_arch = "mips64")))]
+ {
+ assert_eq!(c::TCSANOW, 0);
+ assert_eq!(c::TCSADRAIN, 1);
+ assert_eq!(c::TCSAFLUSH, 2);
+ }
+}
+
+#[cfg(linux_kernel)]
+#[test]
+fn termios_cibaud() {
+ // Test an assumption.
+ assert_eq!(c::CIBAUD, c::CBAUD << c::IBSHIFT);
+}