mirror of
https://github.com/uutils/coreutils
synced 2024-12-18 00:53:25 +00:00
Fixing some issues discovered from tests...mostly to match GNU behavior
Signed-off-by: Hanif Bin Ariffin <hanif.ariffin.4326@gmail.com>
This commit is contained in:
parent
bf0f01714c
commit
2c8ba4ad2d
2 changed files with 58 additions and 62 deletions
|
@ -99,17 +99,11 @@ impl Sequence {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn last(&self) -> Option<char> {
|
||||
match self {
|
||||
Sequence::CharStar(c) => Some(*c),
|
||||
rest => rest.flatten().last(),
|
||||
}
|
||||
}
|
||||
|
||||
// Hide all the nasty sh*t in here
|
||||
pub fn solve_set_characters(
|
||||
set1: &Vec<Sequence>,
|
||||
set2: &Vec<Sequence>,
|
||||
set1: Vec<Sequence>,
|
||||
set2: Vec<Sequence>,
|
||||
truncate_set1_flag: bool,
|
||||
) -> Result<(Vec<char>, Vec<char>), String> {
|
||||
let is_char_star = |s: &&Sequence| -> bool {
|
||||
match s {
|
||||
|
@ -139,7 +133,8 @@ impl Sequence {
|
|||
.flat_map(Sequence::flatten)
|
||||
.count();
|
||||
let star_compensate_len = set1_len.saturating_sub(set2_len);
|
||||
let set2_solved = match (partition.next(), partition.next()) {
|
||||
let (left, right) = (partition.next(), partition.next());
|
||||
let set2_solved: Vec<char> = match (left, right) {
|
||||
(None, None) => match char_star {
|
||||
Some(c) => std::iter::repeat(*c).take(star_compensate_len).collect(),
|
||||
None => std::iter::empty().collect(),
|
||||
|
@ -176,7 +171,10 @@ impl Sequence {
|
|||
.collect(),
|
||||
},
|
||||
};
|
||||
let set1_solved = set1.iter().flat_map(Sequence::flatten).collect();
|
||||
let mut set1_solved: Vec<char> = set1.iter().flat_map(Sequence::flatten).collect();
|
||||
if truncate_set1_flag {
|
||||
set1_solved.truncate(set2_solved.len());
|
||||
}
|
||||
return Ok((set1_solved, set2_solved));
|
||||
} else {
|
||||
Err(format!(
|
||||
|
@ -407,9 +405,9 @@ pub struct DeleteOperation {
|
|||
}
|
||||
|
||||
impl DeleteOperation {
|
||||
pub fn new(set: Vec<Sequence>, complement_flag: bool) -> DeleteOperation {
|
||||
pub fn new(set: Vec<char>, complement_flag: bool) -> DeleteOperation {
|
||||
DeleteOperation {
|
||||
set: set.iter().flat_map(Sequence::flatten).collect::<Vec<_>>(),
|
||||
set,
|
||||
complement_flag,
|
||||
}
|
||||
}
|
||||
|
@ -427,18 +425,16 @@ pub struct TranslateOperationComplement {
|
|||
set2_iter: usize,
|
||||
set1: Vec<char>,
|
||||
set2: Vec<char>,
|
||||
fallback: char,
|
||||
translation_map: HashMap<char, char>,
|
||||
}
|
||||
|
||||
impl TranslateOperationComplement {
|
||||
fn new(set1: Vec<char>, set2: Vec<char>, fallback: char) -> TranslateOperationComplement {
|
||||
fn new(set1: Vec<char>, set2: Vec<char>) -> TranslateOperationComplement {
|
||||
TranslateOperationComplement {
|
||||
iter: 0,
|
||||
set2_iter: 0,
|
||||
set1,
|
||||
set2,
|
||||
fallback,
|
||||
translation_map: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
@ -450,12 +446,22 @@ pub struct TranslateOperationStandard {
|
|||
}
|
||||
|
||||
impl TranslateOperationStandard {
|
||||
fn new(set1: Vec<char>, set2: Vec<char>, fallback: char) -> TranslateOperationStandard {
|
||||
TranslateOperationStandard {
|
||||
translation_map: set1
|
||||
.into_iter()
|
||||
.zip(set2.into_iter().chain(std::iter::repeat(fallback)))
|
||||
.collect::<HashMap<_, _>>(),
|
||||
fn new(set1: Vec<char>, set2: Vec<char>) -> Result<TranslateOperationStandard, String> {
|
||||
if let Some(fallback) = set2.last().map(|s| *s) {
|
||||
Ok(TranslateOperationStandard {
|
||||
translation_map: set1
|
||||
.into_iter()
|
||||
.zip(set2.into_iter().chain(std::iter::repeat(fallback)))
|
||||
.collect::<HashMap<_, _>>(),
|
||||
})
|
||||
} else {
|
||||
if set1.is_empty() && set2.is_empty() {
|
||||
Ok(TranslateOperationStandard {
|
||||
translation_map: HashMap::new(),
|
||||
})
|
||||
} else {
|
||||
Err("when not truncating set1, string2 must be non-empty".to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -478,29 +484,17 @@ impl TranslateOperation {
|
|||
|
||||
impl TranslateOperation {
|
||||
pub fn new(
|
||||
set1: Vec<Sequence>,
|
||||
set2: Vec<Sequence>,
|
||||
truncate_set1_flag: bool,
|
||||
set1: Vec<char>,
|
||||
set2: Vec<char>,
|
||||
complement: bool,
|
||||
) -> Result<TranslateOperation, String> {
|
||||
let (mut set1_solved, set2_solved) = Sequence::solve_set_characters(&set1, &set2)?;
|
||||
if truncate_set1_flag {
|
||||
set1_solved.truncate(set2_solved.len());
|
||||
}
|
||||
let fallback = set2.last().map(Sequence::last).flatten().expect(
|
||||
format!(
|
||||
"{}: when not truncating set1, string2 must be non-empty",
|
||||
executable!()
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
if complement {
|
||||
Ok(TranslateOperation::Complement(
|
||||
TranslateOperationComplement::new(set1_solved, set2_solved, fallback),
|
||||
TranslateOperationComplement::new(set1, set2),
|
||||
))
|
||||
} else {
|
||||
Ok(TranslateOperation::Standard(
|
||||
TranslateOperationStandard::new(set1_solved, set2_solved, fallback),
|
||||
TranslateOperationStandard::new(set1, set2)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -520,7 +514,6 @@ impl SymbolTranslator for TranslateOperation {
|
|||
set2_iter,
|
||||
set1,
|
||||
set2,
|
||||
fallback,
|
||||
translation_map,
|
||||
}) => {
|
||||
// First, try to see if current char is already mapped
|
||||
|
@ -539,7 +532,7 @@ impl SymbolTranslator for TranslateOperation {
|
|||
*set2_iter = set2_iter.saturating_add(1);
|
||||
translation_map.insert(next_key, *value);
|
||||
} else {
|
||||
translation_map.insert(current, *fallback);
|
||||
translation_map.insert(current, *set2.last().unwrap());
|
||||
}
|
||||
}
|
||||
Some(*translation_map.get(¤t).unwrap())
|
||||
|
@ -557,9 +550,9 @@ pub struct SqueezeOperation {
|
|||
}
|
||||
|
||||
impl SqueezeOperation {
|
||||
pub fn new(set1: Vec<Sequence>, complement: bool) -> SqueezeOperation {
|
||||
pub fn new(set1: Vec<char>, complement: bool) -> SqueezeOperation {
|
||||
SqueezeOperation {
|
||||
set1: set1.iter().flat_map(Sequence::flatten).collect(),
|
||||
set1,
|
||||
complement,
|
||||
previous: None,
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
.values_of(options::SETS)
|
||||
.map(|v| v.map(ToString::to_string).collect::<Vec<_>>())
|
||||
.unwrap_or_default();
|
||||
let sets_len = sets.len();
|
||||
|
||||
if sets.is_empty() {
|
||||
show_error!(
|
||||
|
@ -75,7 +76,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
return 1;
|
||||
}
|
||||
|
||||
if !(delete_flag || squeeze_flag) && sets.len() < 2 {
|
||||
if !(delete_flag || squeeze_flag) && sets_len < 2 {
|
||||
show_error!(
|
||||
"missing operand after '{}'\nTry '{} --help' for more information.",
|
||||
sets[0],
|
||||
|
@ -84,7 +85,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
return 1;
|
||||
}
|
||||
|
||||
if sets.len() > 2 {
|
||||
if sets_len > 2 {
|
||||
show_error!(
|
||||
"extra operand '{}'\nTry '{} --help' for more information.",
|
||||
sets[0],
|
||||
|
@ -99,37 +100,44 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
let locked_stdout = stdout.lock();
|
||||
let mut buffered_stdout = BufWriter::new(locked_stdout);
|
||||
|
||||
let mut sets_iter = sets.into_iter();
|
||||
let (set1, set2) = match Sequence::solve_set_characters(
|
||||
Sequence::from_str(sets_iter.next().unwrap_or_default().as_str()),
|
||||
Sequence::from_str(sets_iter.next().unwrap_or_default().as_str()),
|
||||
truncate_set1_flag,
|
||||
) {
|
||||
Ok(r) => r,
|
||||
Err(s) => {
|
||||
show_error!("{}", s);
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
if delete_flag {
|
||||
if squeeze_flag {
|
||||
let mut delete_buffer = vec![];
|
||||
{
|
||||
let mut delete_writer = BufWriter::new(&mut delete_buffer);
|
||||
let delete_op = DeleteOperation::new(Sequence::from_str(&sets[0]), complement_flag);
|
||||
let delete_op = DeleteOperation::new(set1.clone(), complement_flag);
|
||||
translate_input(&mut locked_stdin, &mut delete_writer, delete_op);
|
||||
}
|
||||
{
|
||||
let mut squeeze_reader = BufReader::new(delete_buffer.as_bytes());
|
||||
let op = SqueezeOperation::new(Sequence::from_str(&sets[1]), complement_flag);
|
||||
let op = SqueezeOperation::new(set2, complement_flag);
|
||||
translate_input(&mut squeeze_reader, &mut buffered_stdout, op);
|
||||
}
|
||||
} else {
|
||||
let op = DeleteOperation::new(Sequence::from_str(&sets[0]), complement_flag);
|
||||
let op = DeleteOperation::new(set1, complement_flag);
|
||||
translate_input(&mut locked_stdin, &mut buffered_stdout, op);
|
||||
}
|
||||
} else if squeeze_flag {
|
||||
if sets.len() < 2 {
|
||||
let op = SqueezeOperation::new(Sequence::from_str(&sets[0]), complement_flag);
|
||||
if sets_len < 2 {
|
||||
let op = SqueezeOperation::new(set1, complement_flag);
|
||||
translate_input(&mut locked_stdin, &mut buffered_stdout, op);
|
||||
} else {
|
||||
let mut translate_buffer = vec![];
|
||||
{
|
||||
let mut writer = BufWriter::new(&mut translate_buffer);
|
||||
match TranslateOperation::new(
|
||||
Sequence::from_str(&sets[0]),
|
||||
Sequence::from_str(&sets[1]),
|
||||
truncate_set1_flag,
|
||||
complement_flag,
|
||||
) {
|
||||
match TranslateOperation::new(set1.clone(), set2.clone(), complement_flag) {
|
||||
Ok(op) => translate_input(&mut locked_stdin, &mut writer, op),
|
||||
Err(s) => {
|
||||
show_error!("{}", s);
|
||||
|
@ -139,17 +147,12 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
}
|
||||
{
|
||||
let mut reader = BufReader::new(translate_buffer.as_bytes());
|
||||
let squeeze_op = SqueezeOperation::new(Sequence::from_str(&sets[1]), false);
|
||||
let squeeze_op = SqueezeOperation::new(set2, false);
|
||||
translate_input(&mut reader, &mut buffered_stdout, squeeze_op);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match TranslateOperation::new(
|
||||
Sequence::from_str(&sets[0]),
|
||||
Sequence::from_str(&sets[1]),
|
||||
truncate_set1_flag,
|
||||
complement_flag,
|
||||
) {
|
||||
match TranslateOperation::new(set1, set2, complement_flag) {
|
||||
Ok(op) => translate_input(&mut locked_stdin, &mut buffered_stdout, op),
|
||||
Err(s) => {
|
||||
show_error!("{}", s);
|
||||
|
|
Loading…
Reference in a new issue