1
Fork 0
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:
Jeffrey Finkelstein 2021-08-27 18:55:02 -04:00
parent 1df9a1691c
commit 2c66d9e0a7
2 changed files with 59 additions and 2 deletions

View file

@ -38,6 +38,8 @@ struct SeqOptions {
}
enum Number {
/// Negative zero, as if it were an integer.
MinusZero,
BigInt(BigInt),
F64(f64),
}
@ -45,6 +47,7 @@ enum Number {
impl Number {
fn is_zero(&self) -> bool {
match self {
Number::MinusZero => true,
Number::BigInt(n) => n.is_zero(),
Number::F64(n) => n.is_zero(),
}
@ -52,6 +55,7 @@ impl Number {
fn into_f64(self) -> f64 {
match self {
Number::MinusZero => -0.,
// BigInt::to_f64() can not return None.
Number::BigInt(n) => n.to_f64().unwrap(),
Number::F64(n) => n,
@ -67,7 +71,16 @@ impl FromStr for Number {
}
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>() {
Ok(value) if value.is_nan() => Err(format!(
"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) {
(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)) => {
print_seq_integers(
(first, increment, last),
@ -154,6 +175,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
options.terminator,
options.widths,
padding,
false,
)
}
(first, last, increment) => print_seq(
@ -247,13 +269,27 @@ fn print_seq(
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(
range: RangeInt,
separator: String,
terminator: String,
pad: bool,
padding: usize,
is_first_minus_zero: bool,
) {
let (first, increment, last) = range;
let mut value = first;
@ -262,6 +298,9 @@ fn print_seq_integers(
if !is_first_iteration {
print!("{}", separator);
}
if is_first_iteration && is_first_minus_zero {
print!("-");
}
is_first_iteration = false;
if pad {
print!("{number:>0width$}", number = value, width = padding);

View file

@ -140,3 +140,21 @@ fn test_seq_wrong_arg_floats() {
fn test_zero_step_floats() {
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();
}