diff options
| author | Valentin Popov <valentin@popov.link> | 2024-01-08 00:21:28 +0300 | 
|---|---|---|
| committer | Valentin Popov <valentin@popov.link> | 2024-01-08 00:21:28 +0300 | 
| commit | 1b6a04ca5504955c571d1c97504fb45ea0befee4 (patch) | |
| tree | 7579f518b23313e8a9748a88ab6173d5e030b227 /vendor/rustix/src/termios | |
| parent | 5ecd8cf2cba827454317368b68571df0d13d7842 (diff) | |
| download | fparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.tar.xz fparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.zip  | |
Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
Diffstat (limited to 'vendor/rustix/src/termios')
| -rw-r--r-- | vendor/rustix/src/termios/ioctl.rs | 53 | ||||
| -rw-r--r-- | vendor/rustix/src/termios/mod.rs | 27 | ||||
| -rw-r--r-- | vendor/rustix/src/termios/tc.rs | 209 | ||||
| -rw-r--r-- | vendor/rustix/src/termios/tty.rs | 84 | ||||
| -rw-r--r-- | vendor/rustix/src/termios/types.rs | 1450 | 
5 files changed, 1823 insertions, 0 deletions
diff --git a/vendor/rustix/src/termios/ioctl.rs b/vendor/rustix/src/termios/ioctl.rs new file mode 100644 index 0000000..620ae4c --- /dev/null +++ b/vendor/rustix/src/termios/ioctl.rs @@ -0,0 +1,53 @@ +//! Terminal-related `ioctl` functions. + +#![allow(unsafe_code)] + +use crate::fd::AsFd; +use crate::{backend, io, ioctl}; +use backend::c; + +/// `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 = "redox", target_os = "wasi")))] +#[inline] +#[doc(alias = "TIOCEXCL")] +pub fn ioctl_tiocexcl<Fd: AsFd>(fd: Fd) -> io::Result<()> { +    // SAFETY: TIOCEXCL is a no-argument setter opcode. +    unsafe { +        let ctl = ioctl::NoArg::<ioctl::BadOpcode<{ c::TIOCEXCL as _ }>>::new(); +        ioctl::ioctl(fd, ctl) +    } +} + +/// `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 = "redox", target_os = "wasi")))] +#[inline] +#[doc(alias = "TIOCNXCL")] +pub fn ioctl_tiocnxcl<Fd: AsFd>(fd: Fd) -> io::Result<()> { +    // SAFETY: TIOCNXCL is a no-argument setter opcode. +    unsafe { +        let ctl = ioctl::NoArg::<ioctl::BadOpcode<{ c::TIOCNXCL as _ }>>::new(); +        ioctl::ioctl(fd, ctl) +    } +} diff --git a/vendor/rustix/src/termios/mod.rs b/vendor/rustix/src/termios/mod.rs new file mode 100644 index 0000000..c61d3f1 --- /dev/null +++ b/vendor/rustix/src/termios/mod.rs @@ -0,0 +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(any(target_os = "espidf", target_os = "haiku", target_os = "wasi")))] +mod ioctl; +#[cfg(not(target_os = "wasi"))] +mod tc; +#[cfg(not(windows))] +mod tty; +#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] +mod types; + +#[cfg(not(any(target_os = "espidf", target_os = "haiku", target_os = "wasi")))] +pub use ioctl::*; +#[cfg(not(target_os = "wasi"))] +pub use tc::*; +#[cfg(not(windows))] +pub use tty::*; +#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] +pub use types::*; diff --git a/vendor/rustix/src/termios/tc.rs b/vendor/rustix/src/termios/tc.rs new file mode 100644 index 0000000..58ba2c2 --- /dev/null +++ b/vendor/rustix/src/termios/tc.rs @@ -0,0 +1,209 @@ +use crate::fd::AsFd; +#[cfg(not(target_os = "espidf"))] +use crate::termios::{Action, OptionalActions, QueueSelector, Termios, Winsize}; +use crate::{backend, io}; + +pub use crate::pid::Pid; + +/// `tcgetattr(fd)`—Get terminal attributes. +/// +/// Also known as the `TCGETS` (or `TCGETS2` on Linux) 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 +#[cfg(not(any(windows, target_os = "espidf", 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()) +} + +/// `tcgetwinsize(fd)`—Get the current terminal window size. +/// +/// Also known as the `TIOCGWINSZ` operation with `ioctl`. +/// +/// # References +///  - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man4/tty_ioctl.4.html +#[cfg(not(any(windows, target_os = "espidf", target_os = "wasi")))] +#[inline] +#[doc(alias = "TIOCGWINSZ")] +pub fn tcgetwinsize<Fd: AsFd>(fd: Fd) -> io::Result<Winsize> { +    backend::termios::syscalls::tcgetwinsize(fd.as_fd()) +} + +/// `tcgetpgrp(fd)`—Get the terminal foreground process group. +/// +/// Also known as the `TIOCGPGRP` operation with `ioctl`. +/// +/// On Linux, if `fd` is a pseudo-terminal, the underlying system call here can +/// return a pid of 0, which rustix's `Pid` type doesn't support. So rustix +/// instead handles this case by failing with [`io::Errno::OPNOTSUPP`] if the +/// pid is 0. +/// +/// # References +///  - [POSIX] +///  - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetpgrp.html +/// [Linux]: https://man7.org/linux/man-pages/man3/tcgetpgrp.3.html +#[cfg(not(any(windows, target_os = "wasi")))] +#[inline] +#[doc(alias = "TIOCGPGRP")] +pub fn tcgetpgrp<Fd: AsFd>(fd: Fd) -> io::Result<Pid> { +    backend::termios::syscalls::tcgetpgrp(fd.as_fd()) +} + +/// `tcsetpgrp(fd, pid)`—Set the terminal foreground process group. +/// +/// Also known as the `TIOCSPGRP` operation with `ioctl`. +/// +/// # References +///  - [POSIX] +///  - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetpgrp.html +/// [Linux]: https://man7.org/linux/man-pages/man3/tcsetpgrp.3.html +#[cfg(not(any(windows, target_os = "wasi")))] +#[inline] +#[doc(alias = "TIOCSPGRP")] +pub fn tcsetpgrp<Fd: AsFd>(fd: Fd, pid: Pid) -> io::Result<()> { +    backend::termios::syscalls::tcsetpgrp(fd.as_fd(), pid) +} + +/// `tcsetattr(fd)`—Set terminal attributes. +/// +/// Also known as the `TCSETS` (or `TCSETS2 on Linux) 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 +#[cfg(not(target_os = "espidf"))] +#[inline] +#[doc(alias = "TCSETS")] +#[doc(alias = "TCSETS2")] +#[doc(alias = "tcsetattr2")] +pub fn tcsetattr<Fd: AsFd>( +    fd: Fd, +    optional_actions: OptionalActions, +    termios: &Termios, +) -> io::Result<()> { +    backend::termios::syscalls::tcsetattr(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. +/// +/// This function always uses an effective duration parameter of zero. For the +/// equivalent of a `tcsendbreak` with a non-zero duration parameter, use +/// `tcdrain`. +/// +/// # References +///  - [POSIX `tcsendbreak`] +///  - [Linux `ioctl_tty`] +///  - [Linux `termios`] +/// +/// [POSIX `tcsendbreak`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsendbreak.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 = "TCSBRK")] +pub fn tcsendbreak<Fd: AsFd>(fd: Fd) -> io::Result<()> { +    backend::termios::syscalls::tcsendbreak(fd.as_fd()) +} + +/// `tcdrain(fd, duration)`—Wait until all pending output has been written. +/// +/// # References +///  - [POSIX `tcdrain`] +///  - [Linux `ioctl_tty`] +///  - [Linux `termios`] +/// +/// [POSIX `tcsetattr`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcdrain.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 +#[cfg(not(target_os = "espidf"))] +#[inline] +pub fn tcdrain<Fd: AsFd>(fd: Fd) -> io::Result<()> { +    backend::termios::syscalls::tcdrain(fd.as_fd()) +} + +/// `tcflush(fd, queue_selector)`—Wait until all pending output has been +/// written. +/// +/// # References +///  - [POSIX `tcflush`] +///  - [Linux `ioctl_tty`] +///  - [Linux `termios`] +/// +/// [POSIX `tcflush`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflush.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 +#[cfg(not(target_os = "espidf"))] +#[inline] +#[doc(alias = "TCFLSH")] +pub fn tcflush<Fd: AsFd>(fd: Fd, queue_selector: QueueSelector) -> io::Result<()> { +    backend::termios::syscalls::tcflush(fd.as_fd(), queue_selector) +} + +/// `tcflow(fd, action)`—Suspend or resume transmission or reception. +/// +/// # References +///  - [POSIX `tcflow`] +///  - [Linux `ioctl_tty`] +///  - [Linux `termios`] +/// +/// [POSIX `tcflow`]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflow.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 +#[cfg(not(target_os = "espidf"))] +#[inline] +#[doc(alias = "TCXONC")] +pub fn tcflow<Fd: AsFd>(fd: Fd, action: Action) -> io::Result<()> { +    backend::termios::syscalls::tcflow(fd.as_fd(), action) +} + +/// `tcgetsid(fd)`—Return the session ID of the current session with `fd` as +/// its controlling terminal. +/// +/// # References +///  - [POSIX] +///  - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetsid.html +/// [Linux]: https://man7.org/linux/man-pages/man3/tcgetsid.3.html +#[inline] +#[doc(alias = "TIOCGSID")] +pub fn tcgetsid<Fd: AsFd>(fd: Fd) -> io::Result<Pid> { +    backend::termios::syscalls::tcgetsid(fd.as_fd()) +} + +/// `tcsetwinsize(fd)`—Set the current terminal window size. +/// +/// Also known as the `TIOCSWINSZ` operation with `ioctl`. +/// +/// # References +///  - [Linux] +/// +/// [Linux]: https://man7.org/linux/man-pages/man4/tty_ioctl.4.html +#[cfg(not(target_os = "espidf"))] +#[inline] +#[doc(alias = "TIOCSWINSZ")] +pub fn tcsetwinsize<Fd: AsFd>(fd: Fd, winsize: Winsize) -> io::Result<()> { +    backend::termios::syscalls::tcsetwinsize(fd.as_fd(), winsize) +} diff --git a/vendor/rustix/src/termios/tty.rs b/vendor/rustix/src/termios/tty.rs new file mode 100644 index 0000000..b14e602 --- /dev/null +++ b/vendor/rustix/src/termios/tty.rs @@ -0,0 +1,84 @@ +//! Functions which operate on file descriptors which might be terminals. + +use crate::backend; +use backend::fd::AsFd; +#[cfg(all(feature = "alloc", feature = "procfs"))] +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] +use { +    crate::ffi::CString, crate::io, crate::path::SMALL_PATH_BUFFER_SIZE, alloc::vec::Vec, +    backend::fd::BorrowedFd, +}; + +/// `isatty(fd)`—Tests whether a file descriptor refers to a terminal. +/// +/// # References +///  - [POSIX] +///  - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/isatty.html +/// [Linux]: https://man7.org/linux/man-pages/man3/isatty.3.html +#[inline] +pub fn isatty<Fd: AsFd>(fd: Fd) -> bool { +    backend::termios::syscalls::isatty(fd.as_fd()) +} + +/// `ttyname_r(fd)` +/// +/// If `reuse` already has available capacity, reuse it if possible. +/// +/// # References +///  - [POSIX] +///  - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/ttyname.html +/// [Linux]: https://man7.org/linux/man-pages/man3/ttyname.3.html +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] +#[cfg(all(feature = "alloc", feature = "procfs"))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "procfs")))] +#[doc(alias = "ttyname_r")] +#[inline] +pub fn ttyname<Fd: AsFd, B: Into<Vec<u8>>>(dirfd: Fd, reuse: B) -> io::Result<CString> { +    _ttyname(dirfd.as_fd(), reuse.into()) +} + +#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] +#[cfg(all(feature = "alloc", feature = "procfs"))] +#[allow(unsafe_code)] +fn _ttyname(dirfd: BorrowedFd<'_>, mut buffer: Vec<u8>) -> io::Result<CString> { +    buffer.clear(); +    buffer.reserve(SMALL_PATH_BUFFER_SIZE); + +    loop { +        match backend::termios::syscalls::ttyname(dirfd, buffer.spare_capacity_mut()) { +            Err(io::Errno::RANGE) => { +                // Use `Vec` reallocation strategy to grow capacity +                // exponentially. +                buffer.reserve(buffer.capacity() + 1); +            } +            Ok(len) => { +                // SAFETY: Assume the backend returns the length of the string +                // excluding the NUL. +                unsafe { +                    buffer.set_len(len + 1); +                } + +                // 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 0000000..57e9a5d --- /dev/null +++ b/vendor/rustix/src/termios/types.rs @@ -0,0 +1,1450 @@ +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 = "fuchsia", +        target_os = "haiku", +        target_os = "redox" +    ))] +    pub line_discipline: c::cc_t, + +    /// How are various special control codes handled? +    #[doc(alias = "c_cc")] +    #[cfg(not(target_os = "haiku"))] +    pub special_codes: SpecialCodes, + +    #[cfg(target_os = "nto")] +    pub(crate) __reserved: [c::c_uint; 3], + +    /// 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. +    #[cfg(not(any(solarish, all(libc, target_env = "newlib"), target_os = "aix")))] +    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. +    #[cfg(not(any(solarish, all(libc, target_env = "newlib"), target_os = "aix")))] +    pub(crate) output_speed: c::speed_t, + +    /// How are various special control codes handled? +    #[doc(alias = "c_cc")] +    #[cfg(target_os = "haiku")] +    pub special_codes: SpecialCodes, +} + +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. +    #[cfg(not(target_os = "nto"))] +    #[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 illumos, `input_speed` is not present. +        #[cfg(any(solarish, all(libc, target_env = "newlib"), target_os = "aix"))] +        unsafe { +            speed::decode(c::cfgetispeed(crate::utils::as_ptr(self).cast())).unwrap() +        } + +        // On other platforms, it's the encoded speed. +        #[cfg(not(any( +            linux_kernel, +            bsd, +            solarish, +            all(libc, target_env = "newlib"), +            target_os = "aix" +        )))] +        { +            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 illumos, `output_speed` is not present. +        #[cfg(any(solarish, all(libc, target_env = "newlib"), target_os = "aix"))] +        unsafe { +            speed::decode(c::cfgetospeed(crate::utils::as_ptr(self).cast())).unwrap() +        } + +        // On other platforms, it's the encoded speed. +        #[cfg(not(any( +            linux_kernel, +            bsd, +            solarish, +            all(libc, target_env = "newlib"), +            target_os = "aix" +        )))] +        { +            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. +    #[cfg(not(target_os = "nto"))] +    #[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 = "fuchsia", +            target_os = "haiku", +            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 = "aix", target_os = "haiku", target_os = "nto"))] +        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( +            freebsdlike, +            netbsdlike, +            solarish, +            target_os = "aix", +            target_os = "emscripten", +            target_os = "haiku", +            target_os = "hurd", +            target_os = "redox", +        )))] +        const IUTF8 = c::IUTF8; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +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, +            freebsdlike, +            target_os = "aix", +            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; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +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 = "nto", target_os = "redox")))] +        const CRTSCTS = c::CRTSCTS; + +        /// `CMSPAR` +        #[cfg(not(any( +            bsd, +            solarish, +            target_os = "aix", +            target_os = "emscripten", +            target_os = "haiku", +            target_os = "hurd", +            target_os = "nto", +            target_os = "redox", +        )))] +        const CMSPAR = c::CMSPAR; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +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(any(target_os = "nto", target_os = "redox")))] +        const ECHOPRT = c::ECHOPRT; + +        /// `ECHOKE` +        #[cfg(not(target_os = "redox"))] +        const ECHOKE = c::ECHOKE; + +        /// `FLUSHO` +        #[cfg(not(any(target_os = "nto", target_os = "redox")))] +        const FLUSHO = c::FLUSHO; + +        /// `PENDIN` +        #[cfg(not(any(target_os = "nto", target_os = "redox")))] +        const PENDIN = c::PENDIN; + +        /// `EXTPROC` +        #[cfg(not(any(target_os = "aix", target_os = "haiku", target_os = "nto", 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; + +        /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> +        const _ = !0; +    } +} + +/// 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`. +    /// +    /// On BSD platforms, integer speed values are already the same as their +    /// encoded values, and on Linux platforms, we use `TCGETS2`/`TCSETS2` +    /// and the `c_ispeed`/`c_ospeed`` fields, except that on Linux on +    /// PowerPC on QEMU, `TCGETS2`/`TCSETS2` don't set `c_ispeed`/`c_ospeed`. +    #[cfg(not(any( +        bsd, +        all( +            linux_kernel, +            not(any(target_arch = "powerpc", target_arch = "powerpc64")) +        ) +    )))] +    pub(crate) const 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(any(target_os = "aix", target_os = "nto")))] +            c::B230400 => Some(230_400), +            #[cfg(not(any( +                apple, +                target_os = "aix", +                target_os = "dragonfly", +                target_os = "haiku", +                target_os = "nto", +                target_os = "openbsd" +            )))] +            c::B460800 => Some(460_800), +            #[cfg(not(any( +                bsd, +                solarish, +                target_os = "aix", +                target_os = "haiku", +                target_os = "nto" +            )))] +            c::B500000 => Some(500_000), +            #[cfg(not(any( +                bsd, +                solarish, +                target_os = "aix", +                target_os = "haiku", +                target_os = "nto" +            )))] +            c::B576000 => Some(576_000), +            #[cfg(not(any( +                apple, +                target_os = "aix", +                target_os = "dragonfly", +                target_os = "haiku", +                target_os = "nto", +                target_os = "openbsd" +            )))] +            c::B921600 => Some(921_600), +            #[cfg(not(any( +                bsd, +                target_os = "aix", +                target_os = "haiku", +                target_os = "nto", +                target_os = "solaris" +            )))] +            c::B1000000 => Some(1_000_000), +            #[cfg(not(any( +                bsd, +                target_os = "aix", +                target_os = "haiku", +                target_os = "nto", +                target_os = "solaris" +            )))] +            c::B1152000 => Some(1_152_000), +            #[cfg(not(any( +                bsd, +                target_os = "aix", +                target_os = "haiku", +                target_os = "nto", +                target_os = "solaris" +            )))] +            c::B1500000 => Some(1_500_000), +            #[cfg(not(any( +                bsd, +                target_os = "aix", +                target_os = "haiku", +                target_os = "nto", +                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 = "nto", +                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 = "nto", +                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 = "nto", +                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 = "nto", +                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) const 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(any(target_os = "aix", target_os = "nto")))] +            230_400 => Some(c::B230400), +            #[cfg(not(any( +                apple, +                target_os = "aix", +                target_os = "dragonfly", +                target_os = "haiku", +                target_os = "nto", +                target_os = "openbsd", +            )))] +            460_800 => Some(c::B460800), +            #[cfg(not(any( +                bsd, +                solarish, +                target_os = "aix", +                target_os = "haiku", +                target_os = "nto" +            )))] +            500_000 => Some(c::B500000), +            #[cfg(not(any( +                bsd, +                solarish, +                target_os = "aix", +                target_os = "haiku", +                target_os = "nto" +            )))] +            576_000 => Some(c::B576000), +            #[cfg(not(any( +                apple, +                target_os = "aix", +                target_os = "dragonfly", +                target_os = "haiku", +                target_os = "nto", +                target_os = "openbsd" +            )))] +            921_600 => Some(c::B921600), +            #[cfg(not(any( +                bsd, +                target_os = "aix", +                target_os = "haiku", +                target_os = "nto", +                target_os = "solaris" +            )))] +            1_000_000 => Some(c::B1000000), +            #[cfg(not(any( +                bsd, +                target_os = "aix", +                target_os = "haiku", +                target_os = "nto", +                target_os = "solaris" +            )))] +            1_152_000 => Some(c::B1152000), +            #[cfg(not(any( +                bsd, +                target_os = "aix", +                target_os = "haiku", +                target_os = "nto", +                target_os = "solaris" +            )))] +            1_500_000 => Some(c::B1500000), +            #[cfg(not(any( +                bsd, +                target_os = "aix", +                target_os = "haiku", +                target_os = "nto", +                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 = "nto", +                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 = "nto", +                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 = "nto", +                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 = "nto", +                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( +        bsd, +        solarish, +        target_os = "aix", +        target_os = "haiku", +        target_os = "hurd", +        target_os = "nto", +    )))] +    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")))] +        const_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_size!(c::termios2, c::termios); +    } + +    #[cfg(not(linux_raw))] +    { +        // On Mips, Sparc, and Android, the libc lacks the ospeed and ispeed +        // fields. +        #[cfg(all( +            not(all( +                target_env = "gnu", +                any( +                    target_arch = "mips", +                    target_arch = "mips32r6", +                    target_arch = "mips64", +                    target_arch = "mips64r6", +                    target_arch = "sparc", +                    target_arch = "sparc64" +                ) +            )), +            not(all(libc, target_os = "android")) +        ))] +        check_renamed_type!(Termios, termios); +        #[cfg(not(all( +            not(all( +                target_env = "gnu", +                any( +                    target_arch = "mips", +                    target_arch = "mips32r6", +                    target_arch = "mips64", +                    target_arch = "mips64r6", +                    target_arch = "sparc", +                    target_arch = "sparc64" +                ) +            )), +            not(all(libc, target_os = "android")) +        )))] +        const_assert!(core::mem::size_of::<Termios>() >= core::mem::size_of::<c::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 = "fuchsia", +            target_os = "haiku", +            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", +    target_os = "haiku", +    target_os = "redox" +)))] +fn termios_legacy() { +    // Check that our doc aliases above are correct. +    const_assert_eq!(c::EXTA, c::B19200); +    const_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. +    const_assert_eq!(c::B0, 0); +    const_assert_eq!(c::B50, 50); +    const_assert_eq!(c::B19200, 19200); +    const_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. + +    const_assert_eq!(c::TCSETS2, c::TCSETS2 + 0); +    const_assert_eq!(c::TCSETSW2, c::TCSETS2 + 1); +    const_assert_eq!(c::TCSETSF2, c::TCSETS2 + 2); + +    const_assert_eq!(c::TCSANOW - c::TCSANOW, 0); +    const_assert_eq!(c::TCSADRAIN - c::TCSANOW, 1); +    const_assert_eq!(c::TCSAFLUSH - c::TCSANOW, 2); + +    // MIPS is different here. +    #[cfg(any( +        target_arch = "mips", +        target_arch = "mips32r6", +        target_arch = "mips64", +        target_arch = "mips64r6" +    ))] +    { +        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 = "mips32r6", +        target_arch = "mips64", +        target_arch = "mips64r6" +    )))] +    { +        const_assert_eq!(c::TCSANOW, 0); +        const_assert_eq!(c::TCSADRAIN, 1); +        const_assert_eq!(c::TCSAFLUSH, 2); +    } +} + +#[cfg(linux_kernel)] +#[test] +fn termios_cibaud() { +    // Test an assumption. +    const_assert_eq!(c::CIBAUD, c::CBAUD << c::IBSHIFT); +}  | 
