1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-29 12:07:46 +00:00

printf: allow precision in string

This commit is contained in:
Terts Diepraam 2023-11-20 12:38:26 +01:00
parent 5f2374b339
commit c43ee01d19

View file

@ -17,6 +17,7 @@ pub enum Spec {
}, },
String { String {
width: Option<CanAsterisk<usize>>, width: Option<CanAsterisk<usize>>,
precision: Option<CanAsterisk<usize>>,
parse_escape: bool, parse_escape: bool,
align_left: bool, align_left: bool,
}, },
@ -159,11 +160,13 @@ impl Spec {
}, },
b's' => Spec::String { b's' => Spec::String {
width, width,
precision,
parse_escape: false, parse_escape: false,
align_left: minus, align_left: minus,
}, },
b'b' => Spec::String { b'b' => Spec::String {
width, width,
precision,
parse_escape: true, parse_escape: true,
align_left: minus, align_left: minus,
}, },
@ -254,10 +257,12 @@ impl Spec {
} }
&Spec::String { &Spec::String {
width, width,
precision,
parse_escape, parse_escape,
align_left, align_left,
} => { } => {
let width = resolve_asterisk(width, &mut args)?.unwrap_or(0); let width = resolve_asterisk(width, &mut args)?.unwrap_or(0);
let precision = resolve_asterisk(precision, &mut args)?;
let arg = next_arg(&mut args)?; let arg = next_arg(&mut args)?;
let Some(s) = arg.get_str() else { let Some(s) = arg.get_str() else {
return Err(FormatError::InvalidArgument(arg.clone())); return Err(FormatError::InvalidArgument(arg.clone()));
@ -273,15 +278,29 @@ impl Spec {
} }
}; };
} }
// GNU does do this truncation on a byte level, see for instance:
// printf "%.1s" 🙃
// > <20>
// For now, we let printf panic when we truncate within a code point.
// TODO: We need to not use Rust's formatting for aligning the output,
// so that we can just write bytes to stdout without panicking.
let truncated = match precision {
Some(p) if p < parsed.len() => &parsed[..p],
_ => &parsed,
};
write_padded( write_padded(
writer, writer,
std::str::from_utf8(&parsed).expect("TODO: Accept invalid utf8"), std::str::from_utf8(&truncated).expect("TODO: Accept invalid utf8"),
width, width,
false, false,
align_left, align_left,
) )
} else { } else {
write_padded(writer, s, width, false, align_left) let truncated = match precision {
Some(p) if p < s.len() => &s[..p],
_ => s,
};
write_padded(writer, truncated, width, false, align_left)
} }
} }
&Spec::SignedInt { &Spec::SignedInt {