mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
seq: print negative zero at start of integer seq.
This commit is contained in:
parent
1df9a1691c
commit
2c66d9e0a7
2 changed files with 59 additions and 2 deletions
|
@ -38,6 +38,8 @@ struct SeqOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Number {
|
enum Number {
|
||||||
|
/// Negative zero, as if it were an integer.
|
||||||
|
MinusZero,
|
||||||
BigInt(BigInt),
|
BigInt(BigInt),
|
||||||
F64(f64),
|
F64(f64),
|
||||||
}
|
}
|
||||||
|
@ -45,6 +47,7 @@ enum Number {
|
||||||
impl Number {
|
impl Number {
|
||||||
fn is_zero(&self) -> bool {
|
fn is_zero(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
|
Number::MinusZero => true,
|
||||||
Number::BigInt(n) => n.is_zero(),
|
Number::BigInt(n) => n.is_zero(),
|
||||||
Number::F64(n) => n.is_zero(),
|
Number::F64(n) => n.is_zero(),
|
||||||
}
|
}
|
||||||
|
@ -52,6 +55,7 @@ impl Number {
|
||||||
|
|
||||||
fn into_f64(self) -> f64 {
|
fn into_f64(self) -> f64 {
|
||||||
match self {
|
match self {
|
||||||
|
Number::MinusZero => -0.,
|
||||||
// BigInt::to_f64() can not return None.
|
// BigInt::to_f64() can not return None.
|
||||||
Number::BigInt(n) => n.to_f64().unwrap(),
|
Number::BigInt(n) => n.to_f64().unwrap(),
|
||||||
Number::F64(n) => n,
|
Number::F64(n) => n,
|
||||||
|
@ -67,7 +71,16 @@ impl FromStr for Number {
|
||||||
}
|
}
|
||||||
|
|
||||||
match s.parse::<BigInt>() {
|
match s.parse::<BigInt>() {
|
||||||
Ok(n) => Ok(Number::BigInt(n)),
|
Ok(n) => {
|
||||||
|
// If `s` is '-0', then `parse()` returns
|
||||||
|
// `BigInt::zero()`, but we need to return
|
||||||
|
// `Number::MinusZero` instead.
|
||||||
|
if n == BigInt::zero() && s.starts_with('-') {
|
||||||
|
Ok(Number::MinusZero)
|
||||||
|
} else {
|
||||||
|
Ok(Number::BigInt(n))
|
||||||
|
}
|
||||||
|
}
|
||||||
Err(_) => match s.parse::<f64>() {
|
Err(_) => match s.parse::<f64>() {
|
||||||
Ok(value) if value.is_nan() => Err(format!(
|
Ok(value) if value.is_nan() => Err(format!(
|
||||||
"invalid 'not-a-number' argument: '{}'\nTry '{} --help' for more information.",
|
"invalid 'not-a-number' argument: '{}'\nTry '{} --help' for more information.",
|
||||||
|
@ -147,6 +160,14 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
match (first, last, increment) {
|
match (first, last, increment) {
|
||||||
|
(Number::MinusZero, Number::BigInt(last), Number::BigInt(increment)) => print_seq_integers(
|
||||||
|
(BigInt::zero(), increment, last),
|
||||||
|
options.separator,
|
||||||
|
options.terminator,
|
||||||
|
options.widths,
|
||||||
|
padding,
|
||||||
|
true,
|
||||||
|
),
|
||||||
(Number::BigInt(first), Number::BigInt(last), Number::BigInt(increment)) => {
|
(Number::BigInt(first), Number::BigInt(last), Number::BigInt(increment)) => {
|
||||||
print_seq_integers(
|
print_seq_integers(
|
||||||
(first, increment, last),
|
(first, increment, last),
|
||||||
|
@ -154,6 +175,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
options.terminator,
|
options.terminator,
|
||||||
options.widths,
|
options.widths,
|
||||||
padding,
|
padding,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
(first, last, increment) => print_seq(
|
(first, last, increment) => print_seq(
|
||||||
|
@ -247,13 +269,27 @@ fn print_seq(
|
||||||
crash_if_err!(1, stdout().flush());
|
crash_if_err!(1, stdout().flush());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// BigInt based code path
|
/// Print an integer sequence.
|
||||||
|
///
|
||||||
|
/// This function prints a sequence of integers defined by `range`,
|
||||||
|
/// which defines the first integer, last integer, and increment of the
|
||||||
|
/// range. The `separator` is inserted between each integer and
|
||||||
|
/// `terminator` is inserted at the end.
|
||||||
|
///
|
||||||
|
/// The `pad` parameter indicates whether to pad numbers to the width
|
||||||
|
/// given in `padding`.
|
||||||
|
///
|
||||||
|
/// If `is_first_minus_zero` is `true`, then the `first` parameter is
|
||||||
|
/// printed as if it were negative zero, even though no such number
|
||||||
|
/// exists as an integer (negative zero only exists for floating point
|
||||||
|
/// numbers). Only set this to `true` if `first` is actually zero.
|
||||||
fn print_seq_integers(
|
fn print_seq_integers(
|
||||||
range: RangeInt,
|
range: RangeInt,
|
||||||
separator: String,
|
separator: String,
|
||||||
terminator: String,
|
terminator: String,
|
||||||
pad: bool,
|
pad: bool,
|
||||||
padding: usize,
|
padding: usize,
|
||||||
|
is_first_minus_zero: bool,
|
||||||
) {
|
) {
|
||||||
let (first, increment, last) = range;
|
let (first, increment, last) = range;
|
||||||
let mut value = first;
|
let mut value = first;
|
||||||
|
@ -262,6 +298,9 @@ fn print_seq_integers(
|
||||||
if !is_first_iteration {
|
if !is_first_iteration {
|
||||||
print!("{}", separator);
|
print!("{}", separator);
|
||||||
}
|
}
|
||||||
|
if is_first_iteration && is_first_minus_zero {
|
||||||
|
print!("-");
|
||||||
|
}
|
||||||
is_first_iteration = false;
|
is_first_iteration = false;
|
||||||
if pad {
|
if pad {
|
||||||
print!("{number:>0width$}", number = value, width = padding);
|
print!("{number:>0width$}", number = value, width = padding);
|
||||||
|
|
|
@ -140,3 +140,21 @@ fn test_seq_wrong_arg_floats() {
|
||||||
fn test_zero_step_floats() {
|
fn test_zero_step_floats() {
|
||||||
new_ucmd!().args(&["10.0", "0", "32"]).fails();
|
new_ucmd!().args(&["10.0", "0", "32"]).fails();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_preserve_negative_zero_start() {
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["-0", "1"])
|
||||||
|
.succeeds()
|
||||||
|
.stdout_is("-0\n1\n")
|
||||||
|
.no_stderr();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_drop_negative_zero_end() {
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["1", "-1", "-0"])
|
||||||
|
.succeeds()
|
||||||
|
.stdout_is("1\n0\n")
|
||||||
|
.no_stderr();
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue