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

seq: adapt output to GNU seq

This commit is contained in:
Michael Debertol 2021-06-01 20:35:18 +02:00
parent 9b29ac98a5
commit 5329d77cc2
2 changed files with 38 additions and 27 deletions

View file

@ -13,6 +13,7 @@ use num_traits::Zero;
use num_traits::{Num, ToPrimitive}; use num_traits::{Num, ToPrimitive};
use std::cmp; use std::cmp;
use std::io::{stdout, Write}; use std::io::{stdout, Write};
use std::str::FromStr;
static VERSION: &str = env!("CARGO_PKG_VERSION"); static VERSION: &str = env!("CARGO_PKG_VERSION");
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.";
@ -43,18 +44,6 @@ enum Number {
} }
impl Number { impl Number {
fn new(mut s: &str) -> Self {
if s.starts_with('+') {
s = &s[1..];
}
match s.parse::<BigInt>() {
Ok(n) => Number::BigInt(n),
// The argument validator made sure this is a valid float.
Err(_) => Number::F64(s.parse::<f64>().unwrap()),
}
}
fn is_zero(&self) -> bool { fn is_zero(&self) -> bool {
match self { match self {
Number::BigInt(n) => n.is_zero(), Number::BigInt(n) => n.is_zero(),
@ -71,6 +60,32 @@ impl Number {
} }
} }
impl FromStr for Number {
type Err = String;
fn from_str(mut s: &str) -> Result<Self, Self::Err> {
if s.starts_with('+') {
s = &s[1..];
}
match s.parse::<BigInt>() {
Ok(n) => Ok(Number::BigInt(n)),
Err(_) => match s.parse::<f64>() {
Ok(value) if value.is_nan() => Err(format!(
"invalid 'not-a-number' argument: '{}'\nTry '{} --help' for more information.",
s,
executable!(),
)),
Ok(value) => Ok(Number::F64(value)),
Err(_) => Err(format!(
"invalid floating point argument: '{}'\nTry '{} --help' for more information.",
s,
executable!(),
)),
},
}
}
}
pub fn uumain(args: impl uucore::Args) -> i32 { pub fn uumain(args: impl uucore::Args) -> i32 {
let usage = get_usage(); let usage = get_usage();
let matches = App::new(executable!()) let matches = App::new(executable!())
@ -106,15 +121,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.takes_value(true) .takes_value(true)
.allow_hyphen_values(true) .allow_hyphen_values(true)
.max_values(3) .max_values(3)
.required(true) .required(true),
.validator(|value| {
match value.parse::<f64>() {
Ok(value) if value.is_nan() => Err("can not be NaN".to_string()),
Ok(_) => Ok(()),
Err(e) => Err(e.to_string()),
}
.map_err(|e| format!("invalid floating point argument `{}`: {}", value, e))
}),
) )
.get_matches_from(args); .get_matches_from(args);
@ -134,7 +141,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let dec = slice.find('.').unwrap_or(len); let dec = slice.find('.').unwrap_or(len);
largest_dec = len - dec; largest_dec = len - dec;
padding = dec; padding = dec;
Number::new(slice) return_if_err!(1, slice.parse())
} else { } else {
Number::BigInt(BigInt::one()) Number::BigInt(BigInt::one())
}; };
@ -144,18 +151,22 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let dec = slice.find('.').unwrap_or(len); let dec = slice.find('.').unwrap_or(len);
largest_dec = cmp::max(largest_dec, len - dec); largest_dec = cmp::max(largest_dec, len - dec);
padding = cmp::max(padding, dec); padding = cmp::max(padding, dec);
Number::new(slice) return_if_err!(1, slice.parse())
} else { } else {
Number::BigInt(BigInt::one()) Number::BigInt(BigInt::one())
}; };
if increment.is_zero() { if increment.is_zero() {
show_error!("increment value: '{}'", numbers[1]); show_error!(
"invalid Zero increment value: '{}'\nTry '{} --help' for more information.",
numbers[1],
executable!()
);
return 1; return 1;
} }
let last = { let last = {
let slice = numbers[numbers.len() - 1]; let slice = numbers[numbers.len() - 1];
padding = cmp::max(padding, slice.find('.').unwrap_or_else(|| slice.len())); padding = cmp::max(padding, slice.find('.').unwrap_or_else(|| slice.len()));
Number::new(slice) return_if_err!(1, slice.parse())
}; };
if largest_dec > 0 { if largest_dec > 0 {
largest_dec -= 1; largest_dec -= 1;

View file

@ -5,7 +5,7 @@ fn test_rejects_nan() {
new_ucmd!() new_ucmd!()
.args(&["NaN"]) .args(&["NaN"])
.fails() .fails()
.stderr_only("error: Invalid value for '<numbers>...': invalid floating point argument `NaN`: can not be NaN"); .stderr_only("seq: invalid 'not-a-number' argument: 'NaN'\nTry 'seq --help' for more information.");
} }
#[test] #[test]
@ -13,7 +13,7 @@ fn test_rejects_non_floats() {
new_ucmd!() new_ucmd!()
.args(&["foo"]) .args(&["foo"])
.fails() .fails()
.stderr_only("error: Invalid value for '<numbers>...': invalid floating point argument `foo`: invalid float literal"); .stderr_only("seq: invalid floating point argument: 'foo'\nTry 'seq --help' for more information.");
} }
// ---- Tests for the big integer based path ---- // ---- Tests for the big integer based path ----