mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
Merge pull request #7246 from RenjiSann/printf-negative-asterisk
printf: negative asterisk param changes alignment
This commit is contained in:
commit
717a6921fc
2 changed files with 65 additions and 14 deletions
|
@ -314,15 +314,17 @@ impl Spec {
|
||||||
) -> Result<(), FormatError> {
|
) -> Result<(), FormatError> {
|
||||||
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, neg_width) =
|
||||||
write_padded(writer, &[args.get_char()], width, *align_left)
|
resolve_asterisk_maybe_negative(*width, &mut args).unwrap_or_default();
|
||||||
|
write_padded(writer, &[args.get_char()], width, *align_left || neg_width)
|
||||||
}
|
}
|
||||||
Self::String {
|
Self::String {
|
||||||
width,
|
width,
|
||||||
align_left,
|
align_left,
|
||||||
precision,
|
precision,
|
||||||
} => {
|
} => {
|
||||||
let width = resolve_asterisk(*width, &mut args)?.unwrap_or(0);
|
let (width, neg_width) =
|
||||||
|
resolve_asterisk_maybe_negative(*width, &mut args).unwrap_or_default();
|
||||||
|
|
||||||
// GNU does do this truncation on a byte level, see for instance:
|
// GNU does do this truncation on a byte level, see for instance:
|
||||||
// printf "%.1s" 🙃
|
// printf "%.1s" 🙃
|
||||||
|
@ -330,13 +332,18 @@ impl Spec {
|
||||||
// For now, we let printf panic when we truncate within a code point.
|
// 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,
|
// TODO: We need to not use Rust's formatting for aligning the output,
|
||||||
// so that we can just write bytes to stdout without panicking.
|
// so that we can just write bytes to stdout without panicking.
|
||||||
let precision = resolve_asterisk(*precision, &mut args)?;
|
let precision = resolve_asterisk(*precision, &mut args);
|
||||||
let s = args.get_str();
|
let s = args.get_str();
|
||||||
let truncated = match precision {
|
let truncated = match precision {
|
||||||
Some(p) if p < s.len() => &s[..p],
|
Some(p) if p < s.len() => &s[..p],
|
||||||
_ => s,
|
_ => s,
|
||||||
};
|
};
|
||||||
write_padded(writer, truncated.as_bytes(), width, *align_left)
|
write_padded(
|
||||||
|
writer,
|
||||||
|
truncated.as_bytes(),
|
||||||
|
width,
|
||||||
|
*align_left || neg_width,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Self::EscapedString => {
|
Self::EscapedString => {
|
||||||
let s = args.get_str();
|
let s = args.get_str();
|
||||||
|
@ -374,8 +381,8 @@ impl Spec {
|
||||||
positive_sign,
|
positive_sign,
|
||||||
alignment,
|
alignment,
|
||||||
} => {
|
} => {
|
||||||
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)?.unwrap_or(0);
|
let precision = resolve_asterisk(*precision, &mut args).unwrap_or(0);
|
||||||
let i = args.get_i64();
|
let i = args.get_i64();
|
||||||
|
|
||||||
if precision as u64 > i32::MAX as u64 {
|
if precision as u64 > i32::MAX as u64 {
|
||||||
|
@ -397,8 +404,8 @@ impl Spec {
|
||||||
precision,
|
precision,
|
||||||
alignment,
|
alignment,
|
||||||
} => {
|
} => {
|
||||||
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)?.unwrap_or(0);
|
let precision = resolve_asterisk(*precision, &mut args).unwrap_or(0);
|
||||||
let i = args.get_u64();
|
let i = args.get_u64();
|
||||||
|
|
||||||
if precision as u64 > i32::MAX as u64 {
|
if precision as u64 > i32::MAX as u64 {
|
||||||
|
@ -423,8 +430,8 @@ impl Spec {
|
||||||
alignment,
|
alignment,
|
||||||
precision,
|
precision,
|
||||||
} => {
|
} => {
|
||||||
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)?.unwrap_or(6);
|
let precision = resolve_asterisk(*precision, &mut args).unwrap_or(6);
|
||||||
let f = args.get_f64();
|
let f = args.get_f64();
|
||||||
|
|
||||||
if precision as u64 > i32::MAX as u64 {
|
if precision as u64 > i32::MAX as u64 {
|
||||||
|
@ -450,12 +457,30 @@ impl Spec {
|
||||||
fn resolve_asterisk<'a>(
|
fn resolve_asterisk<'a>(
|
||||||
option: Option<CanAsterisk<usize>>,
|
option: Option<CanAsterisk<usize>>,
|
||||||
mut args: impl ArgumentIter<'a>,
|
mut args: impl ArgumentIter<'a>,
|
||||||
) -> Result<Option<usize>, FormatError> {
|
) -> Option<usize> {
|
||||||
Ok(match option {
|
match option {
|
||||||
None => None,
|
None => None,
|
||||||
Some(CanAsterisk::Asterisk) => Some(usize::try_from(args.get_u64()).ok().unwrap_or(0)),
|
Some(CanAsterisk::Asterisk) => Some(usize::try_from(args.get_u64()).ok().unwrap_or(0)),
|
||||||
Some(CanAsterisk::Fixed(w)) => Some(w),
|
Some(CanAsterisk::Fixed(w)) => Some(w),
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_asterisk_maybe_negative<'a>(
|
||||||
|
option: Option<CanAsterisk<usize>>,
|
||||||
|
mut args: impl ArgumentIter<'a>,
|
||||||
|
) -> Option<(usize, bool)> {
|
||||||
|
match option {
|
||||||
|
None => None,
|
||||||
|
Some(CanAsterisk::Asterisk) => {
|
||||||
|
let nb = args.get_i64();
|
||||||
|
if nb < 0 {
|
||||||
|
Some((usize::try_from(-(nb as isize)).ok().unwrap_or(0), true))
|
||||||
|
} else {
|
||||||
|
Some((usize::try_from(nb).ok().unwrap_or(0), false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(CanAsterisk::Fixed(w)) => Some((w, false)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_padded(
|
fn write_padded(
|
||||||
|
|
|
@ -504,6 +504,32 @@ fn sub_any_asterisk_hex_arg() {
|
||||||
.stdout_only("0123456789");
|
.stdout_only("0123456789");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sub_any_asterisk_negative_first_param() {
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["a(%*s)b", "-5", "xyz"])
|
||||||
|
.succeeds()
|
||||||
|
.stdout_only("a(xyz )b"); // Would be 'a( xyz)b' if -5 was 5
|
||||||
|
|
||||||
|
// Negative octal
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["a(%*s)b", "-010", "xyz"])
|
||||||
|
.succeeds()
|
||||||
|
.stdout_only("a(xyz )b");
|
||||||
|
|
||||||
|
// Negative hexadecimal
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["a(%*s)b", "-0x10", "xyz"])
|
||||||
|
.succeeds()
|
||||||
|
.stdout_only("a(xyz )b");
|
||||||
|
|
||||||
|
// Should also work on %c
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["a(%*c)b", "-5", "x"])
|
||||||
|
.succeeds()
|
||||||
|
.stdout_only("a(x )b"); // Would be 'a( x)b' if -5 was 5
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sub_any_specifiers_no_params() {
|
fn sub_any_specifiers_no_params() {
|
||||||
new_ucmd!()
|
new_ucmd!()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue