diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:57:19 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:57:19 +0000 |
commit | a0b8f38ab54ac451646aa00cd5e91b6c76f22a84 (patch) | |
tree | fc451898ccaf445814e26b46664d78702178101d /vendor/rustix/src/termios | |
parent | Adding debian version 1.71.1+dfsg1-2. (diff) | |
download | rustc-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.rs | 40 | ||||
-rw-r--r-- | vendor/rustix/src/termios/constants.rs | 101 | ||||
-rw-r--r-- | vendor/rustix/src/termios/ioctl.rs | 42 | ||||
-rw-r--r-- | vendor/rustix/src/termios/mod.rs | 20 | ||||
-rw-r--r-- | vendor/rustix/src/termios/tc.rs | 95 | ||||
-rw-r--r-- | vendor/rustix/src/termios/tty.rs | 45 | ||||
-rw-r--r-- | vendor/rustix/src/termios/types.rs | 1273 |
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); +} |