Added ergonomics for `-n`/`--no-consume`: Will consume data if it is non-blocking to *start* consuming. Added TTY checks for input/output chain file.
Fortune for genmarkov's current commit: Future small blessing − 末小吉cli
parent
19b5f322dc
commit
72101413f0
@ -0,0 +1,77 @@
|
||||
//! I/O utilities.
|
||||
//! For working with `ioctl()` & other lower-level file-descriptor operations like peeking & terminal queries.
|
||||
use std::os::unix::prelude::*;
|
||||
use std::os::fd::AsFd;
|
||||
use std::ffi::{
|
||||
c_int,
|
||||
};
|
||||
use std::{
|
||||
io,
|
||||
num::NonZeroUsize,
|
||||
};
|
||||
|
||||
/// Check if open stream `file` refers to a terminal.
|
||||
pub fn is_tty<T: ?Sized>(file: &T) -> bool
|
||||
where T: AsFd
|
||||
{
|
||||
// SAFETY: This function is (essentially) pure.
|
||||
unsafe extern "C" {
|
||||
safe fn isatty(fd: c_int) -> c_int;
|
||||
}
|
||||
|
||||
let file = file.as_fd();
|
||||
match isatty(file.as_raw_fd()) {
|
||||
1 => true,
|
||||
0 => false,
|
||||
bug => unreachable!("BUG: isatty({:?}) invalid return value: {:?}", file, bug),
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if stream `file` has data ready to read.
|
||||
///
|
||||
/// # Returns
|
||||
/// If `Err` is returned and the kind is `ErrorKind::Unsupported`, the operation could not be carried out.
|
||||
/// If `ioctl(FIONREAD)` fails on `file`'s fd, the `ioctl()` call's error is returned.
|
||||
///
|
||||
/// Otherwise:
|
||||
/// - If `Ok(None)` is returned, there are 0 bytes pending.
|
||||
/// - If `Ok(Some(x))`is returned, there are at least `x` bytes pending.
|
||||
///
|
||||
/// __NOTE__: It is not guaranteed that this function will be able to return an `Ok()` value, these are not fatal errors.
|
||||
pub fn has_known_available_data<T: ?Sized>(file: &T) -> io::Result<Option<NonZeroUsize>>
|
||||
where T: AsFd
|
||||
{
|
||||
#[cfg(feature="posix_io")]
|
||||
fn check_fd_raw(file: impl AsRawFd) -> io::Result<c_int>
|
||||
{
|
||||
use libc::{
|
||||
ioctl,
|
||||
FIONREAD,
|
||||
};
|
||||
|
||||
let mut num: c_int = 0;
|
||||
// SAFETY: FIONREAD takes `int*`
|
||||
match unsafe {
|
||||
ioctl(file.as_raw_fd(), FIONREAD, &raw mut num)
|
||||
} {
|
||||
0 => Ok(num),
|
||||
_ => Err(io::Error::last_os_error()),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature="posix_io"))]
|
||||
#[inline(always)]
|
||||
fn check_fd_raw(_file: impl AsRawFd) -> io::Result<c_int>
|
||||
{
|
||||
Err(io::Error::new(io::ErrorKind::Unsupported, "Operation unsupported"))
|
||||
}
|
||||
|
||||
let file = file.as_fd();
|
||||
|
||||
let num = check_fd_raw(file)?;
|
||||
if num < 0 {
|
||||
Err(io::Error::new(io::ErrorKind::InvalidData, "ioctl(FIONREAD) returned an invalid invariant"))
|
||||
} else {
|
||||
Ok(NonZeroUsize::new(num as usize))
|
||||
}
|
||||
}
|
Loading…
Reference in new issue