Skip to content

Commit 2ad25de

Browse files
committed
printf: trim leading whitespace when parsing numeric values
Trim leading whitespace from numeric input to printf.
1 parent 7bd90bb commit 2ad25de

File tree

2 files changed

+51
-3
lines changed

2 files changed

+51
-3
lines changed

src/uucore/src/lib/features/format/num_parser.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,11 +181,13 @@ impl ParsedNumber {
181181
};
182182
}
183183

184+
let trimmed_input = input.trim_ascii_start();
185+
184186
// Initial minus sign
185-
let (negative, unsigned) = if let Some(input) = input.strip_prefix('-') {
186-
(true, input)
187+
let (negative, unsigned) = if let Some(trimmed_input) = trimmed_input.strip_prefix('-') {
188+
(true, trimmed_input)
187189
} else {
188-
(false, input)
190+
(false, trimmed_input)
189191
};
190192

191193
// Parse an optional base prefix ("0b" / "0B" / "0" / "0x" / "0X"). "0" is octal unless a
@@ -384,4 +386,24 @@ mod tests {
384386
assert_eq!(Ok(0b1011), ParsedNumber::parse_u64("0b1011"));
385387
assert_eq!(Ok(0b1011), ParsedNumber::parse_u64("0B1011"));
386388
}
389+
390+
#[test]
391+
fn test_parsing_with_leading_whitespace() {
392+
assert_eq!(Ok(1), ParsedNumber::parse_u64(" 0x1"));
393+
assert_eq!(Ok(-2), ParsedNumber::parse_i64(" -0x2"));
394+
assert_eq!(Ok(-3), ParsedNumber::parse_i64(" \t-0x3"));
395+
assert_eq!(Ok(-4), ParsedNumber::parse_i64(" \n-0x4"));
396+
assert_eq!(Ok(-5), ParsedNumber::parse_i64(" \n\t\u{000d}-0x5"));
397+
398+
// Ensure that trailing whitespace is still a partial match
399+
assert_eq!(Err(ParseError::PartialMatch(6, " ")), ParsedNumber::parse_u64("0x6 "));
400+
assert_eq!(Err(ParseError::PartialMatch(7, "\t")), ParsedNumber::parse_u64("0x7\t"));
401+
assert_eq!(Err(ParseError::PartialMatch(8, "\n")), ParsedNumber::parse_u64("0x8\n"));
402+
403+
// Ensure that unicode non-ascii whitespace is a partial match
404+
assert_eq!(Err(ParseError::NotNumeric), ParsedNumber::parse_i64("\u{2029}-0x9"));
405+
406+
// Ensure that whitespace after the number has "started" is not allowed
407+
assert_eq!(Err(ParseError::NotNumeric), ParsedNumber::parse_i64("- 0x9"));
408+
}
387409
}

tests/by-util/test_printf.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,3 +1036,29 @@ fn float_switch_switch_decimal_scientific() {
10361036
.succeeds()
10371037
.stdout_only("1e-05");
10381038
}
1039+
1040+
#[test]
1041+
fn float_arg_with_whitespace() {
1042+
new_ucmd!()
1043+
.args(&["%f", " \u{0020}\u{000d}\t\n0.000001"])
1044+
.succeeds()
1045+
.stdout_only("0.000001");
1046+
1047+
new_ucmd!()
1048+
.args(&["%f", "0.1 "])
1049+
.fails()
1050+
.stderr_contains("value not completely converted");
1051+
1052+
// Unicode whitespace should not be allowed in a number
1053+
new_ucmd!()
1054+
.args(&["%f", "\u{2029}0.1"])
1055+
.fails()
1056+
.stderr_contains("expected a numeric value");
1057+
1058+
// A input string with a whitespace special character that has
1059+
// not already been expanded should fail.
1060+
new_ucmd!()
1061+
.args(&["%f", "\\t0.1"])
1062+
.fails()
1063+
.stderr_contains("expected a numeric value");
1064+
}

0 commit comments

Comments
 (0)