Skip to content

Commit 8d84efe

Browse files
committed
uucore: parser: num_parser: Parse "0x"/"0b" as PartialMatch
printf treats "0x" as a partial match of 0 and "x".
1 parent 3f27073 commit 8d84efe

File tree

1 file changed

+66
-25
lines changed

1 file changed

+66
-25
lines changed

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

Lines changed: 66 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -404,9 +404,6 @@ fn parse(
404404
} else {
405405
(Base::Decimal, unsigned)
406406
};
407-
if rest.is_empty() {
408-
return Err(ExtendedParserError::NotNumeric);
409-
}
410407

411408
// Parse the integral part of the number
412409
let mut chars = rest.chars().enumerate().fuse().peekable();
@@ -472,6 +469,16 @@ fn parse(
472469

473470
// If no digit has been parsed, check if this is a special value, or declare the parsing unsuccessful
474471
if digits.is_none() {
472+
// If we trimmed an initial `0x`/`0b`, return a partial match.
473+
if rest != unsigned {
474+
let ebd = if negative {
475+
ExtendedBigDecimal::MinusZero
476+
} else {
477+
ExtendedBigDecimal::zero()
478+
};
479+
return Err(ExtendedParserError::PartialMatch(ebd, &unsigned[1..]));
480+
}
481+
475482
return if integral_only {
476483
Err(ExtendedParserError::NotNumeric)
477484
} else {
@@ -876,23 +883,41 @@ mod tests {
876883
))
877884
));
878885

879-
// TODO: GNU coreutils treats these as partial matches.
880-
assert_eq!(
881-
Err(ExtendedParserError::NotNumeric),
882-
ExtendedBigDecimal::extended_parse("0x")
883-
);
884-
assert_eq!(
885-
Err(ExtendedParserError::NotNumeric),
886-
ExtendedBigDecimal::extended_parse("0x.")
887-
);
888-
assert_eq!(
889-
Err(ExtendedParserError::NotNumeric),
890-
ExtendedBigDecimal::extended_parse("0xp")
891-
);
892-
assert_eq!(
893-
Err(ExtendedParserError::NotNumeric),
894-
ExtendedBigDecimal::extended_parse("0xp-2")
895-
);
886+
// Not actually hex numbers, but the prefixes look like it.
887+
assert!(matches!(f64::extended_parse("0x"),
888+
Err(ExtendedParserError::PartialMatch(f, "x")) if f == 0.0));
889+
assert!(matches!(f64::extended_parse("0x."),
890+
Err(ExtendedParserError::PartialMatch(f, "x.")) if f == 0.0));
891+
assert!(matches!(f64::extended_parse("0xp"),
892+
Err(ExtendedParserError::PartialMatch(f, "xp")) if f == 0.0));
893+
assert!(matches!(f64::extended_parse("0xp-2"),
894+
Err(ExtendedParserError::PartialMatch(f, "xp-2")) if f == 0.0));
895+
assert!(matches!(f64::extended_parse("0x.p-2"),
896+
Err(ExtendedParserError::PartialMatch(f, "x.p-2")) if f == 0.0));
897+
assert!(matches!(f64::extended_parse("0X"),
898+
Err(ExtendedParserError::PartialMatch(f, "X")) if f == 0.0));
899+
assert!(matches!(f64::extended_parse("-0x"),
900+
Err(ExtendedParserError::PartialMatch(f, "x")) if f == -0.0));
901+
assert!(matches!(f64::extended_parse("+0x"),
902+
Err(ExtendedParserError::PartialMatch(f, "x")) if f == 0.0));
903+
assert!(matches!(f64::extended_parse("-0x."),
904+
Err(ExtendedParserError::PartialMatch(f, "x.")) if f == -0.0));
905+
assert!(matches!(
906+
u64::extended_parse("0x"),
907+
Err(ExtendedParserError::PartialMatch(0, "x"))
908+
));
909+
assert!(matches!(
910+
u64::extended_parse("-0x"),
911+
Err(ExtendedParserError::PartialMatch(0, "x"))
912+
));
913+
assert!(matches!(
914+
i64::extended_parse("0x"),
915+
Err(ExtendedParserError::PartialMatch(0, "x"))
916+
));
917+
assert!(matches!(
918+
i64::extended_parse("-0x"),
919+
Err(ExtendedParserError::PartialMatch(0, "x"))
920+
));
896921
}
897922

898923
#[test]
@@ -926,6 +951,27 @@ mod tests {
926951
assert_eq!(Ok(0b1011), u64::extended_parse("+0b1011"));
927952
assert_eq!(Ok(-0b1011), i64::extended_parse("-0b1011"));
928953

954+
assert!(matches!(
955+
u64::extended_parse("0b"),
956+
Err(ExtendedParserError::PartialMatch(0, "b"))
957+
));
958+
assert!(matches!(
959+
u64::extended_parse("0b."),
960+
Err(ExtendedParserError::PartialMatch(0, "b."))
961+
));
962+
assert!(matches!(
963+
u64::extended_parse("-0b"),
964+
Err(ExtendedParserError::PartialMatch(0, "b"))
965+
));
966+
assert!(matches!(
967+
i64::extended_parse("0b"),
968+
Err(ExtendedParserError::PartialMatch(0, "b"))
969+
));
970+
assert!(matches!(
971+
i64::extended_parse("-0b"),
972+
Err(ExtendedParserError::PartialMatch(0, "b"))
973+
));
974+
929975
// Binary not allowed for floats
930976
assert!(matches!(
931977
f64::extended_parse("0b100"),
@@ -950,11 +996,6 @@ mod tests {
950996
Err(ExtendedParserError::PartialMatch(ebd, "b.")) => ebd == ExtendedBigDecimal::zero(),
951997
_ => false,
952998
});
953-
// TODO: GNU coreutils treats this as partial match.
954-
assert_eq!(
955-
Err(ExtendedParserError::NotNumeric),
956-
u64::extended_parse("0b")
957-
);
958999
}
9591000

9601001
#[test]

0 commit comments

Comments
 (0)