summaryrefslogtreecommitdiff
path: root/vendor/rustix/src/termios
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2024-01-08 00:21:28 +0300
committerValentin Popov <valentin@popov.link>2024-01-08 00:21:28 +0300
commit1b6a04ca5504955c571d1c97504fb45ea0befee4 (patch)
tree7579f518b23313e8a9748a88ab6173d5e030b227 /vendor/rustix/src/termios
parent5ecd8cf2cba827454317368b68571df0d13d7842 (diff)
downloadfparkan-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.rs53
-rw-r--r--vendor/rustix/src/termios/mod.rs27
-rw-r--r--vendor/rustix/src/termios/tc.rs209
-rw-r--r--vendor/rustix/src/termios/tty.rs84
-rw-r--r--vendor/rustix/src/termios/types.rs1450
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);
+}