1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-29 12:07:46 +00:00

shuf: use UResult

This commit is contained in:
Thomas Queiroz 2021-11-16 18:04:20 -03:00
parent bcef1d6cca
commit 06f3db8c55
No known key found for this signature in database
GPG key ID: 229D2DDF7ECA5F8F

View file

@ -7,14 +7,12 @@
// spell-checker:ignore (ToDO) cmdline evec seps rvec fdata // spell-checker:ignore (ToDO) cmdline evec seps rvec fdata
#[macro_use]
extern crate uucore;
use clap::{crate_version, App, Arg}; use clap::{crate_version, App, Arg};
use rand::Rng; use rand::Rng;
use std::fs::File; use std::fs::File;
use std::io::{stdin, stdout, BufReader, BufWriter, Read, Write}; use std::io::{stdin, stdout, BufReader, BufWriter, Read, Write};
use uucore::display::Quotable; use uucore::display::Quotable;
use uucore::error::{FromIo, UResult, USimpleError};
use uucore::InvalidEncodingHandling; use uucore::InvalidEncodingHandling;
enum Mode { enum Mode {
@ -52,7 +50,8 @@ mod options {
pub static FILE: &str = "file"; pub static FILE: &str = "file";
} }
pub fn uumain(args: impl uucore::Args) -> i32 { #[uucore_procs::gen_uumain]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let args = args let args = args
.collect_str(InvalidEncodingHandling::ConvertLossy) .collect_str(InvalidEncodingHandling::ConvertLossy)
.accept_any(); .accept_any();
@ -65,7 +64,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
match parse_range(range) { match parse_range(range) {
Ok(m) => Mode::InputRange(m), Ok(m) => Mode::InputRange(m),
Err(msg) => { Err(msg) => {
crash!(1, "{}", msg); return Err(USimpleError::new(1, msg));
} }
} }
} else { } else {
@ -77,8 +76,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
Some(count) => match count.parse::<usize>() { Some(count) => match count.parse::<usize>() {
Ok(val) => val, Ok(val) => val,
Err(_) => { Err(_) => {
show_error!("invalid line count: {}", count.quote()); return Err(USimpleError::new(
return 1; 1,
format!("invalid line count: {}", count.quote()),
));
} }
}, },
None => std::usize::MAX, None => std::usize::MAX,
@ -97,22 +98,22 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
Mode::Echo(args) => { Mode::Echo(args) => {
let mut evec = args.iter().map(String::as_bytes).collect::<Vec<_>>(); let mut evec = args.iter().map(String::as_bytes).collect::<Vec<_>>();
find_seps(&mut evec, options.sep); find_seps(&mut evec, options.sep);
shuf_bytes(&mut evec, options); shuf_bytes(&mut evec, options)?;
} }
Mode::InputRange((b, e)) => { Mode::InputRange((b, e)) => {
let rvec = (b..e).map(|x| format!("{}", x)).collect::<Vec<String>>(); let rvec = (b..e).map(|x| format!("{}", x)).collect::<Vec<String>>();
let mut rvec = rvec.iter().map(String::as_bytes).collect::<Vec<&[u8]>>(); let mut rvec = rvec.iter().map(String::as_bytes).collect::<Vec<&[u8]>>();
shuf_bytes(&mut rvec, options); shuf_bytes(&mut rvec, options)?;
} }
Mode::Default(filename) => { Mode::Default(filename) => {
let fdata = read_input_file(&filename); let fdata = read_input_file(&filename)?;
let mut fdata = vec![&fdata[..]]; let mut fdata = vec![&fdata[..]];
find_seps(&mut fdata, options.sep); find_seps(&mut fdata, options.sep);
shuf_bytes(&mut fdata, options); shuf_bytes(&mut fdata, options)?;
} }
} }
0 Ok(())
} }
pub fn uu_app() -> App<'static, 'static> { pub fn uu_app() -> App<'static, 'static> {
@ -180,22 +181,20 @@ pub fn uu_app() -> App<'static, 'static> {
.arg(Arg::with_name(options::FILE).takes_value(true)) .arg(Arg::with_name(options::FILE).takes_value(true))
} }
fn read_input_file(filename: &str) -> Vec<u8> { fn read_input_file(filename: &str) -> UResult<Vec<u8>> {
let mut file = BufReader::new(if filename == "-" { let mut file = BufReader::new(if filename == "-" {
Box::new(stdin()) as Box<dyn Read> Box::new(stdin()) as Box<dyn Read>
} else { } else {
match File::open(filename) { let file = File::open(filename)
Ok(f) => Box::new(f) as Box<dyn Read>, .map_err_context(|| format!("failed to open {}", filename.quote()))?;
Err(e) => crash!(1, "failed to open {}: {}", filename.quote(), e), Box::new(file) as Box<dyn Read>
}
}); });
let mut data = Vec::new(); let mut data = Vec::new();
if let Err(e) = file.read_to_end(&mut data) { file.read_to_end(&mut data)
crash!(1, "failed reading {}: {}", filename.quote(), e) .map_err_context(|| format!("failed reading {}", filename.quote()))?;
};
data Ok(data)
} }
fn find_seps(data: &mut Vec<&[u8]>, sep: u8) { fn find_seps(data: &mut Vec<&[u8]>, sep: u8) {
@ -231,22 +230,22 @@ fn find_seps(data: &mut Vec<&[u8]>, sep: u8) {
} }
} }
fn shuf_bytes(input: &mut Vec<&[u8]>, opts: Options) { fn shuf_bytes(input: &mut Vec<&[u8]>, opts: Options) -> UResult<()> {
let mut output = BufWriter::new(match opts.output { let mut output = BufWriter::new(match opts.output {
None => Box::new(stdout()) as Box<dyn Write>, None => Box::new(stdout()) as Box<dyn Write>,
Some(s) => match File::create(&s[..]) { Some(s) => {
Ok(f) => Box::new(f) as Box<dyn Write>, let file = File::create(&s[..])
Err(e) => crash!(1, "failed to open {} for writing: {}", s.quote(), e), .map_err_context(|| format!("failed to open {} for writing", s.quote()))?;
}, Box::new(file) as Box<dyn Write>
}
}); });
let mut rng = match opts.random_source { let mut rng = match opts.random_source {
Some(r) => WrappedRng::RngFile(rand::rngs::adapter::ReadRng::new( Some(r) => {
match File::open(&r[..]) { let file = File::open(&r[..])
Ok(f) => f, .map_err_context(|| format!("failed to open random source {}", r.quote()))?;
Err(e) => crash!(1, "failed to open random source {}: {}", r.quote(), e), WrappedRng::RngFile(rand::rngs::adapter::ReadRng::new(file))
}, }
)),
None => WrappedRng::RngDefault(rand::thread_rng()), None => WrappedRng::RngDefault(rand::thread_rng()),
}; };
@ -268,10 +267,10 @@ fn shuf_bytes(input: &mut Vec<&[u8]>, opts: Options) {
// write the randomly chosen value and the separator // write the randomly chosen value and the separator
output output
.write_all(input[r]) .write_all(input[r])
.unwrap_or_else(|e| crash!(1, "write failed: {}", e)); .map_err_context(|| "write failed".to_string())?;
output output
.write_all(&[opts.sep]) .write_all(&[opts.sep])
.unwrap_or_else(|e| crash!(1, "write failed: {}", e)); .map_err_context(|| "write failed".to_string())?;
// if we do not allow repeats, remove the chosen value from the input vector // if we do not allow repeats, remove the chosen value from the input vector
if !opts.repeat { if !opts.repeat {
@ -284,6 +283,7 @@ fn shuf_bytes(input: &mut Vec<&[u8]>, opts: Options) {
count -= 1; count -= 1;
} }
Ok(())
} }
fn parse_range(input_range: &str) -> Result<(usize, usize), String> { fn parse_range(input_range: &str) -> Result<(usize, usize), String> {