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

seq: return UResult from uumain() function (#2784)

This commit is contained in:
jfinkels 2021-12-29 09:20:17 -05:00 committed by GitHub
parent 3f18b98c9d
commit 8a55205521
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 119 additions and 65 deletions

70
src/uu/seq/src/error.rs Normal file
View file

@ -0,0 +1,70 @@
// * This file is part of the uutils coreutils package.
// *
// * For the full copyright and license information, please view the LICENSE
// * file that was distributed with this source code.
// spell-checker:ignore numberparse argtype
//! Errors returned by seq.
use std::error::Error;
use std::fmt::Display;
use uucore::display::Quotable;
use uucore::error::UError;
use crate::numberparse::ParseNumberError;
#[derive(Debug)]
pub enum SeqError {
/// An error parsing the input arguments.
///
/// The parameters are the [`String`] argument as read from the
/// command line and the underlying parsing error itself.
ParseError(String, ParseNumberError),
/// The increment argument was zero, which is not allowed.
///
/// The parameter is the increment argument as a [`String`] as read
/// from the command line.
ZeroIncrement(String),
}
impl SeqError {
/// The [`String`] argument as read from the command-line.
fn arg(&self) -> &str {
match self {
SeqError::ParseError(s, _) => s,
SeqError::ZeroIncrement(s) => s,
}
}
/// The type of argument that is causing the error.
fn argtype(&self) -> &str {
match self {
SeqError::ParseError(_, e) => match e {
ParseNumberError::Float => "floating point",
ParseNumberError::Nan => "'not-a-number'",
ParseNumberError::Hex => "hexadecimal",
},
SeqError::ZeroIncrement(_) => "Zero increment",
}
}
}
impl UError for SeqError {
/// Always return 1.
fn code(&self) -> i32 {
1
}
}
impl Error for SeqError {}
impl Display for SeqError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"invalid {} argument: {}\nTry '{} --help' for more information.",
self.argtype(),
self.arg().quote(),
uucore::execution_phrase(),
)
}
}

View file

@ -1,26 +1,27 @@
// TODO: Make -w flag work with decimals // * This file is part of the uutils coreutils package.
// *
// * For the full copyright and license information, please view the LICENSE
// * file that was distributed with this source code.
// TODO: Support -f flag // TODO: Support -f flag
// spell-checker:ignore (ToDO) istr chiter argptr ilen extendedbigdecimal extendedbigint numberparse // spell-checker:ignore (ToDO) istr chiter argptr ilen extendedbigdecimal extendedbigint numberparse
use std::io::{stdout, ErrorKind, Write};
#[macro_use]
extern crate uucore;
use clap::{crate_version, App, AppSettings, Arg}; use clap::{crate_version, App, AppSettings, Arg};
use num_traits::Zero; use num_traits::Zero;
use std::io::{stdout, ErrorKind, Write};
use uucore::error::FromIo;
use uucore::error::UResult;
mod error;
mod extendedbigdecimal; mod extendedbigdecimal;
mod extendedbigint; mod extendedbigint;
mod number; mod number;
mod numberparse; mod numberparse;
use crate::error::SeqError;
use crate::extendedbigdecimal::ExtendedBigDecimal; use crate::extendedbigdecimal::ExtendedBigDecimal;
use crate::extendedbigint::ExtendedBigInt; use crate::extendedbigint::ExtendedBigInt;
use crate::number::Number; use crate::number::Number;
use crate::number::PreciseNumber; use crate::number::PreciseNumber;
use crate::numberparse::ParseNumberError;
use uucore::display::Quotable;
static ABOUT: &str = "Display numbers from FIRST to LAST, in steps of INCREMENT."; static ABOUT: &str = "Display numbers from FIRST to LAST, in steps of INCREMENT.";
static OPT_SEPARATOR: &str = "separator"; static OPT_SEPARATOR: &str = "separator";
@ -54,47 +55,8 @@ type RangeInt = (ExtendedBigInt, ExtendedBigInt, ExtendedBigInt);
/// The elements are (first, increment, last). /// The elements are (first, increment, last).
type RangeFloat = (ExtendedBigDecimal, ExtendedBigDecimal, ExtendedBigDecimal); type RangeFloat = (ExtendedBigDecimal, ExtendedBigDecimal, ExtendedBigDecimal);
/// Terminate the process with error code 1. #[uucore_procs::gen_uumain]
/// pub fn uumain(args: impl uucore::Args) -> UResult<()> {
/// Before terminating the process, this function prints an error
/// message that depends on `arg` and `e`.
///
/// Although the signature of this function states that it returns a
/// [`PreciseNumber`], it never reaches the return statement. It is just
/// there to make it easier to use this function when unwrapping the
/// result of calling [`str::parse`] when attempting to parse a
/// [`PreciseNumber`].
///
/// # Examples
///
/// ```rust,ignore
/// let s = "1.2e-3";
/// s.parse::<PreciseNumber>.unwrap_or_else(|e| exit_with_error(s, e))
/// ```
fn exit_with_error(arg: &str, e: ParseNumberError) -> ! {
match e {
ParseNumberError::Float => crash!(
1,
"invalid floating point argument: {}\nTry '{} --help' for more information.",
arg.quote(),
uucore::execution_phrase()
),
ParseNumberError::Nan => crash!(
1,
"invalid 'not-a-number' argument: {}\nTry '{} --help' for more information.",
arg.quote(),
uucore::execution_phrase()
),
ParseNumberError::Hex => crash!(
1,
"invalid hexadecimal argument: {}\nTry '{} --help' for more information.",
arg.quote(),
uucore::execution_phrase()
),
}
}
pub fn uumain(args: impl uucore::Args) -> i32 {
let usage = usage(); let usage = usage();
let matches = uu_app().usage(&usage[..]).get_matches_from(args); let matches = uu_app().usage(&usage[..]).get_matches_from(args);
@ -107,28 +69,33 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
}; };
let first = if numbers.len() > 1 { let first = if numbers.len() > 1 {
let slice = numbers[0]; match numbers[0].parse() {
slice.parse().unwrap_or_else(|e| exit_with_error(slice, e)) Ok(num) => num,
Err(e) => return Err(SeqError::ParseError(numbers[0].to_string(), e).into()),
}
} else { } else {
PreciseNumber::one() PreciseNumber::one()
}; };
let increment = if numbers.len() > 2 { let increment = if numbers.len() > 2 {
let slice = numbers[1]; match numbers[1].parse() {
slice.parse().unwrap_or_else(|e| exit_with_error(slice, e)) Ok(num) => num,
Err(e) => return Err(SeqError::ParseError(numbers[1].to_string(), e).into()),
}
} else { } else {
PreciseNumber::one() PreciseNumber::one()
}; };
if increment.is_zero() { if increment.is_zero() {
show_error!( return Err(SeqError::ZeroIncrement(numbers[1].to_string()).into());
"invalid Zero increment value: '{}'\nTry '{} --help' for more information.",
numbers[1],
uucore::execution_phrase()
);
return 1;
} }
let last: PreciseNumber = { let last: PreciseNumber = {
let slice = numbers[numbers.len() - 1]; // We are guaranteed that `numbers.len()` is greater than zero
slice.parse().unwrap_or_else(|e| exit_with_error(slice, e)) // and at most three because of the argument specification in
// `uu_app()`.
let n: usize = numbers.len();
match numbers[n - 1].parse() {
Ok(num) => num,
Err(e) => return Err(SeqError::ParseError(numbers[n - 1].to_string(), e).into()),
}
}; };
let padding = first let padding = first
@ -164,9 +131,9 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
), ),
}; };
match result { match result {
Ok(_) => 0, Ok(_) => Ok(()),
Err(err) if err.kind() == ErrorKind::BrokenPipe => 0, Err(err) if err.kind() == ErrorKind::BrokenPipe => Ok(()),
Err(_) => 1, Err(e) => Err(e.map_err_context(|| "write error".into())),
} }
} }

View file

@ -1,3 +1,4 @@
// spell-checker:ignore lmnop xlmnop
use crate::common::util::*; use crate::common::util::*;
use std::io::Read; use std::io::Read;
@ -676,3 +677,19 @@ fn test_rounding_end() {
.stdout_is("1\n") .stdout_is("1\n")
.no_stderr(); .no_stderr();
} }
#[test]
fn test_parse_error_float() {
new_ucmd!()
.arg("lmnop")
.fails()
.usage_error("invalid floating point argument: 'lmnop'");
}
#[test]
fn test_parse_error_hex() {
new_ucmd!()
.arg("0xlmnop")
.fails()
.usage_error("invalid hexadecimal argument: '0xlmnop'");
}