diff --git a/src/uu/basename/src/basename.rs b/src/uu/basename/src/basename.rs index f7f4a3d08..9f3ce3cc4 100644 --- a/src/uu/basename/src/basename.rs +++ b/src/uu/basename/src/basename.rs @@ -7,11 +7,10 @@ // spell-checker:ignore (ToDO) fullname -#[macro_use] -extern crate uucore; - use clap::{crate_version, App, Arg}; use std::path::{is_separator, PathBuf}; +use uucore::display::Quotable; +use uucore::error::{UResult, UUsageError}; use uucore::InvalidEncodingHandling; static SUMMARY: &str = "Print NAME with any leading directory components removed @@ -32,7 +31,8 @@ pub mod options { pub static ZERO: &str = "zero"; } -pub fn uumain(args: impl uucore::Args) -> i32 { +#[uucore_procs::gen_uumain] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { let args = args .collect_str(InvalidEncodingHandling::ConvertLossy) .accept_any(); @@ -44,12 +44,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { // too few arguments if !matches.is_present(options::NAME) { - crash!( - 1, - "{1}\nTry '{0} --help' for more information.", - uucore::execution_phrase(), - "missing operand" - ); + return Err(UUsageError::new(1, "missing operand".to_string())); } let opt_suffix = matches.is_present(options::SUFFIX); @@ -58,12 +53,18 @@ pub fn uumain(args: impl uucore::Args) -> i32 { let multiple_paths = opt_suffix || opt_multiple; // too many arguments if !multiple_paths && matches.occurrences_of(options::NAME) > 2 { - crash!( + return Err(UUsageError::new( 1, - "extra operand '{1}'\nTry '{0} --help' for more information.", - uucore::execution_phrase(), - matches.values_of(options::NAME).unwrap().nth(2).unwrap() - ); + format!( + "extra operand {}", + matches + .values_of(options::NAME) + .unwrap() + .nth(2) + .unwrap() + .quote() + ), + )); } let suffix = if opt_suffix { @@ -89,7 +90,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { print!("{}{}", basename(path, suffix), line_ending); } - 0 + Ok(()) } pub fn uu_app() -> App<'static, 'static> { diff --git a/src/uu/date/src/date.rs b/src/uu/date/src/date.rs index adcf77024..bd814353f 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -18,6 +18,9 @@ use std::fs::File; use std::io::{BufRead, BufReader}; use std::path::PathBuf; use uucore::display::Quotable; +#[cfg(not(any(target_os = "macos", target_os = "redox")))] +use uucore::error::FromIo; +use uucore::error::{UResult, USimpleError}; use uucore::show_error; #[cfg(windows)] use winapi::{ @@ -137,7 +140,8 @@ impl<'a> From<&'a str> for Rfc3339Format { } } -pub fn uumain(args: impl uucore::Args) -> i32 { +#[uucore_procs::gen_uumain] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { let syntax = format!( "{0} [OPTION]... [+FORMAT]... {0} [OPTION]... [MMDDhhmm[[CC]YY][.ss]]", @@ -147,8 +151,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 { let format = if let Some(form) = matches.value_of(OPT_FORMAT) { if !form.starts_with('+') { - show_error!("invalid date {}", form.quote()); - return 1; + return Err(USimpleError::new( + 1, + format!("invalid date {}", form.quote()), + )); } let form = form[1..].to_string(); Format::Custom(form) @@ -176,8 +182,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 { let set_to = match matches.value_of(OPT_SET).map(parse_date) { None => None, Some(Err((input, _err))) => { - show_error!("invalid date {}", input.quote()); - return 1; + return Err(USimpleError::new( + 1, + format!("invalid date {}", input.quote()), + )); } Some(Ok(date)) => Some(date), }; @@ -241,14 +249,12 @@ pub fn uumain(args: impl uucore::Args) -> i32 { let formatted = date.format(format_string).to_string().replace("%f", "%N"); println!("{}", formatted); } - Err((input, _err)) => { - show_error!("invalid date {}", input.quote()); - } + Err((input, _err)) => show_error!("invalid date {}", input.quote()), } } } - 0 + Ok(()) } pub fn uu_app() -> App<'static, 'static> { @@ -348,20 +354,24 @@ fn parse_date + Clone>( } #[cfg(not(any(unix, windows)))] -fn set_system_datetime(_date: DateTime) -> i32 { +fn set_system_datetime(_date: DateTime) -> UResult<()> { unimplemented!("setting date not implemented (unsupported target)"); } #[cfg(target_os = "macos")] -fn set_system_datetime(_date: DateTime) -> i32 { - show_error!("setting the date is not supported by macOS"); - 1 +fn set_system_datetime(_date: DateTime) -> UResult<()> { + Err(USimpleError::new( + 1, + "setting the date is not supported by macOS".to_string(), + )) } #[cfg(target_os = "redox")] -fn set_system_datetime(_date: DateTime) -> i32 { - show_error!("setting the date is not supported by Redox"); - 1 +fn set_system_datetime(_date: DateTime) -> UResult<()> { + Err(USimpleError::new( + 1, + "setting the date is not supported by Redox".to_string(), + )) } #[cfg(all(unix, not(target_os = "macos"), not(target_os = "redox")))] @@ -370,7 +380,7 @@ fn set_system_datetime(_date: DateTime) -> i32 { /// https://doc.rust-lang.org/libc/i686-unknown-linux-gnu/libc/fn.clock_settime.html /// https://linux.die.net/man/3/clock_settime /// https://www.gnu.org/software/libc/manual/html_node/Time-Types.html -fn set_system_datetime(date: DateTime) -> i32 { +fn set_system_datetime(date: DateTime) -> UResult<()> { let timespec = timespec { tv_sec: date.timestamp() as _, tv_nsec: date.timestamp_subsec_nanos() as _, @@ -379,11 +389,9 @@ fn set_system_datetime(date: DateTime) -> i32 { let result = unsafe { clock_settime(CLOCK_REALTIME, ×pec) }; if result != 0 { - let error = std::io::Error::last_os_error(); - show_error!("cannot set date: {}", error); - error.raw_os_error().unwrap() + Err(std::io::Error::last_os_error().map_err_context(|| "cannot set date".to_string())) } else { - 0 + Ok(()) } } @@ -392,7 +400,7 @@ fn set_system_datetime(date: DateTime) -> i32 { /// See here for more: /// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-setsystemtime /// https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-systemtime -fn set_system_datetime(date: DateTime) -> i32 { +fn set_system_datetime(date: DateTime) -> UResult<()> { let system_time = SYSTEMTIME { wYear: date.year() as WORD, wMonth: date.month() as WORD, @@ -409,10 +417,8 @@ fn set_system_datetime(date: DateTime) -> i32 { let result = unsafe { SetSystemTime(&system_time) }; if result == 0 { - let error = std::io::Error::last_os_error(); - show_error!("cannot set date: {}", error); - error.raw_os_error().unwrap() + Err(std::io::Error::last_os_error().map_err_context(|| "cannot set date".to_string())) } else { - 0 + Ok(()) } } diff --git a/src/uu/fold/src/fold.rs b/src/uu/fold/src/fold.rs index c4cc16469..30a1012af 100644 --- a/src/uu/fold/src/fold.rs +++ b/src/uu/fold/src/fold.rs @@ -7,13 +7,12 @@ // spell-checker:ignore (ToDOs) ncount routput -#[macro_use] -extern crate uucore; - use clap::{crate_version, App, Arg}; use std::fs::File; use std::io::{stdin, BufRead, BufReader, Read}; use std::path::Path; +use uucore::display::Quotable; +use uucore::error::{FromIo, UResult, USimpleError}; use uucore::InvalidEncodingHandling; const TAB_WIDTH: usize = 8; @@ -30,7 +29,8 @@ mod options { pub const 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 .collect_str(InvalidEncodingHandling::ConvertLossy) .accept_any(); @@ -46,10 +46,12 @@ pub fn uumain(args: impl uucore::Args) -> i32 { }; let width = match poss_width { - Some(inp_width) => match inp_width.parse::() { - Ok(width) => width, - Err(e) => crash!(1, "illegal width value (\"{}\"): {}", inp_width, e), - }, + Some(inp_width) => inp_width.parse::().map_err(|e| { + USimpleError::new( + 1, + format!("illegal width value ({}): {}", inp_width.quote(), e), + ) + })?, None => 80, }; @@ -58,9 +60,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { None => vec!["-".to_owned()], }; - fold(files, bytes, spaces, width); - - 0 + fold(files, bytes, spaces, width) } pub fn uu_app() -> App<'static, 'static> { @@ -110,7 +110,7 @@ fn handle_obsolete(args: &[String]) -> (Vec, Option) { (args.to_vec(), None) } -fn fold(filenames: Vec, bytes: bool, spaces: bool, width: usize) { +fn fold(filenames: Vec, bytes: bool, spaces: bool, width: usize) -> UResult<()> { for filename in &filenames { let filename: &str = filename; let mut stdin_buf; @@ -119,16 +119,17 @@ fn fold(filenames: Vec, bytes: bool, spaces: bool, width: usize) { stdin_buf = stdin(); &mut stdin_buf as &mut dyn Read } else { - file_buf = crash_if_err!(1, File::open(Path::new(filename))); + file_buf = File::open(Path::new(filename)).map_err_context(|| filename.to_string())?; &mut file_buf as &mut dyn Read }); if bytes { - fold_file_bytewise(buffer, spaces, width); + fold_file_bytewise(buffer, spaces, width)?; } else { - fold_file(buffer, spaces, width); + fold_file(buffer, spaces, width)?; } } + Ok(()) } /// Fold `file` to fit `width` (number of columns), counting all characters as @@ -139,11 +140,15 @@ fn fold(filenames: Vec, bytes: bool, spaces: bool, width: usize) { /// to all other characters in the stream. /// /// If `spaces` is `true`, attempt to break lines at whitespace boundaries. -fn fold_file_bytewise(mut file: BufReader, spaces: bool, width: usize) { +fn fold_file_bytewise(mut file: BufReader, spaces: bool, width: usize) -> UResult<()> { let mut line = String::new(); loop { - if let Ok(0) = file.read_line(&mut line) { + if file + .read_line(&mut line) + .map_err_context(|| "failed to read line".to_string())? + == 0 + { break; } @@ -190,6 +195,8 @@ fn fold_file_bytewise(mut file: BufReader, spaces: bool, width: usiz line.truncate(0); } + + Ok(()) } /// Fold `file` to fit `width` (number of columns). @@ -200,7 +207,7 @@ fn fold_file_bytewise(mut file: BufReader, spaces: bool, width: usiz /// /// If `spaces` is `true`, attempt to break lines at whitespace boundaries. #[allow(unused_assignments)] -fn fold_file(mut file: BufReader, spaces: bool, width: usize) { +fn fold_file(mut file: BufReader, spaces: bool, width: usize) -> UResult<()> { let mut line = String::new(); let mut output = String::new(); let mut col_count = 0; @@ -230,7 +237,11 @@ fn fold_file(mut file: BufReader, spaces: bool, width: usize) { } loop { - if let Ok(0) = file.read_line(&mut line) { + if file + .read_line(&mut line) + .map_err_context(|| "failed to read line".to_string())? + == 0 + { break; } @@ -281,4 +292,6 @@ fn fold_file(mut file: BufReader, spaces: bool, width: usize) { line.truncate(0); } + + Ok(()) } diff --git a/src/uu/nl/src/nl.rs b/src/uu/nl/src/nl.rs index 600ebace0..b004d2b74 100644 --- a/src/uu/nl/src/nl.rs +++ b/src/uu/nl/src/nl.rs @@ -8,14 +8,12 @@ // spell-checker:ignore (ToDO) corasick memchr -#[macro_use] -extern crate uucore; - use clap::{crate_version, App, Arg}; use std::fs::File; use std::io::{stdin, BufRead, BufReader, Read}; use std::iter::repeat; use std::path::Path; +use uucore::error::{FromIo, UResult, USimpleError}; use uucore::InvalidEncodingHandling; mod helper; @@ -83,7 +81,8 @@ pub mod options { pub const NUMBER_WIDTH: &str = "number-width"; } -pub fn uumain(args: impl uucore::Args) -> i32 { +#[uucore_procs::gen_uumain] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { let args = args .collect_str(InvalidEncodingHandling::ConvertLossy) .accept_any(); @@ -109,11 +108,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 { // program if some options could not successfully be parsed. let parse_errors = helper::parse_options(&mut settings, &matches); if !parse_errors.is_empty() { - show_error!("Invalid arguments supplied."); - for message in &parse_errors { - println!("{}", message); - } - return 1; + return Err(USimpleError::new( + 1, + format!("Invalid arguments supplied.\n{}", parse_errors.join("\n")), + )); } let mut read_stdin = false; @@ -130,16 +128,16 @@ pub fn uumain(args: impl uucore::Args) -> i32 { continue; } let path = Path::new(file); - let reader = File::open(path).unwrap(); + let reader = File::open(path).map_err_context(|| file.to_string())?; let mut buffer = BufReader::new(reader); - nl(&mut buffer, &settings); + nl(&mut buffer, &settings)?; } if read_stdin { let mut buffer = BufReader::new(stdin()); - nl(&mut buffer, &settings); + nl(&mut buffer, &settings)?; } - 0 + Ok(()) } pub fn uu_app() -> App<'static, 'static> { @@ -227,7 +225,7 @@ pub fn uu_app() -> App<'static, 'static> { } // nl implements the main functionality for an individual buffer. -fn nl(reader: &mut BufReader, settings: &Settings) { +fn nl(reader: &mut BufReader, settings: &Settings) -> UResult<()> { let regexp: regex::Regex = regex::Regex::new(r".?").unwrap(); let mut line_no = settings.starting_line_number; // The current line number's width as a string. Using to_string is inefficient @@ -248,7 +246,8 @@ fn nl(reader: &mut BufReader, settings: &Settings) { _ => ®exp, }; let mut line_filter: fn(&str, ®ex::Regex) -> bool = pass_regex; - for mut l in reader.lines().map(|r| r.unwrap()) { + for l in reader.lines() { + let mut l = l.map_err_context(|| "could not read line".to_string())?; // Sanitize the string. We want to print the newline ourselves. if l.ends_with('\n') { l.pop(); @@ -372,6 +371,7 @@ fn nl(reader: &mut BufReader, settings: &Settings) { line_no_width += 1; } } + Ok(()) } fn pass_regex(line: &str, re: ®ex::Regex) -> bool { diff --git a/src/uu/nproc/src/nproc.rs b/src/uu/nproc/src/nproc.rs index 16b8d8c3a..4ab1378b0 100644 --- a/src/uu/nproc/src/nproc.rs +++ b/src/uu/nproc/src/nproc.rs @@ -7,11 +7,10 @@ // spell-checker:ignore (ToDO) NPROCESSORS nprocs numstr threadstr sysconf -#[macro_use] -extern crate uucore; - use clap::{crate_version, App, Arg}; use std::env; +use uucore::display::Quotable; +use uucore::error::{UResult, USimpleError}; #[cfg(target_os = "linux")] pub const _SC_NPROCESSORS_CONF: libc::c_int = 83; @@ -31,7 +30,8 @@ fn usage() -> String { format!("{0} [OPTIONS]...", uucore::execution_phrase()) } -pub fn uumain(args: impl uucore::Args) -> i32 { +#[uucore_procs::gen_uumain] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { let usage = usage(); let matches = uu_app().usage(&usage[..]).get_matches_from(args); @@ -39,8 +39,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 { Some(numstr) => match numstr.parse() { Ok(num) => num, Err(e) => { - show_error!("\"{}\" is not a valid number: {}", numstr, e); - return 1; + return Err(USimpleError::new( + 1, + format!("{} is not a valid number: {}", numstr.quote(), e), + )); } }, None => 0, @@ -66,7 +68,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { cores -= ignore; } println!("{}", cores); - 0 + Ok(()) } pub fn uu_app() -> App<'static, 'static> { diff --git a/src/uu/shuf/src/shuf.rs b/src/uu/shuf/src/shuf.rs index 9a899d746..ce0af5ec2 100644 --- a/src/uu/shuf/src/shuf.rs +++ b/src/uu/shuf/src/shuf.rs @@ -7,14 +7,12 @@ // spell-checker:ignore (ToDO) cmdline evec seps rvec fdata -#[macro_use] -extern crate uucore; - use clap::{crate_version, App, Arg}; use rand::Rng; use std::fs::File; use std::io::{stdin, stdout, BufReader, BufWriter, Read, Write}; use uucore::display::Quotable; +use uucore::error::{FromIo, UResult, USimpleError}; use uucore::InvalidEncodingHandling; enum Mode { @@ -52,7 +50,8 @@ mod options { 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 .collect_str(InvalidEncodingHandling::ConvertLossy) .accept_any(); @@ -65,7 +64,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { match parse_range(range) { Ok(m) => Mode::InputRange(m), Err(msg) => { - crash!(1, "{}", msg); + return Err(USimpleError::new(1, msg)); } } } else { @@ -77,8 +76,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 { Some(count) => match count.parse::() { Ok(val) => val, Err(_) => { - show_error!("invalid line count: {}", count.quote()); - return 1; + return Err(USimpleError::new( + 1, + format!("invalid line count: {}", count.quote()), + )); } }, None => std::usize::MAX, @@ -97,22 +98,22 @@ pub fn uumain(args: impl uucore::Args) -> i32 { Mode::Echo(args) => { let mut evec = args.iter().map(String::as_bytes).collect::>(); find_seps(&mut evec, options.sep); - shuf_bytes(&mut evec, options); + shuf_bytes(&mut evec, options)?; } Mode::InputRange((b, e)) => { let rvec = (b..e).map(|x| format!("{}", x)).collect::>(); let mut rvec = rvec.iter().map(String::as_bytes).collect::>(); - shuf_bytes(&mut rvec, options); + shuf_bytes(&mut rvec, options)?; } Mode::Default(filename) => { - let fdata = read_input_file(&filename); + let fdata = read_input_file(&filename)?; let mut fdata = vec![&fdata[..]]; 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> { @@ -180,22 +181,20 @@ pub fn uu_app() -> App<'static, 'static> { .arg(Arg::with_name(options::FILE).takes_value(true)) } -fn read_input_file(filename: &str) -> Vec { +fn read_input_file(filename: &str) -> UResult> { let mut file = BufReader::new(if filename == "-" { Box::new(stdin()) as Box } else { - match File::open(filename) { - Ok(f) => Box::new(f) as Box, - Err(e) => crash!(1, "failed to open {}: {}", filename.quote(), e), - } + let file = File::open(filename) + .map_err_context(|| format!("failed to open {}", filename.quote()))?; + Box::new(file) as Box }); let mut data = Vec::new(); - if let Err(e) = file.read_to_end(&mut data) { - crash!(1, "failed reading {}: {}", filename.quote(), e) - }; + file.read_to_end(&mut data) + .map_err_context(|| format!("failed reading {}", filename.quote()))?; - data + Ok(data) } 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 { None => Box::new(stdout()) as Box, - Some(s) => match File::create(&s[..]) { - Ok(f) => Box::new(f) as Box, - Err(e) => crash!(1, "failed to open {} for writing: {}", s.quote(), e), - }, + Some(s) => { + let file = File::create(&s[..]) + .map_err_context(|| format!("failed to open {} for writing", s.quote()))?; + Box::new(file) as Box + } }); let mut rng = match opts.random_source { - Some(r) => WrappedRng::RngFile(rand::rngs::adapter::ReadRng::new( - match File::open(&r[..]) { - Ok(f) => f, - Err(e) => crash!(1, "failed to open random source {}: {}", r.quote(), e), - }, - )), + Some(r) => { + let file = File::open(&r[..]) + .map_err_context(|| format!("failed to open random source {}", r.quote()))?; + WrappedRng::RngFile(rand::rngs::adapter::ReadRng::new(file)) + } 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 output .write_all(input[r]) - .unwrap_or_else(|e| crash!(1, "write failed: {}", e)); + .map_err_context(|| "write failed".to_string())?; output .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 !opts.repeat { @@ -284,6 +283,7 @@ fn shuf_bytes(input: &mut Vec<&[u8]>, opts: Options) { count -= 1; } + Ok(()) } fn parse_range(input_range: &str) -> Result<(usize, usize), String> { diff --git a/src/uu/uname/src/uname.rs b/src/uu/uname/src/uname.rs index 2c396081e..a4801dfc1 100644 --- a/src/uu/uname/src/uname.rs +++ b/src/uu/uname/src/uname.rs @@ -10,11 +10,9 @@ // spell-checker:ignore (ToDO) nodename kernelname kernelrelease kernelversion sysname hwplatform mnrsv -#[macro_use] -extern crate uucore; - use clap::{crate_version, App, Arg}; use platform_info::*; +use uucore::error::{FromIo, UResult}; const ABOUT: &str = "Print certain system information. With no OPTION, same as -s."; @@ -49,11 +47,13 @@ const HOST_OS: &str = "Fuchsia"; #[cfg(target_os = "redox")] const HOST_OS: &str = "Redox"; -pub fn uumain(args: impl uucore::Args) -> i32 { +#[uucore_procs::gen_uumain] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { let usage = format!("{} [OPTION]...", uucore::execution_phrase()); let matches = uu_app().usage(&usage[..]).get_matches_from(args); - let uname = crash_if_err!(1, PlatformInfo::new()); + let uname = + PlatformInfo::new().map_err_context(|| "failed to create PlatformInfo".to_string())?; let mut output = String::new(); let all = matches.is_present(options::ALL); @@ -115,7 +115,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { } println!("{}", output.trim_end()); - 0 + Ok(()) } pub fn uu_app() -> App<'static, 'static> {