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

uucore: parser: num_parser: Parse "0x"/"0b" as PartialMatch

printf treats "0x" as a partial match of 0 and "x".
This commit is contained in:
Nicolas Boichat 2025-04-08 15:20:29 +02:00
parent 8363274f75
commit a4c56fbcee

View file

@ -450,9 +450,6 @@ pub(crate) fn parse<'a>(
} else { } else {
(Base::Decimal, unsigned) (Base::Decimal, unsigned)
}; };
if rest.is_empty() {
return Err(ExtendedParserError::NotNumeric);
}
// Parse the integral part of the number // Parse the integral part of the number
let mut chars = rest.chars().enumerate().fuse().peekable(); let mut chars = rest.chars().enumerate().fuse().peekable();
@ -518,6 +515,16 @@ pub(crate) fn parse<'a>(
// If no digit has been parsed, check if this is a special value, or declare the parsing unsuccessful // If no digit has been parsed, check if this is a special value, or declare the parsing unsuccessful
if digits.is_none() { if digits.is_none() {
// If we trimmed an initial `0x`/`0b`, return a partial match.
if rest != unsigned {
let ebd = if negative {
ExtendedBigDecimal::MinusZero
} else {
ExtendedBigDecimal::zero()
};
return Err(ExtendedParserError::PartialMatch(ebd, &unsigned[1..]));
}
return if target == ParseTarget::Integral { return if target == ParseTarget::Integral {
Err(ExtendedParserError::NotNumeric) Err(ExtendedParserError::NotNumeric)
} else { } else {
@ -968,23 +975,41 @@ mod tests {
)) ))
)); ));
// TODO: GNU coreutils treats these as partial matches. // Not actually hex numbers, but the prefixes look like it.
assert_eq!( assert!(matches!(f64::extended_parse("0x"),
Err(ExtendedParserError::NotNumeric), Err(ExtendedParserError::PartialMatch(f, "x")) if f == 0.0));
ExtendedBigDecimal::extended_parse("0x") assert!(matches!(f64::extended_parse("0x."),
); Err(ExtendedParserError::PartialMatch(f, "x.")) if f == 0.0));
assert_eq!( assert!(matches!(f64::extended_parse("0xp"),
Err(ExtendedParserError::NotNumeric), Err(ExtendedParserError::PartialMatch(f, "xp")) if f == 0.0));
ExtendedBigDecimal::extended_parse("0x.") assert!(matches!(f64::extended_parse("0xp-2"),
); Err(ExtendedParserError::PartialMatch(f, "xp-2")) if f == 0.0));
assert_eq!( assert!(matches!(f64::extended_parse("0x.p-2"),
Err(ExtendedParserError::NotNumeric), Err(ExtendedParserError::PartialMatch(f, "x.p-2")) if f == 0.0));
ExtendedBigDecimal::extended_parse("0xp") assert!(matches!(f64::extended_parse("0X"),
); Err(ExtendedParserError::PartialMatch(f, "X")) if f == 0.0));
assert_eq!( assert!(matches!(f64::extended_parse("-0x"),
Err(ExtendedParserError::NotNumeric), Err(ExtendedParserError::PartialMatch(f, "x")) if f == -0.0));
ExtendedBigDecimal::extended_parse("0xp-2") assert!(matches!(f64::extended_parse("+0x"),
); Err(ExtendedParserError::PartialMatch(f, "x")) if f == 0.0));
assert!(matches!(f64::extended_parse("-0x."),
Err(ExtendedParserError::PartialMatch(f, "x.")) if f == -0.0));
assert!(matches!(
u64::extended_parse("0x"),
Err(ExtendedParserError::PartialMatch(0, "x"))
));
assert!(matches!(
u64::extended_parse("-0x"),
Err(ExtendedParserError::PartialMatch(0, "x"))
));
assert!(matches!(
i64::extended_parse("0x"),
Err(ExtendedParserError::PartialMatch(0, "x"))
));
assert!(matches!(
i64::extended_parse("-0x"),
Err(ExtendedParserError::PartialMatch(0, "x"))
));
} }
#[test] #[test]
@ -1018,6 +1043,27 @@ mod tests {
assert_eq!(Ok(0b1011), u64::extended_parse("+0b1011")); assert_eq!(Ok(0b1011), u64::extended_parse("+0b1011"));
assert_eq!(Ok(-0b1011), i64::extended_parse("-0b1011")); assert_eq!(Ok(-0b1011), i64::extended_parse("-0b1011"));
assert!(matches!(
u64::extended_parse("0b"),
Err(ExtendedParserError::PartialMatch(0, "b"))
));
assert!(matches!(
u64::extended_parse("0b."),
Err(ExtendedParserError::PartialMatch(0, "b."))
));
assert!(matches!(
u64::extended_parse("-0b"),
Err(ExtendedParserError::PartialMatch(0, "b"))
));
assert!(matches!(
i64::extended_parse("0b"),
Err(ExtendedParserError::PartialMatch(0, "b"))
));
assert!(matches!(
i64::extended_parse("-0b"),
Err(ExtendedParserError::PartialMatch(0, "b"))
));
// Binary not allowed for floats // Binary not allowed for floats
assert!(matches!( assert!(matches!(
f64::extended_parse("0b100"), f64::extended_parse("0b100"),
@ -1042,11 +1088,6 @@ mod tests {
Err(ExtendedParserError::PartialMatch(ebd, "b.")) => ebd == ExtendedBigDecimal::zero(), Err(ExtendedParserError::PartialMatch(ebd, "b.")) => ebd == ExtendedBigDecimal::zero(),
_ => false, _ => false,
}); });
// TODO: GNU coreutils treats this as partial match.
assert_eq!(
Err(ExtendedParserError::NotNumeric),
u64::extended_parse("0b")
);
} }
#[test] #[test]