diff --git a/Cargo.lock b/Cargo.lock index 1d7634aa2..9c273695c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1928,9 +1928,9 @@ name = "uu_dd" version = "0.0.4" dependencies = [ "byte-unit", + "clap", "debug_print", "gcd", - "getopts", "libc", "rand 0.8.4", "signal-hook", diff --git a/src/uu/dd/Cargo.toml b/src/uu/dd/Cargo.toml index df7dbf483..6296b83ce 100644 --- a/src/uu/dd/Cargo.toml +++ b/src/uu/dd/Cargo.toml @@ -16,9 +16,8 @@ path = "src/dd.rs" [dependencies] byte-unit = "4.0" +clap = "2.33.3" debug_print = "1.0" -# Probably best to keep the getopts version identical to the version of getopts in the uucore crate -getopts = "<= 0.2.21" gcd = "2.0" libc = "0.2" signal-hook = "0.3.9" diff --git a/src/uu/dd/src/conversion_tables.rs b/src/uu/dd/src/conversion_tables.rs index 9ba604465..755331eed 100644 --- a/src/uu/dd/src/conversion_tables.rs +++ b/src/uu/dd/src/conversion_tables.rs @@ -1,4 +1,3 @@ - // Conversion tables are just lookup tables. // eg. The ASCII->EBCDIC table stores the EBCDIC code at the index // obtained by treating the ASCII representation as a number. diff --git a/src/uu/dd/src/datastructures.rs b/src/uu/dd/src/datastructures.rs new file mode 100644 index 000000000..cb720aeb7 --- /dev/null +++ b/src/uu/dd/src/datastructures.rs @@ -0,0 +1,178 @@ +use crate::conversion_tables::*; + +use std::error::Error; +use std::time; + +pub struct ProgUpdate +{ + pub reads_complete: u64, + pub reads_partial: u64, + pub writes_complete: u64, + pub writes_partial: u64, + pub bytes_total: u128, + pub records_truncated: u32, + pub duration: time::Duration, +} + +pub struct ReadStat +{ + pub reads_complete: u64, + pub reads_partial: u64, + pub records_truncated: u32, +} +impl std::ops::AddAssign for ReadStat +{ + fn add_assign(&mut self, other: Self) + { + *self = Self { + reads_complete: self.reads_complete + other.reads_complete, + reads_partial: self.reads_partial + other.reads_partial, + records_truncated: self.records_truncated + other.records_truncated, + } + } +} + +pub struct WriteStat +{ + pub writes_complete: u64, + pub writes_partial: u64, + pub bytes_total: u128, +} +impl std::ops::AddAssign for WriteStat +{ + fn add_assign(&mut self, other: Self) + { + *self = Self { + writes_complete: self.writes_complete + other.writes_complete, + writes_partial: self.writes_partial + other.writes_partial, + bytes_total: self.bytes_total + other.bytes_total, + } + } +} + +type Cbs = usize; + +/// Stores all Conv Flags that apply to the input +pub struct IConvFlags +{ + pub ctable: Option<&'static ConversionTable>, + pub block: Option, + pub unblock: Option, + pub swab: bool, + pub sync: Option, + pub noerror: bool, +} + +/// Stores all Conv Flags that apply to the output +#[derive(Debug, PartialEq)] +pub struct OConvFlags +{ + pub sparse: bool, + pub excl: bool, + pub nocreat: bool, + pub notrunc: bool, + pub fdatasync: bool, + pub fsync: bool, +} + +/// Stores all Flags that apply to the input +pub struct IFlags +{ + pub cio: bool, + pub direct: bool, + pub directory: bool, + pub dsync: bool, + pub sync: bool, + pub nocache: bool, + pub nonblock: bool, + pub noatime: bool, + pub noctty: bool, + pub nofollow: bool, + pub nolinks: bool, + pub binary: bool, + pub text: bool, + pub fullblock: bool, + pub count_bytes: bool, + pub skip_bytes: bool, +} + +/// Stores all Flags that apply to the output +pub struct OFlags +{ + pub append: bool, + pub cio: bool, + pub direct: bool, + pub directory: bool, + pub dsync: bool, + pub sync: bool, + pub nocache: bool, + pub nonblock: bool, + pub noatime: bool, + pub noctty: bool, + pub nofollow: bool, + pub nolinks: bool, + pub binary: bool, + pub text: bool, + pub seek_bytes: bool, +} + +/// The value of the status cl-option. +/// Controls printing of transfer stats +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum StatusLevel +{ + Progress, + Noxfer, + None, +} + +/// The value of count=N +/// Defaults to Reads(N) +/// if iflag=count_bytes +/// then becomes Bytes(N) +pub enum CountType +{ + Reads(usize), + Bytes(usize), +} + +#[derive(Debug)] +pub enum InternalError +{ + WrongInputType, + WrongOutputType, + InvalidConvBlockUnblockCase, +} + +impl std::fmt::Display for InternalError +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self + { + Self::WrongInputType | + Self::WrongOutputType => + write!(f, "Internal dd error: Wrong Input/Output data type"), + Self::InvalidConvBlockUnblockCase => + write!(f, "Internal dd error: Invalid Conversion, Block, or Unblock data"), + } + } +} + +impl Error for InternalError {} + +pub mod options +{ + pub const INFILE: &'static str = "if"; + pub const OUTFILE: &'static str = "of"; + pub const IBS: &'static str = "ibs"; + pub const OBS: &'static str = "obs"; + pub const BS: &'static str = "bs"; + pub const CBS: &'static str = "cbs"; + pub const COUNT: &'static str = "count"; + pub const SKIP: &'static str = "skip"; + pub const SEEK: &'static str = "seek"; + pub const STATUS: &'static str = "status"; + pub const CONV: &'static str = "conv"; + pub const IFLAG: &'static str = "iflag"; + pub const OFLAG: &'static str = "oflag"; +} diff --git a/src/uu/dd/src/dd.rs b/src/uu/dd/src/dd.rs index c81d8da2f..fe43be397 100644 --- a/src/uu/dd/src/dd.rs +++ b/src/uu/dd/src/dd.rs @@ -14,202 +14,40 @@ use uucore::InvalidEncodingHandling; #[cfg(test)] mod dd_unit_tests; +mod datastructures; +use datastructures::*; + mod parseargs; +use parseargs::Matches; mod conversion_tables; use conversion_tables::*; +use clap::{self, crate_version}; use byte_unit::Byte; use debug_print::debug_println; use gcd::Gcd; -use getopts; use signal_hook::consts::signal; use std::cmp; use std::convert::TryInto; use std::error::Error; use std::env; -use std::fs::{ - File, OpenOptions, -}; -use std::io::{ - self, Read, Write, - Seek, -}; +use std::fs::{File, OpenOptions, }; +use std::io::{self, Read, Write, Seek, }; #[cfg(unix)] use libc; #[cfg(unix)] use std::os::unix::fs::OpenOptionsExt; -use std::sync::{ - Arc, atomic::AtomicUsize, mpsc, atomic::Ordering, -}; +use std::sync::{Arc, atomic::AtomicUsize, mpsc, atomic::Ordering, }; use std::thread; use std::time; const SYNTAX: &str = "dd [OPERAND]...\ndd OPTION"; -const SUMMARY: &str = "copy, and optionally convert, a file system resource"; -const LONG_HELP: &str = ""; +const ABOUT: &str = "copy, and optionally convert, a file system resource"; const BUF_INIT_BYTE: u8 = 0xDD; const RTN_SUCCESS: i32 = 0; const RTN_FAILURE: i32 = 1; -// ----- Datatypes ----- -struct ProgUpdate -{ - reads_complete: u64, - reads_partial: u64, - writes_complete: u64, - writes_partial: u64, - bytes_total: u128, - records_truncated: u32, - duration: time::Duration, -} - -struct ReadStat -{ - reads_complete: u64, - reads_partial: u64, - records_truncated: u32, -} -impl std::ops::AddAssign for ReadStat -{ - fn add_assign(&mut self, other: Self) - { - *self = Self { - reads_complete: self.reads_complete + other.reads_complete, - reads_partial: self.reads_partial + other.reads_partial, - records_truncated: self.records_truncated + other.records_truncated, - } - } -} - -struct WriteStat -{ - writes_complete: u64, - writes_partial: u64, - bytes_total: u128, -} -impl std::ops::AddAssign for WriteStat -{ - fn add_assign(&mut self, other: Self) - { - *self = Self { - writes_complete: self.writes_complete + other.writes_complete, - writes_partial: self.writes_partial + other.writes_partial, - bytes_total: self.bytes_total + other.bytes_total, - } - } -} - -type Cbs = usize; - -/// Stores all Conv Flags that apply to the input -pub struct IConvFlags -{ - ctable: Option<&'static ConversionTable>, - block: Option, - unblock: Option, - swab: bool, - sync: Option, - noerror: bool, -} - -/// Stores all Conv Flags that apply to the output -#[derive(Debug, PartialEq)] -pub struct OConvFlags -{ - sparse: bool, - excl: bool, - nocreat: bool, - notrunc: bool, - fdatasync: bool, - fsync: bool, -} - -/// Stores all Flags that apply to the input -pub struct IFlags -{ - cio: bool, - direct: bool, - directory: bool, - dsync: bool, - sync: bool, - nocache: bool, - nonblock: bool, - noatime: bool, - noctty: bool, - nofollow: bool, - nolinks: bool, - binary: bool, - text: bool, - fullblock: bool, - count_bytes: bool, - skip_bytes: bool, -} - -/// Stores all Flags that apply to the output -pub struct OFlags -{ - append: bool, - cio: bool, - direct: bool, - directory: bool, - dsync: bool, - sync: bool, - nocache: bool, - nonblock: bool, - noatime: bool, - noctty: bool, - nofollow: bool, - nolinks: bool, - binary: bool, - text: bool, - seek_bytes: bool, -} - -/// The value of the status cl-option. -/// Controls printing of transfer stats -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum StatusLevel -{ - Progress, - Noxfer, - None, -} - -/// The value of count=N -/// Defaults to Reads(N) -/// if iflag=count_bytes -/// then becomes Bytes(N) -pub enum CountType -{ - Reads(usize), - Bytes(usize), -} - -#[derive(Debug)] -enum InternalError -{ - WrongInputType, - WrongOutputType, - InvalidConvBlockUnblockCase, -} - -impl std::fmt::Display for InternalError -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self - { - Self::WrongInputType | - Self::WrongOutputType => - write!(f, "Internal dd error: Wrong Input/Output data type"), - Self::InvalidConvBlockUnblockCase => - write!(f, "Internal dd error: Invalid Conversion, Block, or Unblock data"), - } - } -} - -impl Error for InternalError {} - struct Input { src: R, @@ -223,7 +61,7 @@ struct Input impl Input { - fn new(matches: &getopts::Matches) -> Result> + fn new(matches: &Matches) -> Result> { let ibs = parseargs::parse_ibs(matches)?; let non_ascii = parseargs::parse_input_non_ascii(matches)?; @@ -303,7 +141,7 @@ fn make_unix_iflags(oflags: &IFlags) -> Option impl Input { - fn new(matches: &getopts::Matches) -> Result> + fn new(matches: &Matches) -> Result> { let ibs = parseargs::parse_ibs(matches)?; let non_ascii = parseargs::parse_input_non_ascii(matches)?; @@ -313,7 +151,7 @@ impl Input let skip = parseargs::parse_skip_amt(&ibs, &iflags, matches)?; let count = parseargs::parse_count(&iflags, matches)?; - if let Some(fname) = matches.opt_str("if") + if let Some(fname) = matches.value_of("if") { let mut src = { @@ -359,7 +197,7 @@ impl Input impl Read for Input { - fn read(&mut self, mut buf: &mut [u8]) -> io::Result + fn read(&mut self, buf: &mut [u8]) -> io::Result { let mut base_idx = 0; let tlen = buf.len(); @@ -513,21 +351,16 @@ struct Output } impl Output { - fn new(matches: &getopts::Matches) -> Result> + fn new(matches: &Matches) -> Result> { let obs = parseargs::parse_obs(matches)?; let cflags = parseargs::parse_conv_flag_output(matches)?; let oflags = parseargs::parse_oflags(matches)?; - let seek = parseargs::parse_seek_amt(&obs, &oflags, matches)?; - if let Some(amt) = seek - { - let amt: u64 = amt.try_into()?; - dst.seek(io::SeekFrom::Start(amt))?; - } + let dst = io::stdout(); Ok(Output { - dst: io::stdout(), + dst, obs, cflags, oflags, @@ -598,14 +431,14 @@ fn make_unix_oflags(oflags: &OFlags) -> Option } impl Output { - fn new(matches: &getopts::Matches) -> Result> + fn new(matches: &Matches) -> Result> { let obs = parseargs::parse_obs(matches)?; let cflags = parseargs::parse_conv_flag_output(matches)?; let oflags = parseargs::parse_oflags(matches)?; let seek = parseargs::parse_seek_amt(&obs, &oflags, matches)?; - if let Some(fname) = matches.opt_str("of") + if let Some(fname) = matches.value_of("of") { let mut dst = { let mut opts = OpenOptions::new(); @@ -702,37 +535,11 @@ impl Write for Output } } -impl Seek for Output -{ - fn seek(&mut self, pos: io::SeekFrom) -> io::Result - { - self.dst.seek(pos) - } -} - impl Write for Output { fn write(&mut self, buf: &[u8]) -> io::Result { - #[inline] - fn is_sparse(buf: &[u8]) -> bool - { - buf.iter() - .all(|&e| e == 0u8) - } - // ----------------------------- - if self.cflags.sparse && is_sparse(buf) - { - let seek_amt: i64 = buf.len() - .try_into() - .expect("Internal dd Error: Seek amount greater than signed 64-bit integer"); - self.dst.seek(io::SeekFrom::Current(seek_amt))?; - Ok(buf.len()) - } - else - { - self.dst.write(buf) - } + self.dst.write(buf) } fn flush(&mut self) -> io::Result<()> @@ -1446,9 +1253,14 @@ pub fn uumain(args: impl uucore::Args) -> i32 .accept_any() .iter() .fold(Vec::new(), append_dashes_if_not_present); - let matches = build_app!().parse(dashed_args); - let result = match (matches.opt_present("if"), matches.opt_present("of")) + let matches = build_dd_app!() + // TODO: usage, after_help + //.usage(...) + //.after_help(...) + .get_matches_from(dashed_args); + + let result = match (matches.is_present(options::INFILE), matches.is_present(options::OUTFILE)) { (true, true) => { @@ -1489,74 +1301,74 @@ pub fn uumain(args: impl uucore::Args) -> i32 } } -pub fn uu_app() -> App<'static, 'static> +pub fn uu_app() -> clap::App<'static, 'static> { - build_app!() + build_dd_app!() } #[macro_export] -macro_rules! build_app ( +macro_rules! build_dd_app ( () => { - App::new(executable!()) + clap::App::new(executable!()) .version(crate_version!()) .about(ABOUT) .arg( - Arg::with_name(options::INFILE) + clap::Arg::with_name(options::INFILE) .long(options::INFILE) .takes_value(true) .help("if=FILE (alternatively --if FILE) specifies the file used for input. When not specified, stdin is used instead") ) .arg( - Arg::with_name(options::OUTFILE) + clap::Arg::with_name(options::OUTFILE) .long(options::OUTFILE) .takes_value(true) .help("of=FILE (alternatively --of FILE) specifies the file used for output. When not specified, stdout is used instead") ) .arg( - Arg::with_name(options::IBS) + clap::Arg::with_name(options::IBS) .long(options::IBS) .takes_value(true) .help("ibs=N (alternatively --ibs N) specifies the size of buffer used for reads (default: 512). Multiplier strings permitted.") ) .arg( - Arg::with_name(options::OBS) + clap::Arg::with_name(options::OBS) .long(options::OBS) .takes_value(true) .help("obs=N (alternatively --obs N) specifies the size of buffer used for writes (default: 512). Multiplier strings permitted.") ) .arg( - Arg::with_name(options::BS) + clap::Arg::with_name(options::BS) .long(options::BS) .takes_value(true) .help("bs=N (alternatively --bs N) specifies ibs=N and obs=N (default: 512). If ibs or obs are also specified, bs=N takes presedence. Multiplier strings permitted.") ) .arg( - Arg::with_name(options::CBS) + clap::Arg::with_name(options::CBS) .long(options::CBS) .takes_value(true) .help("cbs=BYTES (alternatively --cbs BYTES) specifies the 'conversion block size' in bytes. Applies to the conv=block, and conv=unblock operations. Multiplier strings permitted.") ) .arg( - Arg::with_name(options::SKIP) + clap::Arg::with_name(options::SKIP) .long(options::SKIP) .takes_value(true) .help("skip=N (alternatively --skip N) causes N ibs-sized records of input to be skipped before beginning copy/convert operations. See iflag=count_bytes if skipping N bytes is prefered. Multiplier strings permitted.") ) .arg( - Arg::with_name(options::SEEK) + clap::Arg::with_name(options::SEEK) .long(options::SEEK) .takes_value(true) .help("seek=N (alternatively --seek N) seeks N obs-sized records into output before beginning copy/convert operations. See oflag=seek_bytes if seeking N bytes is prefered. Multiplier strings permitted.") ) .arg( - Arg::with_name(options::COUNT) + clap::Arg::with_name(options::COUNT) .long(options::COUNT) .takes_value(true) .help("count=N (alternatively --count N) stop reading input after N ibs-sized read operations rather than proceeding until EOF. See iflag=count_bytes if stopping after N bytes is prefered. Multiplier strings permitted.") ) .arg( - Arg::with_name(options::STATUS) + clap::Arg::with_name(options::STATUS) .long(options::STATUS) .takes_value(true) .help("status=LEVEL (alternatively --status LEVEL) controls whether volume and performace stats are written to stderr. @@ -1577,7 +1389,7 @@ Printing performance stats is also triggered by the INFO signal (where supported ") ) .arg( - Arg::with_name(options::CONV) + clap::Arg::with_name(options::CONV) .long(options::CONV) .takes_value(true) .help("conv=CONV[,CONV] (alternatively --conv CONV[,CONV]) specifies a comma-separated list of conversion options or (for legacy reasons) file-flags. Conversion options and file flags may be intermixed. @@ -1611,7 +1423,7 @@ Flags: ") ) .arg( - Arg::with_name(options::IFLAG) + clap::Arg::with_name(options::IFLAG) .long(options::IFLAG) .takes_value(true) .help("iflag=FLAG[,FLAG] (alternatively --iflag FLAG[,FLAG]) a comma separated list of input flags which specify how the input source is treated. FLAG may be any of the input-flags or general-flags specified below. @@ -1638,7 +1450,7 @@ Output-Flags ") ) .arg( - Arg::with_name(options::OFLAG) + clap::Arg::with_name(options::OFLAG) .long(options::OFLAG) .takes_value(true) .help("oflag=FLAG[,FLAG] (alternatively --oflag FLAG[,FLAG]) a comma separated list of output flags which specify how the output source is treated. FLAG may be any of the output-flags or general-flags specified below. diff --git a/src/uu/dd/src/parseargs.rs b/src/uu/dd/src/parseargs.rs index a8ec0527c..258a88315 100644 --- a/src/uu/dd/src/parseargs.rs +++ b/src/uu/dd/src/parseargs.rs @@ -13,6 +13,8 @@ use crate::{ use std::error::Error; +pub type Matches = clap::ArgMatches<'static>; + /// Parser Errors describe errors with parser input #[derive(Debug)] pub enum ParseError @@ -300,21 +302,22 @@ fn parse_multiplier<'a>(s: &'a str) -> Result // "Y" | "YiB" => // Ok(1024*1024*1024*1024*1024*1024*1024*1024), _ => - Err(ParseError::NoMatchingMultiplier(String::from(s))), + Err(ParseError::NoMatchingMultiplier(s.to_string())), } } fn parse_bytes_only(s: &str) -> Result { - let bytes: usize = match s.parse() + match s.parse() { - Ok(val) => val, - Err(_) => return Err(ParseError::ByteStringContainsNoValue(String::from(s))), - }; - Ok(bytes) + Ok(bytes) => + Ok(bytes), + Err(_) => + Err(ParseError::ByteStringContainsNoValue(s.to_string())), + } } -fn parse_bytes_with_opt_multiplier(s: String) -> Result +fn parse_bytes_with_opt_multiplier(s: &str) -> Result { match s.find(char::is_alphabetic) { @@ -329,7 +332,7 @@ fn parse_bytes_with_opt_multiplier(s: String) -> Result } else { - Err(ParseError::MultiplierStringWouldOverflow(s)) + Err(ParseError::MultiplierStringWouldOverflow(s.to_string())) } } _ => @@ -337,13 +340,13 @@ fn parse_bytes_with_opt_multiplier(s: String) -> Result } } -pub fn parse_ibs(matches: &getopts::Matches) -> Result +pub fn parse_ibs(matches: &Matches) -> Result { - if let Some(mixed_str) = matches.opt_str("bs") + if let Some(mixed_str) = matches.value_of("bs") { parse_bytes_with_opt_multiplier(mixed_str) } - else if let Some(mixed_str) = matches.opt_str("ibs") + else if let Some(mixed_str) = matches.value_of("ibs") { parse_bytes_with_opt_multiplier(mixed_str) } @@ -353,9 +356,9 @@ pub fn parse_ibs(matches: &getopts::Matches) -> Result } } -fn parse_cbs(matches: &getopts::Matches) -> Result, ParseError> +fn parse_cbs(matches: &Matches) -> Result, ParseError> { - if let Some(s) = matches.opt_str("cbs") + if let Some(s) = matches.value_of("cbs") { let bytes = parse_bytes_with_opt_multiplier(s)?; Ok(Some(bytes)) @@ -366,9 +369,9 @@ fn parse_cbs(matches: &getopts::Matches) -> Result, ParseError> } } -pub fn parse_status_level(matches: &getopts::Matches) -> Result, ParseError> +pub fn parse_status_level(matches: &Matches) -> Result, ParseError> { - match matches.opt_str("status") + match matches.value_of("status") { Some(s) => { @@ -380,13 +383,13 @@ pub fn parse_status_level(matches: &getopts::Matches) -> Result Result +pub fn parse_obs(matches: &Matches) -> Result { - if let Some(mixed_str) = matches.opt_str("bs") + if let Some(mixed_str) = matches.value_of("bs") { parse_bytes_with_opt_multiplier(mixed_str) } - else if let Some(mixed_str) = matches.opt_str("obs") + else if let Some(mixed_str) = matches.value_of("obs") { parse_bytes_with_opt_multiplier(mixed_str) } @@ -452,11 +455,11 @@ fn parse_ctable(fmt: Option, case: Option) -> Option<&'stati } } -fn parse_flag_list>(tag: &str, matches: &getopts::Matches) -> Result, ParseError> +fn parse_flag_list>(tag: &str, matches: &Matches) -> Result, ParseError> { let mut flags = Vec::new(); - if let Some(comma_str) = matches.opt_str(tag) + if let Some(comma_str) = matches.value_of(tag) { for s in comma_str.split(",") { @@ -470,7 +473,7 @@ fn parse_flag_list>(tag: &str, matches: & /// Parse Conversion Options (Input Variety) /// Construct and validate a IConvFlags -pub fn parse_conv_flag_input(matches: &getopts::Matches) -> Result +pub fn parse_conv_flag_input(matches: &Matches) -> Result { let flags = parse_flag_list("conv", matches)?; let cbs = parse_cbs(matches)?; @@ -588,7 +591,7 @@ pub fn parse_conv_flag_input(matches: &getopts::Matches) -> Result Result +pub fn parse_conv_flag_output(matches: &Matches) -> Result { let flags = parse_flag_list("conv", matches)?; @@ -644,7 +647,7 @@ pub fn parse_conv_flag_output(matches: &getopts::Matches) -> Result Result +pub fn parse_iflags(matches: &Matches) -> Result { let mut cio = false; let mut direct = false; @@ -726,7 +729,7 @@ pub fn parse_iflags(matches: &getopts::Matches) -> Result } /// Parse OFlags struct from CL-input -pub fn parse_oflags(matches: &getopts::Matches) -> Result +pub fn parse_oflags(matches: &Matches) -> Result { let mut append = false; let mut cio = false; @@ -804,9 +807,9 @@ pub fn parse_oflags(matches: &getopts::Matches) -> Result } /// Parse the amount of the input file to skip. -pub fn parse_skip_amt(ibs: &usize, iflags: &IFlags, matches: &getopts::Matches) -> Result, ParseError> +pub fn parse_skip_amt(ibs: &usize, iflags: &IFlags, matches: &Matches) -> Result, ParseError> { - if let Some(amt) = matches.opt_str("skip") + if let Some(amt) = matches.value_of("skip") { if iflags.skip_bytes { @@ -826,9 +829,9 @@ pub fn parse_skip_amt(ibs: &usize, iflags: &IFlags, matches: &getopts::Matches) } /// Parse the amount of the output file to seek. -pub fn parse_seek_amt(obs: &usize, oflags: &OFlags, matches: &getopts::Matches) -> Result, ParseError> +pub fn parse_seek_amt(obs: &usize, oflags: &OFlags, matches: &Matches) -> Result, ParseError> { - if let Some(amt) = matches.opt_str("seek") + if let Some(amt) = matches.value_of("seek") { if oflags.seek_bytes { @@ -848,9 +851,9 @@ pub fn parse_seek_amt(obs: &usize, oflags: &OFlags, matches: &getopts::Matches) } /// Parse the value of count=N and the type of N implied by iflags -pub fn parse_count(iflags: &IFlags, matches: &getopts::Matches) -> Result, ParseError> +pub fn parse_count(iflags: &IFlags, matches: &Matches) -> Result, ParseError> { - if let Some(amt) = matches.opt_str("count") + if let Some(amt) = matches.value_of("count") { let n = parse_bytes_with_opt_multiplier(amt)?; if iflags.count_bytes @@ -869,9 +872,9 @@ pub fn parse_count(iflags: &IFlags, matches: &getopts::Matches) -> Result Result +pub fn parse_input_non_ascii(matches: &Matches) -> Result { - if let Some(conv_opts) = matches.opt_str("conv") + if let Some(conv_opts) = matches.value_of("conv") { Ok(conv_opts.contains("ascii")) }