diff --git a/src/uucore/src/lib/features/format/argument.rs b/src/uucore/src/lib/features/format/argument.rs index ef81fc353..758510498 100644 --- a/src/uucore/src/lib/features/format/argument.rs +++ b/src/uucore/src/lib/features/format/argument.rs @@ -31,7 +31,7 @@ pub enum FormatArgument { } pub trait ArgumentIter<'a>: Iterator { - fn get_char(&mut self) -> char; + fn get_char(&mut self) -> u8; fn get_i64(&mut self) -> i64; fn get_u64(&mut self) -> u64; fn get_f64(&mut self) -> f64; @@ -39,14 +39,14 @@ pub trait ArgumentIter<'a>: Iterator { } impl<'a, T: Iterator> ArgumentIter<'a> for T { - fn get_char(&mut self) -> char { + fn get_char(&mut self) -> u8 { let Some(next) = self.next() else { - return '\0'; + return b'\0'; }; match next { - FormatArgument::Char(c) => *c, - FormatArgument::Unparsed(s) => s.bytes().next().map_or('\0', char::from), - _ => '\0', + FormatArgument::Char(c) => *c as u8, + FormatArgument::Unparsed(s) => s.bytes().next().unwrap_or(b'\0'), + _ => b'\0', } } diff --git a/src/uucore/src/lib/features/format/spec.rs b/src/uucore/src/lib/features/format/spec.rs index 6d342f742..af8a912d2 100644 --- a/src/uucore/src/lib/features/format/spec.rs +++ b/src/uucore/src/lib/features/format/spec.rs @@ -3,7 +3,7 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -// spell-checker:ignore (vars) intmax ptrdiff +// spell-checker:ignore (vars) intmax ptrdiff padlen use crate::quoting_style::{escape_name, QuotingStyle}; @@ -14,7 +14,7 @@ use super::{ }, parse_escape_only, ArgumentIter, FormatChar, FormatError, }; -use std::{fmt::Display, io::Write, ops::ControlFlow}; +use std::{io::Write, ops::ControlFlow}; /// A parsed specification for formatting a value /// @@ -312,7 +312,7 @@ impl Spec { match self { Self::Char { width, align_left } => { let width = resolve_asterisk(*width, &mut args)?.unwrap_or(0); - write_padded(writer, args.get_char(), width, false, *align_left) + write_padded(writer, &[args.get_char()], width, *align_left) } Self::String { width, @@ -333,7 +333,7 @@ impl Spec { Some(p) if p < s.len() => &s[..p], _ => s, }; - write_padded(writer, truncated, width, false, *align_left) + write_padded(writer, truncated.as_bytes(), width, *align_left) } Self::EscapedString => { let s = args.get_str(); @@ -445,16 +445,17 @@ fn resolve_asterisk<'a>( fn write_padded( mut writer: impl Write, - text: impl Display, + text: &[u8], width: usize, - pad_zero: bool, left: bool, ) -> Result<(), FormatError> { - match (left, pad_zero) { - (false, false) => write!(writer, "{text: >width$}"), - (false, true) => write!(writer, "{text:0>width$}"), - // 0 is ignored if we pad left. - (true, _) => write!(writer, "{text: padlen$}", "")?; + writer.write_all(text) } .map_err(FormatError::IoError) } diff --git a/tests/by-util/test_printf.rs b/tests/by-util/test_printf.rs index 46340c28e..38d7b10a6 100644 --- a/tests/by-util/test_printf.rs +++ b/tests/by-util/test_printf.rs @@ -673,7 +673,11 @@ fn sub_alternative_upper_hex() { #[test] fn char_as_byte() { - new_ucmd!().args(&["%c", "🙃"]).succeeds().stdout_only("ð"); + new_ucmd!() + .args(&["%c", "🙃"]) + .succeeds() + .no_stderr() + .stdout_is_bytes(b"\xf0"); } #[test] @@ -736,3 +740,28 @@ fn pad_unsigned_three() { .stdout_only(expected); } } + +#[test] +fn pad_char() { + for (format, expected) in [("%3c", " X"), ("%1c", "X"), ("%-1c", "X"), ("%-3c", "X ")] { + new_ucmd!() + .args(&[format, "X"]) + .succeeds() + .stdout_only(expected); + } +} + +#[test] +fn pad_string() { + for (format, expected) in [ + ("%8s", " bottle"), + ("%-8s", "bottle "), + ("%6s", "bottle"), + ("%-6s", "bottle"), + ] { + new_ucmd!() + .args(&[format, "bottle"]) + .succeeds() + .stdout_only(expected); + } +}