1#[cfg(windows)]
15use windows_sys::Win32::System::Console::STD_HANDLE;
16
17#[cfg(windows)]
18type WCHAR = u16;
19
20#[derive(Clone, Copy, Debug)]
22pub enum Stream {
23 Stdout,
24 Stderr,
25 Stdin,
26}
27
28#[cfg(target_family = "unix")]
30pub fn is(stream: Stream) -> bool {
31 let fd = match stream {
32 Stream::Stdout => libc::STDOUT_FILENO,
33 Stream::Stderr => libc::STDERR_FILENO,
34 Stream::Stdin => libc::STDIN_FILENO,
35 };
36 unsafe { libc::isatty(fd) != 0 }
37}
38
39#[cfg(target_os = "hermit")]
41pub fn is(stream: Stream) -> bool {
42 let fd = match stream {
43 Stream::Stdout => hermit_abi::STDOUT_FILENO,
44 Stream::Stderr => hermit_abi::STDERR_FILENO,
45 Stream::Stdin => hermit_abi::STDIN_FILENO,
46 };
47 hermit_abi::isatty(fd)
48}
49
50#[cfg(windows)]
52pub fn is(stream: Stream) -> bool {
53 use windows_sys::Win32::System::Console::{
54 STD_ERROR_HANDLE as STD_ERROR, STD_INPUT_HANDLE as STD_INPUT,
55 STD_OUTPUT_HANDLE as STD_OUTPUT,
56 };
57
58 let (fd, others) = match stream {
59 Stream::Stdin => (STD_INPUT, [STD_ERROR, STD_OUTPUT]),
60 Stream::Stderr => (STD_ERROR, [STD_INPUT, STD_OUTPUT]),
61 Stream::Stdout => (STD_OUTPUT, [STD_INPUT, STD_ERROR]),
62 };
63 if unsafe { console_on_any(&[fd]) } {
64 return true;
67 }
68
69 if unsafe { console_on_any(&others) } {
74 return false;
75 }
76
77 unsafe { msys_tty_on(fd) }
80}
81
82pub fn isnt(stream: Stream) -> bool {
84 !is(stream)
85}
86
87#[cfg(windows)]
89unsafe fn console_on_any(fds: &[STD_HANDLE]) -> bool {
90 use windows_sys::Win32::System::Console::{GetConsoleMode, GetStdHandle};
91
92 for &fd in fds {
93 let mut out = 0;
94 let handle = GetStdHandle(fd);
95 if GetConsoleMode(handle, &mut out) != 0 {
96 return true;
97 }
98 }
99 false
100}
101
102#[cfg(windows)]
104unsafe fn msys_tty_on(fd: STD_HANDLE) -> bool {
105 use std::os::raw::c_void;
106 use std::{mem, slice};
107
108 use windows_sys::Win32::Foundation::MAX_PATH;
109 use windows_sys::Win32::Storage::FileSystem::GetFileInformationByHandleEx;
110 use windows_sys::Win32::Storage::FileSystem::{FileNameInfo, FILE_NAME_INFO};
111 use windows_sys::Win32::System::Console::GetStdHandle;
112
113 let size = mem::size_of::<FILE_NAME_INFO>();
114 let mut name_info_bytes = vec![0u8; size + MAX_PATH as usize * mem::size_of::<WCHAR>()];
115 let res = GetFileInformationByHandleEx(
116 GetStdHandle(fd),
117 FileNameInfo,
118 &mut *name_info_bytes as *mut _ as *mut c_void,
119 name_info_bytes.len() as u32,
120 );
121 if res == 0 {
122 return false;
123 }
124 let name_info: &FILE_NAME_INFO = &*(name_info_bytes.as_ptr() as *const FILE_NAME_INFO);
125 let s = slice::from_raw_parts(
126 name_info.FileName.as_ptr(),
127 name_info.FileNameLength as usize / 2,
128 );
129 let name = String::from_utf16_lossy(s);
130 let is_msys = name.contains("msys-") || name.contains("cygwin-");
135 let is_pty = name.contains("-pty");
136 is_msys && is_pty
137}
138
139#[cfg(target_family = "wasm")]
141pub fn is(_stream: Stream) -> bool {
142 false
143}