77// https://pubs.opengroup.org/onlinepubs/9699919799/utilities/sort.html
88// https://www.gnu.org/software/coreutils/manual/html_node/sort-invocation.html
99
10- // spell-checker:ignore (misc) HFKJFK Mbdfhn getrlimit RLIMIT_NOFILE rlim
10+ // spell-checker:ignore (misc) HFKJFK Mbdfhn getrlimit RLIMIT_NOFILE rlim bigdecimal extendedbigdecimal
1111
1212mod check;
1313mod chunks;
@@ -17,6 +17,7 @@ mod merge;
1717mod numeric_str_cmp;
1818mod tmp_dir;
1919
20+ use bigdecimal:: BigDecimal ;
2021use chunks:: LineData ;
2122use clap:: builder:: ValueParser ;
2223use clap:: { Arg , ArgAction , Command } ;
@@ -44,7 +45,9 @@ use unicode_width::UnicodeWidthStr;
4445use uucore:: display:: Quotable ;
4546use uucore:: error:: { FromIo , strip_errno} ;
4647use uucore:: error:: { UError , UResult , USimpleError , UUsageError , set_exit_code} ;
48+ use uucore:: extendedbigdecimal:: ExtendedBigDecimal ;
4749use uucore:: line_ending:: LineEnding ;
50+ use uucore:: parser:: num_parser:: { ExtendedParser , ExtendedParserError } ;
4851use uucore:: parser:: parse_size:: { ParseSizeError , Parser } ;
4952use uucore:: parser:: shortcut_value_parser:: ShortcutValueParser ;
5053use uucore:: version_cmp:: version_cmp;
@@ -448,7 +451,7 @@ impl Default for KeySettings {
448451 }
449452}
450453enum Selection < ' a > {
451- AsF64 ( GeneralF64ParseResult ) ,
454+ AsBigDecimal ( GeneralBigDecimalParseResult ) ,
452455 WithNumInfo ( & ' a str , NumInfo ) ,
453456 Str ( & ' a str ) ,
454457}
@@ -490,7 +493,7 @@ impl<'a> Line<'a> {
490493 . map ( |selector| ( selector, selector. get_selection ( line, token_buffer) ) )
491494 {
492495 match selection {
493- Selection :: AsF64 ( parsed_float) => line_data. parsed_floats . push ( parsed_float) ,
496+ Selection :: AsBigDecimal ( parsed_float) => line_data. parsed_floats . push ( parsed_float) ,
494497 Selection :: WithNumInfo ( str, num_info) => {
495498 line_data. num_infos . push ( num_info) ;
496499 line_data. selections . push ( str) ;
@@ -902,8 +905,8 @@ impl FieldSelector {
902905 range = & range[ num_range] ;
903906 Selection :: WithNumInfo ( range, info)
904907 } else if self . settings . mode == SortMode :: GeneralNumeric {
905- // Parse this number as f64 , as this is the requirement for general numeric sorting.
906- Selection :: AsF64 ( general_f64_parse ( & range[ get_leading_gen ( range) ] ) )
908+ // Parse this number as BigDecimal , as this is the requirement for general numeric sorting.
909+ Selection :: AsBigDecimal ( general_bd_parse ( & range[ get_leading_gen ( range) ] ) )
907910 } else {
908911 // This is not a numeric sort, so we don't need a NumCache.
909912 Selection :: Str ( range)
@@ -1789,35 +1792,45 @@ fn get_leading_gen(input: &str) -> Range<usize> {
17891792 leading_whitespace_len..input. len ( )
17901793}
17911794
1792- #[ derive( Copy , Clone , PartialEq , PartialOrd , Debug ) ]
1793- pub enum GeneralF64ParseResult {
1795+ #[ derive( Clone , PartialEq , PartialOrd , Debug ) ]
1796+ pub enum GeneralBigDecimalParseResult {
17941797 Invalid ,
1795- NaN ,
1796- NegInfinity ,
1797- Number ( f64 ) ,
1798+ Nan ,
1799+ MinusInfinity ,
1800+ Number ( BigDecimal ) ,
17981801 Infinity ,
17991802}
18001803
1801- /// Parse the beginning string into a GeneralF64ParseResult .
1802- /// Using a GeneralF64ParseResult instead of f64 is necessary to correctly order floats.
1804+ /// Parse the beginning string into a GeneralBigDecimalParseResult .
1805+ /// Using a GeneralBigDecimalParseResult instead of ExtendedBigDecimal is necessary to correctly order floats.
18031806#[ inline( always) ]
1804- fn general_f64_parse ( a : & str ) -> GeneralF64ParseResult {
1805- // The actual behavior here relies on Rust's implementation of parsing floating points.
1806- // For example "nan", "inf" (ignoring the case) and "infinity" are only parsed to floats starting from 1.53.
1807- // TODO: Once our minimum supported Rust version is 1.53 or above, we should add tests for those cases.
1808- match a. parse :: < f64 > ( ) {
1809- Ok ( a) if a. is_nan ( ) => GeneralF64ParseResult :: NaN ,
1810- Ok ( a) if a == f64:: NEG_INFINITY => GeneralF64ParseResult :: NegInfinity ,
1811- Ok ( a) if a == f64:: INFINITY => GeneralF64ParseResult :: Infinity ,
1812- Ok ( a) => GeneralF64ParseResult :: Number ( a) ,
1813- Err ( _) => GeneralF64ParseResult :: Invalid ,
1807+ fn general_bd_parse ( a : & str ) -> GeneralBigDecimalParseResult {
1808+ // Parse digits, and fold in recoverable errors
1809+ let ebd = match ExtendedBigDecimal :: extended_parse ( a) {
1810+ Err ( ExtendedParserError :: NotNumeric ) => return GeneralBigDecimalParseResult :: Invalid ,
1811+ Err ( ExtendedParserError :: PartialMatch ( ebd, _) )
1812+ | Err ( ExtendedParserError :: Overflow ( ebd) )
1813+ | Err ( ExtendedParserError :: Underflow ( ebd) )
1814+ | Ok ( ebd) => ebd,
1815+ } ;
1816+
1817+ match ebd {
1818+ ExtendedBigDecimal :: BigDecimal ( bd) => GeneralBigDecimalParseResult :: Number ( bd) ,
1819+ ExtendedBigDecimal :: Infinity => GeneralBigDecimalParseResult :: Infinity ,
1820+ ExtendedBigDecimal :: MinusInfinity => GeneralBigDecimalParseResult :: MinusInfinity ,
1821+ // Minus zero and zero are equal
1822+ ExtendedBigDecimal :: MinusZero => GeneralBigDecimalParseResult :: Number ( 0 . into ( ) ) ,
1823+ ExtendedBigDecimal :: Nan | ExtendedBigDecimal :: MinusNan => GeneralBigDecimalParseResult :: Nan ,
18141824 }
18151825}
18161826
18171827/// Compares two floats, with errors and non-numerics assumed to be -inf.
18181828/// Stops coercing at the first non-numeric char.
18191829/// We explicitly need to convert to f64 in this case.
1820- fn general_numeric_compare ( a : & GeneralF64ParseResult , b : & GeneralF64ParseResult ) -> Ordering {
1830+ fn general_numeric_compare (
1831+ a : & GeneralBigDecimalParseResult ,
1832+ b : & GeneralBigDecimalParseResult ,
1833+ ) -> Ordering {
18211834 a. partial_cmp ( b) . unwrap ( )
18221835}
18231836
0 commit comments