1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

paste: support multi-stdin (#1791)

- added `-` as the default input, since `paste` reads stdin if no file
is provided
- `paste` also supports providing `-` multiple times
- added a test for it
This commit is contained in:
Ali 2021-03-10 14:19:12 -08:00 committed by GitHub
parent 734ef0a8a1
commit 374a4fde86
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 49 additions and 11 deletions

View file

@ -12,7 +12,7 @@ extern crate uucore;
use clap::{App, Arg}; use clap::{App, Arg};
use std::fs::File; use std::fs::File;
use std::io::{stdin, BufRead, BufReader, Read}; use std::io::{stdin, BufRead, BufReader, Stdin};
use std::iter::repeat; use std::iter::repeat;
use std::path::Path; use std::path::Path;
@ -26,6 +26,29 @@ mod options {
pub const FILE: &str = "file"; pub const FILE: &str = "file";
} }
// We need this trait to wrap both BufReader and Stdin. We need
// `read_line` function only, but Stdin does not provide BufRead
// unless lock function is called, which prevents us from using stdin
// multiple times
trait ReadLine {
fn read_line(&mut self, buf: &mut String) -> std::io::Result<usize>;
}
struct StdinReadLine(Stdin);
struct BufReadReadLine<R: BufRead>(R);
impl ReadLine for StdinReadLine {
fn read_line(&mut self, buf: &mut String) -> std::io::Result<usize> {
return self.0.read_line(buf);
}
}
impl<R: BufRead> ReadLine for BufReadReadLine<R> {
fn read_line(&mut self, buf: &mut String) -> std::io::Result<usize> {
return self.0.read_line(buf);
}
}
pub fn uumain(args: impl uucore::Args) -> i32 { pub fn uumain(args: impl uucore::Args) -> i32 {
let matches = App::new(executable!()) let matches = App::new(executable!())
.version(VERSION) .version(VERSION)
@ -49,7 +72,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
Arg::with_name(options::FILE) Arg::with_name(options::FILE)
.value_name("FILE") .value_name("FILE")
.multiple(true) .multiple(true)
.required(true), .default_value("-"),
) )
.get_matches_from(args); .get_matches_from(args);
@ -66,15 +89,15 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
} }
fn paste(filenames: Vec<String>, serial: bool, delimiters: String) { fn paste(filenames: Vec<String>, serial: bool, delimiters: String) {
let mut files: Vec<BufReader<Box<dyn Read>>> = filenames let mut files: Vec<Box<dyn ReadLine>> = filenames
.into_iter() .into_iter()
.map(|name| { .map(|name| {
BufReader::new(if name == "-" { if name == "-" {
Box::new(stdin()) as Box<dyn Read> Box::new(StdinReadLine(stdin())) as Box<dyn ReadLine>
} else { } else {
let r = crash_if_err!(1, File::open(Path::new(&name))); let r = crash_if_err!(1, File::open(Path::new(&name)));
Box::new(r) as Box<dyn Read> Box::new(BufReadReadLine(BufReader::new(r))) as Box<dyn ReadLine>
}) }
}) })
.collect(); .collect();

View file

@ -2,8 +2,23 @@ use crate::common::util::*;
#[test] #[test]
fn test_combine_pairs_of_lines() { fn test_combine_pairs_of_lines() {
new_ucmd!() for s in vec!["-s", "--serial"] {
.args(&["-s", "-d", "\t\n", "html_colors.txt"]) for d in vec!["-d", "--delimiters"] {
.run() new_ucmd!()
.stdout_is_fixture("html_colors.expected"); .args(&[s, d, "\t\n", "html_colors.txt"])
.run()
.stdout_is_fixture("html_colors.expected");
}
}
}
#[test]
fn test_multi_stdin() {
for d in vec!["-d", "--delimiters"] {
new_ucmd!()
.args(&[d, "\t\n", "-", "-"])
.pipe_in_fixture("html_colors.txt")
.succeeds()
.stdout_is_fixture("html_colors.expected");
}
} }