Repository: uutils/coreutils (language: rust)

Issue:
sort: needs support for human-readable block size suffixes R and Q
Environment: Ubuntu 20.04, uutils `main` branch (git commit 6a5f2aa334a0ac69c6450eff4a432c3035b57353), GNU coreutils v9.6.3-3189c-dirty

Steps to reproduce:
```
printf "1Q\n1R\n" | sort -h
```

What happens now: uutils `sort` outputs
```
1Q
1R
```

What I expected to happen GNU `sort` outputs
```
1R
1Q
```

Notes: this is causing a failure in the GNU test file `tests/sort/sort.pl`. Apparently `R` and `Q` are new suffixes for (very large) block sizes, see https://www.gnu.org/software/coreutils/manual/html_node/Block-size.html




Discussion / hints:

Fix patch:
diff --git a/src/uu/sort/BENCHMARKING.md b/src/uu/sort/BENCHMARKING.md
index 0cc344c3118..355245b077b 100644
--- a/src/uu/sort/BENCHMARKING.md
+++ b/src/uu/sort/BENCHMARKING.md
@@ -48,7 +48,7 @@ rand = "0.8.3"
 ```rust
 use rand::prelude::*;
 fn main() {
-    let suffixes = ['k', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'];
+    let suffixes = ['k', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 'R', 'Q'];
     let mut rng = thread_rng();
     for _ in 0..100000 {
         println!(
diff --git a/src/uu/sort/src/numeric_str_cmp.rs b/src/uu/sort/src/numeric_str_cmp.rs
index 54950f2dbfe..86cbddc6424 100644
--- a/src/uu/sort/src/numeric_str_cmp.rs
+++ b/src/uu/sort/src/numeric_str_cmp.rs
@@ -82,7 +82,10 @@ impl NumInfo {
             if Self::is_invalid_char(char, &mut had_decimal_pt, parse_settings) {
                 return if let Some(start) = start {
                     let has_si_unit = parse_settings.accept_si_units
-                        && matches!(char, 'K' | 'k' | 'M' | 'G' | 'T' | 'P' | 'E' | 'Z' | 'Y');
+                        && matches!(
+                            char,
+                            'K' | 'k' | 'M' | 'G' | 'T' | 'P' | 'E' | 'Z' | 'Y' | 'R' | 'Q'
+                        );
                     (
                         Self { exponent, sign },
                         start..if has_si_unit { idx + 1 } else { idx },
@@ -176,6 +179,8 @@ fn get_unit(unit: Option<char>) -> u8 {
             'E' => 6,
             'Z' => 7,
             'Y' => 8,
+            'R' => 9,
+            'Q' => 10,
             _ => 0,
         }
     } else {
diff --git a/src/uu/sort/src/sort.rs b/src/uu/sort/src/sort.rs
index e6191410053..b9555974638 100644
--- a/src/uu/sort/src/sort.rs
+++ b/src/uu/sort/src/sort.rs
@@ -289,7 +289,7 @@ impl GlobalSettings {
         // GNU sort (8.32) invalid:  b, B, 1B,                         p, e, z, y
         let size = Parser::default()
             .with_allow_list(&[
-                "b", "k", "K", "m", "M", "g", "G", "t", "T", "P", "E", "Z", "Y",
+                "b", "k", "K", "m", "M", "g", "G", "t", "T", "P", "E", "Z", "Y", "R", "Q",
             ])
             .with_default_unit("K")
             .with_b_byte_count(true)
@@ -535,8 +535,9 @@ impl<'a> Line<'a> {
                     } else {
                         // include a trailing si unit
                         if selector.settings.mode == SortMode::HumanNumeric
-                            && self.line[selection.end..initial_selection.end]
-                                .starts_with(&['k', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'][..])
+                            && self.line[selection.end..initial_selection.end].starts_with(
+                                &['k', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 'R', 'Q'][..],
+                            )
                         {
                             selection.end += 1;
                         }


Test patch:
diff --git a/tests/by-util/test_sort.rs b/tests/by-util/test_sort.rs
index b6ce74cc85a..9a12d3ef8c0 100644
--- a/tests/by-util/test_sort.rs
+++ b/tests/by-util/test_sort.rs
@@ -1313,3 +1313,14 @@ fn test_k_overflow() {
         .succeeds()
         .stdout_is(output);
 }
+
+#[test]
+fn test_human_blocks_r_and_q() {
+    let input = "1Q\n1R\n";
+    let output = "1R\n1Q\n";
+    new_ucmd!()
+        .args(&["-h"])
+        .pipe_in(input)
+        .succeeds()
+        .stdout_is(output);
+}