mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 19:47:45 +00:00
Merge pull request #6951 from fuad1502/csplit-pipe-input
csplit: support reading from pipe
This commit is contained in:
commit
50571c7346
3 changed files with 76 additions and 18 deletions
|
@ -87,7 +87,11 @@ pub fn csplit<T>(options: &CsplitOptions, patterns: &[String], input: T) -> Resu
|
|||
where
|
||||
T: BufRead,
|
||||
{
|
||||
let mut input_iter = InputSplitter::new(input.lines().enumerate());
|
||||
let enumerated_input_lines = input
|
||||
.lines()
|
||||
.map(|line| line.map_err_context(|| "read error".to_string()))
|
||||
.enumerate();
|
||||
let mut input_iter = InputSplitter::new(enumerated_input_lines);
|
||||
let mut split_writer = SplitWriter::new(options);
|
||||
let patterns: Vec<patterns::Pattern> = patterns::get_patterns(patterns)?;
|
||||
let ret = do_csplit(&mut split_writer, patterns, &mut input_iter);
|
||||
|
@ -117,7 +121,7 @@ fn do_csplit<I>(
|
|||
input_iter: &mut InputSplitter<I>,
|
||||
) -> Result<(), CsplitError>
|
||||
where
|
||||
I: Iterator<Item = (usize, io::Result<String>)>,
|
||||
I: Iterator<Item = (usize, UResult<String>)>,
|
||||
{
|
||||
// split the file based on patterns
|
||||
for pattern in patterns {
|
||||
|
@ -305,7 +309,7 @@ impl SplitWriter<'_> {
|
|||
input_iter: &mut InputSplitter<I>,
|
||||
) -> Result<(), CsplitError>
|
||||
where
|
||||
I: Iterator<Item = (usize, io::Result<String>)>,
|
||||
I: Iterator<Item = (usize, UResult<String>)>,
|
||||
{
|
||||
input_iter.rewind_buffer();
|
||||
input_iter.set_size_of_buffer(1);
|
||||
|
@ -358,7 +362,7 @@ impl SplitWriter<'_> {
|
|||
input_iter: &mut InputSplitter<I>,
|
||||
) -> Result<(), CsplitError>
|
||||
where
|
||||
I: Iterator<Item = (usize, io::Result<String>)>,
|
||||
I: Iterator<Item = (usize, UResult<String>)>,
|
||||
{
|
||||
if offset >= 0 {
|
||||
// The offset is zero or positive, no need for a buffer on the lines read.
|
||||
|
@ -470,7 +474,7 @@ impl SplitWriter<'_> {
|
|||
/// This is used to pass matching lines to the next split and to support patterns with a negative offset.
|
||||
struct InputSplitter<I>
|
||||
where
|
||||
I: Iterator<Item = (usize, io::Result<String>)>,
|
||||
I: Iterator<Item = (usize, UResult<String>)>,
|
||||
{
|
||||
iter: I,
|
||||
buffer: Vec<<I as Iterator>::Item>,
|
||||
|
@ -483,7 +487,7 @@ where
|
|||
|
||||
impl<I> InputSplitter<I>
|
||||
where
|
||||
I: Iterator<Item = (usize, io::Result<String>)>,
|
||||
I: Iterator<Item = (usize, UResult<String>)>,
|
||||
{
|
||||
fn new(iter: I) -> Self {
|
||||
Self {
|
||||
|
@ -547,7 +551,7 @@ where
|
|||
|
||||
impl<I> Iterator for InputSplitter<I>
|
||||
where
|
||||
I: Iterator<Item = (usize, io::Result<String>)>,
|
||||
I: Iterator<Item = (usize, UResult<String>)>,
|
||||
{
|
||||
type Item = <I as Iterator>::Item;
|
||||
|
||||
|
@ -581,13 +585,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
Ok(csplit(&options, &patterns, stdin.lock())?)
|
||||
} else {
|
||||
let file = File::open(file_name)
|
||||
.map_err_context(|| format!("cannot access {}", file_name.quote()))?;
|
||||
let file_metadata = file
|
||||
.metadata()
|
||||
.map_err_context(|| format!("cannot access {}", file_name.quote()))?;
|
||||
if !file_metadata.is_file() {
|
||||
return Err(CsplitError::NotRegularFile(file_name.to_string()).into());
|
||||
}
|
||||
.map_err_context(|| format!("cannot open {} for reading", file_name.quote()))?;
|
||||
Ok(csplit(&options, &patterns, BufReader::new(file))?)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ pub enum CsplitError {
|
|||
SuffixFormatTooManyPercents,
|
||||
#[error("{} is not a regular file", ._0.quote())]
|
||||
NotRegularFile(String),
|
||||
#[error("{}", _0)]
|
||||
UError(Box<dyn UError>),
|
||||
}
|
||||
|
||||
impl From<io::Error> for CsplitError {
|
||||
|
@ -43,8 +45,17 @@ impl From<io::Error> for CsplitError {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Box<dyn UError>> for CsplitError {
|
||||
fn from(error: Box<dyn UError>) -> Self {
|
||||
Self::UError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl UError for CsplitError {
|
||||
fn code(&self) -> i32 {
|
||||
1
|
||||
match self {
|
||||
Self::UError(e) => e.code(),
|
||||
_ => 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1379,7 +1379,7 @@ fn no_such_file() {
|
|||
let (_, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.args(&["in", "0"])
|
||||
.fails()
|
||||
.stderr_contains("cannot access 'in': No such file or directory");
|
||||
.stderr_contains("cannot open 'in' for reading: No such file or directory");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1417,3 +1417,52 @@ fn repeat_everything() {
|
|||
assert_eq!(at.read("xxz_004"), generate(37, 44 + 1));
|
||||
assert_eq!(at.read("xxz_005"), generate(46, 50 + 1));
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn test_named_pipe_input_file() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
let mut fifo_writer =
|
||||
create_named_pipe_with_writer(&at.plus_as_string("fifo"), &generate(1, 51));
|
||||
|
||||
let result = ucmd.args(&["fifo", "10"]).succeeds();
|
||||
fifo_writer.kill().unwrap();
|
||||
fifo_writer.wait().unwrap();
|
||||
result.stdout_only("18\n123\n");
|
||||
|
||||
let count = glob(&at.plus_as_string("xx*"))
|
||||
.expect("there should be splits created")
|
||||
.count();
|
||||
assert_eq!(count, 2);
|
||||
assert_eq!(at.read("xx00"), generate(1, 10));
|
||||
assert_eq!(at.read("xx01"), generate(10, 51));
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn create_named_pipe_with_writer(path: &str, data: &str) -> std::process::Child {
|
||||
// cSpell:ignore IRWXU
|
||||
nix::unistd::mkfifo(path, nix::sys::stat::Mode::S_IRWXU).unwrap();
|
||||
std::process::Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(format!("printf '{}' > {path}", data))
|
||||
.spawn()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_directory_input_file() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.mkdir("test_directory");
|
||||
|
||||
#[cfg(unix)]
|
||||
ucmd.args(&["test_directory", "1"])
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.stderr_only("csplit: read error: Is a directory\n");
|
||||
#[cfg(windows)]
|
||||
ucmd.args(&["test_directory", "1"])
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.stderr_only("csplit: cannot open 'test_directory' for reading: Permission denied\n");
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue