diff --git a/programs/fileio.c b/programs/fileio.c index 7a6af7929..46a842f6a 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -4998,12 +4998,8 @@ FIO_listFile(const char* inFileName, int displayLevel, } } -static int -FIO_listFileIsStdin(void* opaque, const char* fileName) -{ - (void)opaque; - return !strcmp(fileName, stdinmark); -} +/* Rust owns this stateless --list input-name predicate. */ +int FIO_listFileIsStdin(void* opaque, const char* fileName); static void FIO_listFileDisplayStdinError(void* opaque) diff --git a/rust/cli/src/lib.rs b/rust/cli/src/lib.rs index 31c5da2a3..0a2631e39 100644 --- a/rust/cli/src/lib.rs +++ b/rust/cli/src/lib.rs @@ -29,3 +29,41 @@ mod zstd_cli; #[cfg(feature = "cli")] #[path = "../../src/zstdcli_trace.rs"] mod zstdcli_trace; + +#[cfg(feature = "cli")] +use std::ffi::c_void; +#[cfg(feature = "cli")] +use std::os::raw::{c_char, c_int}; + +/// Match the C `--list` stdin callback without crossing any file-I/O state. +#[cfg(feature = "cli")] +#[no_mangle] +pub unsafe extern "C" fn FIO_listFileIsStdin( + _opaque: *mut c_void, + file_name: *const c_char, +) -> c_int { + assert!(!file_name.is_null()); + c_int::from(unsafe { libc::strcmp(file_name, c"/*stdin*\\".as_ptr()) == 0 }) +} + +#[cfg(all(test, feature = "cli"))] +mod tests { + use super::FIO_listFileIsStdin; + use std::ffi::CString; + use std::ptr; + + #[test] + fn list_stdin_callback_matches_only_the_stdin_marker() { + let stdin_name = CString::new("/*stdin*\\").unwrap(); + let ordinary_name = CString::new("input.zst").unwrap(); + + assert_eq!( + unsafe { FIO_listFileIsStdin(ptr::null_mut(), stdin_name.as_ptr()) }, + 1 + ); + assert_eq!( + unsafe { FIO_listFileIsStdin(ptr::null_mut(), ordinary_name.as_ptr()) }, + 0 + ); + } +}