Skip to content

Commit

Permalink
Properly accept command line delimiter argument
Browse files Browse the repository at this point in the history
  • Loading branch information
deepinthebuild committed Feb 16, 2018
1 parent e822c86 commit 4362d94
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 3 deletions.
9 changes: 8 additions & 1 deletion cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,17 @@ args:
long: output
takes_value: true
value_name: OUTPUT
use_delimiter: false
- MMAP:
long: mmap
conflicts_with: NO_MMAP
takes_value: false
- NO_MMAP:
help: Prohibits usage of memory mapped files. This will slow down the deduplication process significantly!
long: no-mmap
takes_value: false
takes_value: false
- DELIMITER:
help: Specifies the byte pattern to separate entries by. Default is system-specified newline.
short: z
long: delimiter
takes_value: true
55 changes: 53 additions & 2 deletions src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ pub struct Args {
pub input: Option<PathBuf>,
pub output: Option<PathBuf>,
pub mmap: bool,
pub delim: u8,
pub crlf: bool,
}

impl Args {
Expand All @@ -21,11 +23,20 @@ impl Args {
.map(PathBuf::from);
let output = m.value_of("OUTPUT").map(PathBuf::from);
let mmap = !m.is_present("NO_MMAP");
let delim = m.value_of("DELIMITER").map_or(Ok(b'\n'), parse_to_byte_literal)?;
#[cfg(windows)]
let mut crlf = true;
#[cfg(not(windows))]
let mut crlf= false;

crlf &= m.occurrences_of("DELIMITER") == 0;

Ok(Args {
input,
output,
mmap,
delim,
crlf,
})
}
}
Expand All @@ -46,13 +57,33 @@ impl Default for Options {

impl From<Args> for Options {
fn from(src: Args) -> Self {
Self::default()
Options{delim: src.delim, crlf: src.crlf}
}
}

impl<'a> From<&'a Args> for Options {
fn from(src: &'a Args) -> Self {
Self::default()
Options{delim: src.delim, crlf: src.crlf}
}
}

fn parse_to_byte_literal(input: &str) -> Result<u8, DedupError> {
if input.len() == 1 {return Ok(input.as_bytes()[0])}
if input.len() > 2 {return Err(DedupError::ArgumentParseError(
format!("Invalid delimiter specified, only single byte characters are permitted. Found: {}", input)
))}

let bytes = input.as_bytes();
match (bytes[0], bytes[1]) {
(b'\\', b'n') => Ok(b'\n'),
(b'\\', b't') => Ok(b'\t'),
(b'\\', b'0') => Ok(b'\0'),
(b'\\', b'\\') => Ok(b'\\'),
(b'\\', b'\'') => Ok(b'\''),
(b'\\', b'"') => Ok(b'\"'),
(_, _) => Err(DedupError::ArgumentParseError(
format!("Invalid delimiter specified, only single byte characters are permitted. Found: {}", input)
)),
}
}

Expand Down Expand Up @@ -100,4 +131,24 @@ mod tests {

assert_eq!(m.value_of("OUTPUT"), Some("outputfile"));
}

#[test]
fn specify_delim_test() {
let yml = load_yaml!("../cli.yml");
let m =
App::from_yaml(yml).get_matches_from(vec!["dedup", "-z", "\\t", "inputfile"]);

assert!(m.is_present("DELIMITER"));
assert_eq!(parse_to_byte_literal(m.value_of("DELIMITER").unwrap()).unwrap(),
b'\t');
}

#[test]
fn unspecified_delim_test() {
let yml = load_yaml!("../cli.yml");
let m =
App::from_yaml(yml).get_matches_from(vec!["dedup", "inputfile"]);

assert!(!m.is_present("DELIMITER"));
}
}
2 changes: 2 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::io;
#[derive(Debug)]
pub enum DedupError {
ClosedPipe,
ArgumentParseError(String),
IO(io::Error),
Other,
}
Expand All @@ -14,6 +15,7 @@ impl Display for DedupError {
DedupError::ClosedPipe => write!(f, "A closed pipe was encountered"),
DedupError::Other => write!(f, "An unknown error has occurred"),
DedupError::IO(ref i) => write!(f, "{}", i),
DedupError::ArgumentParseError(ref s) => write!(f, "{}", s),
}
}
}
Expand Down

0 comments on commit 4362d94

Please sign in to comment.