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