diff options
Diffstat (limited to 'vendor/is-terminal')
-rw-r--r-- | vendor/is-terminal/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | vendor/is-terminal/Cargo.toml | 66 | ||||
-rw-r--r-- | vendor/is-terminal/LICENSE-MIT | 23 | ||||
-rw-r--r-- | vendor/is-terminal/LICENSE-MIT-atty | 23 | ||||
-rw-r--r-- | vendor/is-terminal/README.md | 104 | ||||
-rw-r--r-- | vendor/is-terminal/src/lib.rs | 372 |
6 files changed, 589 insertions, 0 deletions
diff --git a/vendor/is-terminal/.cargo-checksum.json b/vendor/is-terminal/.cargo-checksum.json new file mode 100644 index 000000000..0ee665981 --- /dev/null +++ b/vendor/is-terminal/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"66d1f0c7750bdccaddfb640efd98eaab478847f43db9bb61081e009c3f7327a8","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","LICENSE-MIT-atty":"bab426a663ce3d5bbbcea9cdc300da74e94d76c3c79e46699a953f967a08e533","README.md":"bb23e10d4801dee704d2743631e3ca9de6af95761c649e9bd79d62f2df838c9d","src/lib.rs":"eee9f49135fa9f3c24a0e09d0e74a5d5a9f383951dc95c8b08f511102364eb1d"},"package":"21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857"}
\ No newline at end of file diff --git a/vendor/is-terminal/Cargo.toml b/vendor/is-terminal/Cargo.toml new file mode 100644 index 000000000..b195f11d0 --- /dev/null +++ b/vendor/is-terminal/Cargo.toml @@ -0,0 +1,66 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +rust-version = "1.48" +name = "is-terminal" +version = "0.4.4" +authors = [ + "softprops <d.tangren@gmail.com>", + "Dan Gohman <dev@sunfishcode.online>", +] +include = [ + "src", + "build.rs", + "Cargo.toml", + "COPYRIGHT", + "LICENSE*", + "/*.md", +] +description = "Test whether a given stream is a terminal" +documentation = "http://docs.rs/is-terminal" +readme = "README.md" +keywords = [ + "terminal", + "tty", + "isatty", +] +categories = ["command-line-interface"] +license = "MIT" +repository = "https://github.com/sunfishcode/is-terminal" + +[dependencies.io-lifetimes] +version = "1.0.0" + +[dev-dependencies.atty] +version = "0.2.14" + +[target."cfg(any(unix, target_os = \"wasi\"))".dev-dependencies.libc] +version = "0.2.110" + +[target."cfg(not(any(windows, target_os = \"hermit\", target_os = \"unknown\")))".dependencies.rustix] +version = "0.36.4" +features = ["termios"] + +[target."cfg(target_os = \"hermit\")".dependencies.hermit-abi] +version = "0.3.0" + +[target."cfg(windows)".dependencies.windows-sys] +version = "0.45.0" +features = [ + "Win32_Foundation", + "Win32_Storage_FileSystem", + "Win32_System_Console", +] + +[target."cfg(windows)".dev-dependencies.tempfile] +version = "3" diff --git a/vendor/is-terminal/LICENSE-MIT b/vendor/is-terminal/LICENSE-MIT new file mode 100644 index 000000000..31aa79387 --- /dev/null +++ b/vendor/is-terminal/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/vendor/is-terminal/LICENSE-MIT-atty b/vendor/is-terminal/LICENSE-MIT-atty new file mode 100644 index 000000000..b2319d808 --- /dev/null +++ b/vendor/is-terminal/LICENSE-MIT-atty @@ -0,0 +1,23 @@ +Portions of this project are derived from atty, which bears the following +copyright notice and permission notice: + +Copyright (c) 2015-2019 Doug Tangren + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/is-terminal/README.md b/vendor/is-terminal/README.md new file mode 100644 index 000000000..081d93685 --- /dev/null +++ b/vendor/is-terminal/README.md @@ -0,0 +1,104 @@ +<div align="center"> + <h1><code>is-terminal</code></h1> + + <p> + <strong>Test whether a given stream is a terminal</strong> + </p> + + <p> + <a href="https://github.com/sunfishcode/is-terminal/actions?query=workflow%3ACI"><img src="https://github.com/sunfishcode/is-terminal/workflows/CI/badge.svg" alt="Github Actions CI Status" /></a> + <a href="https://crates.io/crates/is-terminal"><img src="https://img.shields.io/crates/v/is-terminal.svg" alt="crates.io page" /></a> + <a href="https://docs.rs/is-terminal"><img src="https://docs.rs/is-terminal/badge.svg" alt="docs.rs docs" /></a> + </p> +</div> + +is-terminal is a simple utility that answers one question: + +> Is this a terminal? + +A "terminal", also known as a "tty", is an I/O device which may be interactive +and may support color and other special features. This crate doesn't provide +any of those features; it just answers this one question. + +On Unix-family platforms, this is effectively the same as the [`isatty`] +function for testing whether a given stream is a terminal, though it accepts +high-level stream types instead of raw file descriptors. + +On Windows, it uses a variety of techniques to determine whether the given +stream is a terminal. + +This crate is derived from [the atty crate] with [PR \#51] bug fix and +[PR \#54] port to windows-sys applied. The only additional difference is that +the atty crate only accepts stdin, stdout, or stderr, while this crate accepts +any stream. In particular, this crate does not access any stream that is not +passed to it, in accordance with [I/O safety]. + +[PR \#51]: https://github.com/softprops/atty/pull/51 +[PR \#54]: https://github.com/softprops/atty/pull/54 + +## Example + +```rust +use is_terminal::IsTerminal; + +fn main() { + if std::io::stdout().is_terminal() { + println!("Stdout is a terminal"); + } else { + println!("Stdout is not a terminal"); + } +} +``` + +## Testing + +This library is tested on both Unix-family and Windows platforms. + +To test it on a platform manually, use the provided `stdio` example program. +When run normally, it prints this: + +```bash +$ cargo run --example stdio +stdin? true +stdout? true +stderr? true +``` + +To test stdin, pipe some text to the program: + +```bash +$ cat | cargo run --example stdio +stdin? false +stdout? true +stderr? true +``` + +To test stdout, pipe the program to something: + +```bash +$ cargo run --example stdio | cat +stdin? true +stdout? false +stderr? true +``` + +To test stderr, pipe the program to something redirecting stderr: + +```bash +$ cargo run --example stdio 2>&1 | cat +stdin? true +stdout? false +stderr? false +``` + +# Minimum Supported Rust Version (MSRV) + +This crate currently works on the version of [Rust on Debian stable], which is +currently Rust 1.48. This policy may change in the future, in minor version +releases, so users using a fixed version of Rust should pin to a specific +version of this crate. + +[`isatty`]: https://man7.org/linux/man-pages/man3/isatty.3.html +[the atty crate]: https://crates.io/crates/atty +[I/O safety]: https://github.com/rust-lang/rfcs/blob/master/text/3128-io-safety.md +[Rust on Debian stable]: https://packages.debian.org/stable/rust/rustc diff --git a/vendor/is-terminal/src/lib.rs b/vendor/is-terminal/src/lib.rs new file mode 100644 index 000000000..18d41e14d --- /dev/null +++ b/vendor/is-terminal/src/lib.rs @@ -0,0 +1,372 @@ +//! is-terminal is a simple utility that answers one question: +//! +//! > Is this a terminal? +//! +//! A "terminal", also known as a "tty", is an I/O device which may be +//! interactive and may support color and other special features. This crate +//! doesn't provide any of those features; it just answers this one question. +//! +//! On Unix-family platforms, this is effectively the same as the [`isatty`] +//! function for testing whether a given stream is a terminal, though it +//! accepts high-level stream types instead of raw file descriptors. +//! +//! On Windows, it uses a variety of techniques to determine whether the +//! given stream is a terminal. +//! +//! # Example +//! +//! ```rust +//! use is_terminal::IsTerminal; +//! +//! if std::io::stdout().is_terminal() { +//! println!("stdout is a terminal") +//! } +//! ``` +//! +//! [`isatty`]: https://man7.org/linux/man-pages/man3/isatty.3.html + +#![cfg_attr(unix, no_std)] + +#[cfg(not(target_os = "unknown"))] +use io_lifetimes::AsFilelike; +#[cfg(windows)] +use io_lifetimes::BorrowedHandle; +#[cfg(windows)] +use std::os::windows::io::AsRawHandle; +#[cfg(windows)] +use windows_sys::Win32::Foundation::HANDLE; + +pub trait IsTerminal { + /// Returns true if this is a terminal. + /// + /// # Example + /// + /// ``` + /// use is_terminal::IsTerminal; + /// + /// if std::io::stdout().is_terminal() { + /// println!("stdout is a terminal") + /// } + /// ``` + fn is_terminal(&self) -> bool; +} + +#[cfg(not(target_os = "unknown"))] +impl<Stream: AsFilelike> IsTerminal for Stream { + #[inline] + fn is_terminal(&self) -> bool { + #[cfg(any(unix, target_os = "wasi"))] + { + rustix::termios::isatty(self) + } + + #[cfg(target_os = "hermit")] + { + hermit_abi::isatty(self.as_filelike().as_fd()) + } + + #[cfg(windows)] + { + handle_is_console(self.as_filelike()) + } + } +} + +// The Windows implementation here is copied from `handle_is_console` in +// std/src/sys/windows/io.rs in Rust at revision +// d7b0bcb20f2f7d5f3ea3489d56ece630147e98f5. + +#[cfg(windows)] +fn handle_is_console(handle: BorrowedHandle<'_>) -> bool { + use windows_sys::Win32::System::Console::{ + GetConsoleMode, GetStdHandle, STD_ERROR_HANDLE, STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, + }; + + let handle = handle.as_raw_handle(); + + unsafe { + // A null handle means the process has no console. + if handle.is_null() { + return false; + } + + let mut out = 0; + if GetConsoleMode(handle as HANDLE, &mut out) != 0 { + // False positives aren't possible. If we got a console then we definitely have a console. + return true; + } + + // At this point, we *could* have a false negative. We can determine that this is a true + // negative if we can detect the presence of a console on any of the standard I/O streams. If + // another stream has a console, then we know we're in a Windows console and can therefore + // trust the negative. + for std_handle in [STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE] { + let std_handle = GetStdHandle(std_handle); + if std_handle != 0 + && std_handle != handle as HANDLE + && GetConsoleMode(std_handle, &mut out) != 0 + { + return false; + } + } + + // Otherwise, we fall back to an msys hack to see if we can detect the presence of a pty. + msys_tty_on(handle as HANDLE) + } +} + +/// Returns true if there is an MSYS tty on the given handle. +/// +/// This incoproates d7b0bcb20f2f7d5f3ea3489d56ece630147e98f5 +#[cfg(windows)] +unsafe fn msys_tty_on(handle: HANDLE) -> bool { + use std::ffi::c_void; + use windows_sys::Win32::{ + Foundation::MAX_PATH, + Storage::FileSystem::{ + FileNameInfo, GetFileInformationByHandleEx, GetFileType, FILE_TYPE_PIPE, + }, + }; + + // Early return if the handle is not a pipe. + if GetFileType(handle) != FILE_TYPE_PIPE { + return false; + } + + /// Mirrors windows_sys::Win32::Storage::FileSystem::FILE_NAME_INFO, giving + /// it a fixed length that we can stack allocate + #[repr(C)] + #[allow(non_snake_case)] + struct FILE_NAME_INFO { + FileNameLength: u32, + FileName: [u16; MAX_PATH as usize], + } + let mut name_info = FILE_NAME_INFO { + FileNameLength: 0, + FileName: [0; MAX_PATH as usize], + }; + // Safety: buffer length is fixed. + let res = GetFileInformationByHandleEx( + handle, + FileNameInfo, + &mut name_info as *mut _ as *mut c_void, + std::mem::size_of::<FILE_NAME_INFO>() as u32, + ); + if res == 0 { + return false; + } + + // Use `get` because `FileNameLength` can be out of range. + let s = match name_info + .FileName + .get(..name_info.FileNameLength as usize / 2) + { + None => return false, + Some(s) => s, + }; + let name = String::from_utf16_lossy(s); + // Get the file name only. + let name = name.rsplit('\\').next().unwrap_or(&name); + // This checks whether 'pty' exists in the file name, which indicates that + // a pseudo-terminal is attached. To mitigate against false positives + // (e.g., an actual file name that contains 'pty'), we also require that + // the file name begins with either the strings 'msys-' or 'cygwin-'.) + let is_msys = name.starts_with("msys-") || name.starts_with("cygwin-"); + let is_pty = name.contains("-pty"); + is_msys && is_pty +} + +#[cfg(target_os = "unknown")] +impl IsTerminal for std::io::Stdin { + #[inline] + fn is_terminal(&self) -> bool { + false + } +} + +#[cfg(target_os = "unknown")] +impl IsTerminal for std::io::Stdout { + #[inline] + fn is_terminal(&self) -> bool { + false + } +} + +#[cfg(target_os = "unknown")] +impl IsTerminal for std::io::Stderr { + #[inline] + fn is_terminal(&self) -> bool { + false + } +} + +#[cfg(target_os = "unknown")] +impl<'a> IsTerminal for std::io::StdinLock<'a> { + #[inline] + fn is_terminal(&self) -> bool { + false + } +} + +#[cfg(target_os = "unknown")] +impl<'a> IsTerminal for std::io::StdoutLock<'a> { + #[inline] + fn is_terminal(&self) -> bool { + false + } +} + +#[cfg(target_os = "unknown")] +impl<'a> IsTerminal for std::io::StderrLock<'a> { + #[inline] + fn is_terminal(&self) -> bool { + false + } +} + +#[cfg(target_os = "unknown")] +impl<'a> IsTerminal for std::fs::File { + #[inline] + fn is_terminal(&self) -> bool { + false + } +} + +#[cfg(target_os = "unknown")] +impl IsTerminal for std::process::ChildStdin { + #[inline] + fn is_terminal(&self) -> bool { + false + } +} + +#[cfg(target_os = "unknown")] +impl IsTerminal for std::process::ChildStdout { + #[inline] + fn is_terminal(&self) -> bool { + false + } +} + +#[cfg(target_os = "unknown")] +impl IsTerminal for std::process::ChildStderr { + #[inline] + fn is_terminal(&self) -> bool { + false + } +} + +#[cfg(test)] +mod tests { + #[cfg(not(target_os = "unknown"))] + use super::IsTerminal; + + #[test] + #[cfg(windows)] + fn stdin() { + assert_eq!( + atty::is(atty::Stream::Stdin), + std::io::stdin().is_terminal() + ) + } + + #[test] + #[cfg(windows)] + fn stdout() { + assert_eq!( + atty::is(atty::Stream::Stdout), + std::io::stdout().is_terminal() + ) + } + + #[test] + #[cfg(windows)] + fn stderr() { + assert_eq!( + atty::is(atty::Stream::Stderr), + std::io::stderr().is_terminal() + ) + } + + #[test] + #[cfg(any(unix, target_os = "wasi"))] + fn stdin() { + unsafe { + assert_eq!( + atty::is(atty::Stream::Stdin), + rustix::io::stdin().is_terminal() + ) + } + } + + #[test] + #[cfg(any(unix, target_os = "wasi"))] + fn stdout() { + unsafe { + assert_eq!( + atty::is(atty::Stream::Stdout), + rustix::io::stdout().is_terminal() + ) + } + } + + #[test] + #[cfg(any(unix, target_os = "wasi"))] + fn stderr() { + unsafe { + assert_eq!( + atty::is(atty::Stream::Stderr), + rustix::io::stderr().is_terminal() + ) + } + } + + #[test] + #[cfg(any(unix, target_os = "wasi"))] + fn stdin_vs_libc() { + unsafe { + assert_eq!( + libc::isatty(libc::STDIN_FILENO) != 0, + rustix::io::stdin().is_terminal() + ) + } + } + + #[test] + #[cfg(any(unix, target_os = "wasi"))] + fn stdout_vs_libc() { + unsafe { + assert_eq!( + libc::isatty(libc::STDOUT_FILENO) != 0, + rustix::io::stdout().is_terminal() + ) + } + } + + #[test] + #[cfg(any(unix, target_os = "wasi"))] + fn stderr_vs_libc() { + unsafe { + assert_eq!( + libc::isatty(libc::STDERR_FILENO) != 0, + rustix::io::stderr().is_terminal() + ) + } + } + + // Verify that the msys_tty_on function works with long path. + #[test] + #[cfg(windows)] + fn msys_tty_on_path_length() { + use std::{fs::File, os::windows::io::AsRawHandle}; + use windows_sys::Win32::Foundation::MAX_PATH; + + let dir = tempfile::tempdir().expect("Unable to create temporary directory"); + let file_path = dir.path().join("ten_chars_".repeat(25)); + // Ensure that the path is longer than MAX_PATH. + assert!(file_path.to_string_lossy().len() > MAX_PATH as usize); + let file = File::create(file_path).expect("Unable to create file"); + + assert!(!unsafe { crate::msys_tty_on(file.as_raw_handle() as isize) }); + } +} |