Skip to content
Snippets Groups Projects

d/patches: backport upstream fixes for tr

Merged Frederic Danis requested to merge wip/fdanis/8085-tr-upstream-fix into apertis/v2022dev3
8 files
+ 552
0
Compare changes
  • Side-by-side
  • Inline
Files
8
From 5674d093275ea9ddc3be9ffbb3627eb5d6cae3a1 Mon Sep 17 00:00:00 2001
From: Jeffrey Finkelstein <jeffrey.finkelstein@protonmail.com>
Date: Sat, 1 May 2021 13:01:55 -0400
Subject: [PATCH] fixup! tr: implement translate and squeeze (-s) mode
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 8bit
---
src/uu/tr/src/tr.rs | 89 +++++++++++++++++++++------------------------
1 file changed, 42 insertions(+), 47 deletions(-)
diff --git a/src/uu/tr/src/tr.rs b/src/uu/tr/src/tr.rs
index 09c4304a..e04737a4 100644
--- a/src/uu/tr/src/tr.rs
+++ b/src/uu/tr/src/tr.rs
@@ -151,6 +151,35 @@ impl SymbolTranslator for TranslateOperation {
}
}
+struct TranslateAndSqueezeOperation {
+ translate: TranslateOperation,
+ squeeze: SqueezeOperation,
+}
+
+impl TranslateAndSqueezeOperation {
+ fn new(
+ set1: ExpandSet,
+ set2: &mut ExpandSet,
+ set2_: ExpandSet,
+ truncate: bool,
+ complement: bool,
+ ) -> TranslateAndSqueezeOperation {
+ TranslateAndSqueezeOperation {
+ translate: TranslateOperation::new(set1, set2, truncate),
+ squeeze: SqueezeOperation::new(set2_, complement),
+ }
+ }
+}
+
+impl SymbolTranslator for TranslateAndSqueezeOperation {
+ fn translate(&self, c: char, prev_c: char) -> Option<char> {
+ // `unwrap()` will never panic because `Translate.translate()`
+ // always returns `Some`.
+ self.squeeze
+ .translate(self.translate.translate(c, 0 as char).unwrap(), prev_c)
+ }
+}
+
fn translate_input<T: SymbolTranslator>(
input: &mut dyn BufRead,
output: &mut dyn Write,
@@ -168,8 +197,11 @@ fn translate_input<T: SymbolTranslator>(
// isolation to make borrow checker happy
let filtered = buf.chars().filter_map(|c| {
let res = translator.translate(c, prev_c);
+ // Set `prev_c` to the post-translate character. This
+ // allows the squeeze operation to correctly function
+ // after the translate operation.
if res.is_some() {
- prev_c = c;
+ prev_c = res.unwrap();
}
res
});
@@ -282,53 +314,16 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let op = SqueezeOperation::new(set1, complement_flag);
translate_input(&mut locked_stdin, &mut buffered_stdout, op);
} else {
- // Define a closure that computes the translation using a hash map.
- //
- // The `unwrap()` should never panic because the
- // `TranslateOperation.translate()` method always returns
- // `Some`.
let mut set2 = ExpandSet::new(sets[1].as_ref());
- let translator = TranslateOperation::new(set1, &mut set2, truncate_flag);
- let translate = |c| translator.translate(c, 0 as char).unwrap();
-
- // Prepare some variables to be used for the closure that
- // computes the squeeze operation.
- //
- // The `squeeze()` closure needs to be defined anew for
- // each line of input, but these variables do not change
- // while reading the input so they can be defined before
- // the `while` loop.
- let set2 = ExpandSet::new(sets[1].as_ref());
- let squeezer = SqueezeOperation::new(set2, complement_flag);
-
- // Prepare some memory to read each line of the input (`buf`) and to write
- let mut buf = String::with_capacity(BUFFER_LEN + 4);
-
- // Loop over each line of stdin.
- while let Ok(length) = locked_stdin.read_line(&mut buf) {
- if length == 0 {
- break;
- }
-
- // Define a closure that computes the squeeze operation.
- //
- // We keep track of the previously seen character on
- // each call to `squeeze()`, but we need to reset the
- // `prev_c` variable at the beginning of each line of
- // the input. That's why we define the closure inside
- // the `while` loop.
- let mut prev_c = 0 as char;
- let squeeze = |c| {
- let result = squeezer.translate(c, prev_c);
- prev_c = c;
- result
- };
-
- // First translate, then squeeze each character of the input line.
- let filtered: String = buf.chars().map(translate).filter_map(squeeze).collect();
- buf.clear();
- buffered_stdout.write_all(filtered.as_bytes()).unwrap();
- }
+ let set2_ = ExpandSet::new(sets[1].as_ref());
+ let op = TranslateAndSqueezeOperation::new(
+ set1,
+ &mut set2,
+ set2_,
+ complement_flag,
+ truncate_flag,
+ );
+ translate_input(&mut locked_stdin, &mut buffered_stdout, op);
}
} else {
let mut set2 = ExpandSet::new(sets[1].as_ref());
--
2.25.1
Loading