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
|
// Hide all the nasty sh*t in here
|
||||||
pub fn solve_set_characters(
|
pub fn solve_set_characters(
|
||||||
set1: &Vec<Sequence>,
|
set1: Vec<Sequence>,
|
||||||
set2: &Vec<Sequence>,
|
set2: Vec<Sequence>,
|
||||||
|
truncate_set1_flag: bool,
|
||||||
) -> Result<(Vec<char>, Vec<char>), String> {
|
) -> Result<(Vec<char>, Vec<char>), String> {
|
||||||
let is_char_star = |s: &&Sequence| -> bool {
|
let is_char_star = |s: &&Sequence| -> bool {
|
||||||
match s {
|
match s {
|
||||||
|
@ -139,7 +133,8 @@ impl Sequence {
|
||||||
.flat_map(Sequence::flatten)
|
.flat_map(Sequence::flatten)
|
||||||
.count();
|
.count();
|
||||||
let star_compensate_len = set1_len.saturating_sub(set2_len);
|
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 {
|
(None, None) => match char_star {
|
||||||
Some(c) => std::iter::repeat(*c).take(star_compensate_len).collect(),
|
Some(c) => std::iter::repeat(*c).take(star_compensate_len).collect(),
|
||||||
None => std::iter::empty().collect(),
|
None => std::iter::empty().collect(),
|
||||||
|
@ -176,7 +171,10 @@ impl Sequence {
|
||||||
.collect(),
|
.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));
|
return Ok((set1_solved, set2_solved));
|
||||||
} else {
|
} else {
|
||||||
Err(format!(
|
Err(format!(
|
||||||
|
@ -407,9 +405,9 @@ pub struct DeleteOperation {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DeleteOperation {
|
impl DeleteOperation {
|
||||||
pub fn new(set: Vec<Sequence>, complement_flag: bool) -> DeleteOperation {
|
pub fn new(set: Vec<char>, complement_flag: bool) -> DeleteOperation {
|
||||||
DeleteOperation {
|
DeleteOperation {
|
||||||
set: set.iter().flat_map(Sequence::flatten).collect::<Vec<_>>(),
|
set,
|
||||||
complement_flag,
|
complement_flag,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -427,18 +425,16 @@ pub struct TranslateOperationComplement {
|
||||||
set2_iter: usize,
|
set2_iter: usize,
|
||||||
set1: Vec<char>,
|
set1: Vec<char>,
|
||||||
set2: Vec<char>,
|
set2: Vec<char>,
|
||||||
fallback: char,
|
|
||||||
translation_map: HashMap<char, char>,
|
translation_map: HashMap<char, char>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TranslateOperationComplement {
|
impl TranslateOperationComplement {
|
||||||
fn new(set1: Vec<char>, set2: Vec<char>, fallback: char) -> TranslateOperationComplement {
|
fn new(set1: Vec<char>, set2: Vec<char>) -> TranslateOperationComplement {
|
||||||
TranslateOperationComplement {
|
TranslateOperationComplement {
|
||||||
iter: 0,
|
iter: 0,
|
||||||
set2_iter: 0,
|
set2_iter: 0,
|
||||||
set1,
|
set1,
|
||||||
set2,
|
set2,
|
||||||
fallback,
|
|
||||||
translation_map: HashMap::new(),
|
translation_map: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -450,12 +446,22 @@ pub struct TranslateOperationStandard {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TranslateOperationStandard {
|
impl TranslateOperationStandard {
|
||||||
fn new(set1: Vec<char>, set2: Vec<char>, fallback: char) -> TranslateOperationStandard {
|
fn new(set1: Vec<char>, set2: Vec<char>) -> Result<TranslateOperationStandard, String> {
|
||||||
TranslateOperationStandard {
|
if let Some(fallback) = set2.last().map(|s| *s) {
|
||||||
translation_map: set1
|
Ok(TranslateOperationStandard {
|
||||||
.into_iter()
|
translation_map: set1
|
||||||
.zip(set2.into_iter().chain(std::iter::repeat(fallback)))
|
.into_iter()
|
||||||
.collect::<HashMap<_, _>>(),
|
.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 {
|
impl TranslateOperation {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
set1: Vec<Sequence>,
|
set1: Vec<char>,
|
||||||
set2: Vec<Sequence>,
|
set2: Vec<char>,
|
||||||
truncate_set1_flag: bool,
|
|
||||||
complement: bool,
|
complement: bool,
|
||||||
) -> Result<TranslateOperation, String> {
|
) -> 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 {
|
if complement {
|
||||||
Ok(TranslateOperation::Complement(
|
Ok(TranslateOperation::Complement(
|
||||||
TranslateOperationComplement::new(set1_solved, set2_solved, fallback),
|
TranslateOperationComplement::new(set1, set2),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Ok(TranslateOperation::Standard(
|
Ok(TranslateOperation::Standard(
|
||||||
TranslateOperationStandard::new(set1_solved, set2_solved, fallback),
|
TranslateOperationStandard::new(set1, set2)?,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -520,7 +514,6 @@ impl SymbolTranslator for TranslateOperation {
|
||||||
set2_iter,
|
set2_iter,
|
||||||
set1,
|
set1,
|
||||||
set2,
|
set2,
|
||||||
fallback,
|
|
||||||
translation_map,
|
translation_map,
|
||||||
}) => {
|
}) => {
|
||||||
// First, try to see if current char is already mapped
|
// 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);
|
*set2_iter = set2_iter.saturating_add(1);
|
||||||
translation_map.insert(next_key, *value);
|
translation_map.insert(next_key, *value);
|
||||||
} else {
|
} else {
|
||||||
translation_map.insert(current, *fallback);
|
translation_map.insert(current, *set2.last().unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(*translation_map.get(¤t).unwrap())
|
Some(*translation_map.get(¤t).unwrap())
|
||||||
|
@ -557,9 +550,9 @@ pub struct SqueezeOperation {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SqueezeOperation {
|
impl SqueezeOperation {
|
||||||
pub fn new(set1: Vec<Sequence>, complement: bool) -> SqueezeOperation {
|
pub fn new(set1: Vec<char>, complement: bool) -> SqueezeOperation {
|
||||||
SqueezeOperation {
|
SqueezeOperation {
|
||||||
set1: set1.iter().flat_map(Sequence::flatten).collect(),
|
set1,
|
||||||
complement,
|
complement,
|
||||||
previous: None,
|
previous: None,
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
.values_of(options::SETS)
|
.values_of(options::SETS)
|
||||||
.map(|v| v.map(ToString::to_string).collect::<Vec<_>>())
|
.map(|v| v.map(ToString::to_string).collect::<Vec<_>>())
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
let sets_len = sets.len();
|
||||||
|
|
||||||
if sets.is_empty() {
|
if sets.is_empty() {
|
||||||
show_error!(
|
show_error!(
|
||||||
|
@ -75,7 +76,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(delete_flag || squeeze_flag) && sets.len() < 2 {
|
if !(delete_flag || squeeze_flag) && sets_len < 2 {
|
||||||
show_error!(
|
show_error!(
|
||||||
"missing operand after '{}'\nTry '{} --help' for more information.",
|
"missing operand after '{}'\nTry '{} --help' for more information.",
|
||||||
sets[0],
|
sets[0],
|
||||||
|
@ -84,7 +85,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if sets.len() > 2 {
|
if sets_len > 2 {
|
||||||
show_error!(
|
show_error!(
|
||||||
"extra operand '{}'\nTry '{} --help' for more information.",
|
"extra operand '{}'\nTry '{} --help' for more information.",
|
||||||
sets[0],
|
sets[0],
|
||||||
|
@ -99,37 +100,44 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
let locked_stdout = stdout.lock();
|
let locked_stdout = stdout.lock();
|
||||||
let mut buffered_stdout = BufWriter::new(locked_stdout);
|
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 delete_flag {
|
||||||
if squeeze_flag {
|
if squeeze_flag {
|
||||||
let mut delete_buffer = vec![];
|
let mut delete_buffer = vec![];
|
||||||
{
|
{
|
||||||
let mut delete_writer = BufWriter::new(&mut delete_buffer);
|
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);
|
translate_input(&mut locked_stdin, &mut delete_writer, delete_op);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let mut squeeze_reader = BufReader::new(delete_buffer.as_bytes());
|
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);
|
translate_input(&mut squeeze_reader, &mut buffered_stdout, op);
|
||||||
}
|
}
|
||||||
} else {
|
} 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);
|
translate_input(&mut locked_stdin, &mut buffered_stdout, op);
|
||||||
}
|
}
|
||||||
} else if squeeze_flag {
|
} else if squeeze_flag {
|
||||||
if sets.len() < 2 {
|
if sets_len < 2 {
|
||||||
let op = SqueezeOperation::new(Sequence::from_str(&sets[0]), complement_flag);
|
let op = SqueezeOperation::new(set1, complement_flag);
|
||||||
translate_input(&mut locked_stdin, &mut buffered_stdout, op);
|
translate_input(&mut locked_stdin, &mut buffered_stdout, op);
|
||||||
} else {
|
} else {
|
||||||
let mut translate_buffer = vec![];
|
let mut translate_buffer = vec![];
|
||||||
{
|
{
|
||||||
let mut writer = BufWriter::new(&mut translate_buffer);
|
let mut writer = BufWriter::new(&mut translate_buffer);
|
||||||
match TranslateOperation::new(
|
match TranslateOperation::new(set1.clone(), set2.clone(), complement_flag) {
|
||||||
Sequence::from_str(&sets[0]),
|
|
||||||
Sequence::from_str(&sets[1]),
|
|
||||||
truncate_set1_flag,
|
|
||||||
complement_flag,
|
|
||||||
) {
|
|
||||||
Ok(op) => translate_input(&mut locked_stdin, &mut writer, op),
|
Ok(op) => translate_input(&mut locked_stdin, &mut writer, op),
|
||||||
Err(s) => {
|
Err(s) => {
|
||||||
show_error!("{}", 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 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);
|
translate_input(&mut reader, &mut buffered_stdout, squeeze_op);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match TranslateOperation::new(
|
match TranslateOperation::new(set1, set2, complement_flag) {
|
||||||
Sequence::from_str(&sets[0]),
|
|
||||||
Sequence::from_str(&sets[1]),
|
|
||||||
truncate_set1_flag,
|
|
||||||
complement_flag,
|
|
||||||
) {
|
|
||||||
Ok(op) => translate_input(&mut locked_stdin, &mut buffered_stdout, op),
|
Ok(op) => translate_input(&mut locked_stdin, &mut buffered_stdout, op),
|
||||||
Err(s) => {
|
Err(s) => {
|
||||||
show_error!("{}", s);
|
show_error!("{}", s);
|
||||||
|
|
Loading…
Reference in a new issue