1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

Merge pull request #6028 from RenjiSann/feature/printf-byte

printf: Make printf operate on bytes instead of strings
This commit is contained in:
Daniel Hofstetter 2024-02-29 16:17:16 +01:00 committed by GitHub
commit 75b2bfb111
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 48 additions and 18 deletions

View file

@ -31,7 +31,7 @@ pub enum FormatArgument {
} }
pub trait ArgumentIter<'a>: Iterator<Item = &'a FormatArgument> { pub trait ArgumentIter<'a>: Iterator<Item = &'a FormatArgument> {
fn get_char(&mut self) -> char; fn get_char(&mut self) -> u8;
fn get_i64(&mut self) -> i64; fn get_i64(&mut self) -> i64;
fn get_u64(&mut self) -> u64; fn get_u64(&mut self) -> u64;
fn get_f64(&mut self) -> f64; fn get_f64(&mut self) -> f64;
@ -39,14 +39,14 @@ pub trait ArgumentIter<'a>: Iterator<Item = &'a FormatArgument> {
} }
impl<'a, T: Iterator<Item = &'a FormatArgument>> ArgumentIter<'a> for T { impl<'a, T: Iterator<Item = &'a FormatArgument>> ArgumentIter<'a> for T {
fn get_char(&mut self) -> char { fn get_char(&mut self) -> u8 {
let Some(next) = self.next() else { let Some(next) = self.next() else {
return '\0'; return b'\0';
}; };
match next { match next {
FormatArgument::Char(c) => *c, FormatArgument::Char(c) => *c as u8,
FormatArgument::Unparsed(s) => s.bytes().next().map_or('\0', char::from), FormatArgument::Unparsed(s) => s.bytes().next().unwrap_or(b'\0'),
_ => '\0', _ => b'\0',
} }
} }

View file

@ -3,7 +3,7 @@
// For the full copyright and license information, please view the LICENSE // For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code. // 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}; use crate::quoting_style::{escape_name, QuotingStyle};
@ -14,7 +14,7 @@ use super::{
}, },
parse_escape_only, ArgumentIter, FormatChar, FormatError, 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 /// A parsed specification for formatting a value
/// ///
@ -312,7 +312,7 @@ impl Spec {
match self { match self {
Self::Char { width, align_left } => { Self::Char { width, align_left } => {
let width = resolve_asterisk(*width, &mut args)?.unwrap_or(0); 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 { Self::String {
width, width,
@ -333,7 +333,7 @@ impl Spec {
Some(p) if p < s.len() => &s[..p], Some(p) if p < s.len() => &s[..p],
_ => s, _ => s,
}; };
write_padded(writer, truncated, width, false, *align_left) write_padded(writer, truncated.as_bytes(), width, *align_left)
} }
Self::EscapedString => { Self::EscapedString => {
let s = args.get_str(); let s = args.get_str();
@ -445,16 +445,17 @@ fn resolve_asterisk<'a>(
fn write_padded( fn write_padded(
mut writer: impl Write, mut writer: impl Write,
text: impl Display, text: &[u8],
width: usize, width: usize,
pad_zero: bool,
left: bool, left: bool,
) -> Result<(), FormatError> { ) -> Result<(), FormatError> {
match (left, pad_zero) { let padlen = width.saturating_sub(text.len());
(false, false) => write!(writer, "{text: >width$}"), if left {
(false, true) => write!(writer, "{text:0>width$}"), writer.write_all(text)?;
// 0 is ignored if we pad left. write!(writer, "{: <padlen$}", "")
(true, _) => write!(writer, "{text: <width$}"), } else {
write!(writer, "{: >padlen$}", "")?;
writer.write_all(text)
} }
.map_err(FormatError::IoError) .map_err(FormatError::IoError)
} }

View file

@ -673,7 +673,11 @@ fn sub_alternative_upper_hex() {
#[test] #[test]
fn char_as_byte() { fn char_as_byte() {
new_ucmd!().args(&["%c", "🙃"]).succeeds().stdout_only("ð"); new_ucmd!()
.args(&["%c", "🙃"])
.succeeds()
.no_stderr()
.stdout_is_bytes(b"\xf0");
} }
#[test] #[test]
@ -736,3 +740,28 @@ fn pad_unsigned_three() {
.stdout_only(expected); .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);
}
}