diff --git a/src/uucore/src/lib/features/format/num_format.rs b/src/uucore/src/lib/features/format/num_format.rs index 819ba6a5f..3e9c44f22 100644 --- a/src/uucore/src/lib/features/format/num_format.rs +++ b/src/uucore/src/lib/features/format/num_format.rs @@ -140,45 +140,25 @@ impl Formatter for UnsignedInt { fn fmt(&self, mut writer: impl Write, x: Self::Input) -> std::io::Result<()> { let mut s = match self.variant { UnsignedIntVariant::Decimal => format!("{x}"), - UnsignedIntVariant::Octal(Prefix::No) => format!("{x:o}"), - UnsignedIntVariant::Octal(Prefix::Yes) => { - // The prefix that rust uses is `0o`, but GNU uses `0`. - // We also need to take into account that 0 should not be 00 and - // that GNU pads prefixed octals with zeros. - // - // Since this is an unsigned int, we do not need to take the minus - // sign into account. - if x < 8u64.pow(self.precision.saturating_sub(1) as u32) { - format!("{x:0>width$o}", width = self.precision) - } else { - format!("0{x:o}") - } - } - UnsignedIntVariant::Hexadecimal(Case::Lowercase, Prefix::No) => { + UnsignedIntVariant::Octal(_) => format!("{x:o}"), + UnsignedIntVariant::Hexadecimal(Case::Lowercase, _) => { format!("{x:x}") } - UnsignedIntVariant::Hexadecimal(Case::Lowercase, Prefix::Yes) => { - if x == 0 { - "0".to_string() - } else { - format!("{x:#x}") - } - } - UnsignedIntVariant::Hexadecimal(Case::Uppercase, Prefix::No) => { + UnsignedIntVariant::Hexadecimal(Case::Uppercase, _) => { format!("{x:X}") } - UnsignedIntVariant::Hexadecimal(Case::Uppercase, Prefix::Yes) => { - if x == 0 { - "0".to_string() - } else { - format!("{x:#X}") - } - } }; - if self.precision > s.len() { - s = format!("{:0width$}", s, width = self.precision); - } + // Zeroes doe not get a prefix. An octal value does also not get a + // prefix if the padded value will not start with a zero. + let prefix = match (x, self.variant) { + (1.., UnsignedIntVariant::Hexadecimal(Case::Lowercase, Prefix::Yes)) => "0x", + (1.., UnsignedIntVariant::Hexadecimal(Case::Uppercase, Prefix::Yes)) => "0X", + (1.., UnsignedIntVariant::Octal(Prefix::Yes)) if s.len() >= self.precision => "0", + _ => "", + }; + + s = format!("{prefix}{s:0>width$}", width = self.precision); match self.alignment { NumberAlignment::Left => write!(writer, "{s: 0123456<"); } + +#[test] +fn pad_unsigned_zeroes() { + for format in ["%.3u", "%.3x", "%.3X", "%.3o"] { + new_ucmd!() + .args(&[format, "0"]) + .succeeds() + .stdout_only("000"); + } +} + +#[test] +fn pad_unsigned_three() { + for (format, expected) in [ + ("%.3u", "003"), + ("%.3x", "003"), + ("%.3X", "003"), + ("%.3o", "003"), + ("%#.3x", "0x003"), + ("%#.3X", "0X003"), + ("%#.3o", "003"), + ] { + new_ucmd!() + .args(&[format, "3"]) + .succeeds() + .stdout_only(expected); + } +}