1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-27 19:17:43 +00:00

printf: fix padding and prefixes for unsigned ints

This commit is contained in:
Terts Diepraam 2024-02-07 16:14:12 +01:00 committed by Daniel Hofstetter
parent 4dae902429
commit 3126e5f8a1
2 changed files with 42 additions and 34 deletions

View file

@ -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:<width$}", width = self.width),

View file

@ -668,7 +668,7 @@ fn sub_alternative_upper_hex() {
new_ucmd!()
.args(&["%#X", "42"])
.succeeds()
.stdout_only("0x2A");
.stdout_only("0X2A");
}
#[test]
@ -708,3 +708,31 @@ fn pad_octal_with_prefix() {
.succeeds()
.stdout_only("> 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);
}
}