mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-30 12:37:49 +00:00
Implements count=N
- Adds tests for count=READS and count=BYTES. - Implements count logic for read count and bytes count limits.
This commit is contained in:
parent
fc110bb656
commit
8141919064
10 changed files with 341 additions and 98 deletions
|
@ -66,6 +66,17 @@ struct ReadStat
|
||||||
reads_partial: u64,
|
reads_partial: u64,
|
||||||
records_truncated: u32,
|
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
|
struct WriteStat
|
||||||
{
|
{
|
||||||
|
@ -73,6 +84,17 @@ struct WriteStat
|
||||||
writes_partial: u64,
|
writes_partial: u64,
|
||||||
bytes_total: u128,
|
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;
|
type Cbs = usize;
|
||||||
|
|
||||||
|
@ -150,6 +172,16 @@ pub enum StatusLevel
|
||||||
None,
|
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)]
|
#[derive(Debug)]
|
||||||
enum InternalError
|
enum InternalError
|
||||||
{
|
{
|
||||||
|
@ -180,6 +212,7 @@ struct Input<R: Read>
|
||||||
non_ascii: bool,
|
non_ascii: bool,
|
||||||
ibs: usize,
|
ibs: usize,
|
||||||
xfer_stats: Option<StatusLevel>,
|
xfer_stats: Option<StatusLevel>,
|
||||||
|
count: Option<CountType>,
|
||||||
cflags: IConvFlags,
|
cflags: IConvFlags,
|
||||||
iflags: IFlags,
|
iflags: IFlags,
|
||||||
}
|
}
|
||||||
|
@ -194,12 +227,14 @@ impl Input<io::Stdin>
|
||||||
let cflags = parseargs::parse_conv_flag_input(matches)?;
|
let cflags = parseargs::parse_conv_flag_input(matches)?;
|
||||||
let iflags = parseargs::parse_iflags(matches)?;
|
let iflags = parseargs::parse_iflags(matches)?;
|
||||||
let skip = parseargs::parse_skip_amt(&ibs, &iflags, matches)?;
|
let skip = parseargs::parse_skip_amt(&ibs, &iflags, matches)?;
|
||||||
|
let count = parseargs::parse_count(&iflags, matches)?;
|
||||||
|
|
||||||
let mut i = Input {
|
let mut i = Input {
|
||||||
src: io::stdin(),
|
src: io::stdin(),
|
||||||
non_ascii,
|
non_ascii,
|
||||||
ibs,
|
ibs,
|
||||||
xfer_stats,
|
xfer_stats,
|
||||||
|
count,
|
||||||
cflags,
|
cflags,
|
||||||
iflags,
|
iflags,
|
||||||
};
|
};
|
||||||
|
@ -225,6 +260,7 @@ impl Input<File>
|
||||||
let cflags = parseargs::parse_conv_flag_input(matches)?;
|
let cflags = parseargs::parse_conv_flag_input(matches)?;
|
||||||
let iflags = parseargs::parse_iflags(matches)?;
|
let iflags = parseargs::parse_iflags(matches)?;
|
||||||
let skip = parseargs::parse_skip_amt(&ibs, &iflags, matches)?;
|
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.opt_str("if")
|
||||||
{
|
{
|
||||||
|
@ -241,6 +277,7 @@ impl Input<File>
|
||||||
non_ascii,
|
non_ascii,
|
||||||
ibs,
|
ibs,
|
||||||
xfer_stats,
|
xfer_stats,
|
||||||
|
count,
|
||||||
cflags,
|
cflags,
|
||||||
iflags,
|
iflags,
|
||||||
};
|
};
|
||||||
|
@ -279,7 +316,7 @@ impl<R: Read> Read for Input<R>
|
||||||
|
|
||||||
impl<R: Read> Input<R>
|
impl<R: Read> Input<R>
|
||||||
{
|
{
|
||||||
/// Fills a given obs-sized buffer.
|
/// Fills a given buffer.
|
||||||
/// Reads in increments of 'self.ibs'.
|
/// Reads in increments of 'self.ibs'.
|
||||||
/// The start of each ibs-sized read follows the previous one.
|
/// The start of each ibs-sized read follows the previous one.
|
||||||
fn fill_consecutive(&mut self, buf: &mut Vec<u8>) -> Result<ReadStat, Box<dyn Error>>
|
fn fill_consecutive(&mut self, buf: &mut Vec<u8>) -> Result<ReadStat, Box<dyn Error>>
|
||||||
|
@ -317,7 +354,7 @@ impl<R: Read> Input<R>
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fills a given obs-sized buffer.
|
/// Fills a given buffer.
|
||||||
/// Reads in increments of 'self.ibs'.
|
/// Reads in increments of 'self.ibs'.
|
||||||
/// The start of each ibs-sized read is aligned to multiples of ibs; remaing space is filled with the 'pad' byte.
|
/// The start of each ibs-sized read is aligned to multiples of ibs; remaing space is filled with the 'pad' byte.
|
||||||
fn fill_blocks(&mut self, buf: &mut Vec<u8>, obs: usize, pad: u8) -> Result<ReadStat, Box<dyn Error>>
|
fn fill_blocks(&mut self, buf: &mut Vec<u8>, obs: usize, pad: u8) -> Result<ReadStat, Box<dyn Error>>
|
||||||
|
@ -375,23 +412,19 @@ impl<R: Read> Input<R>
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Force-fills a buffer, ignoring zero-length reads which would otherwise be
|
/// Force-fills a buffer, ignoring zero-length reads which would otherwise be
|
||||||
/// interpreted as EOF. Does not continue after errors.
|
/// interpreted as EOF.
|
||||||
/// Note: This may never return.
|
/// Note: This will not return unless the source (eventually) produces
|
||||||
fn force_fill(&mut self, mut buf: &mut [u8], target_len: usize) -> Result<(), Box<dyn Error>>
|
/// enough bytes to meet target_len.
|
||||||
|
fn force_fill(&mut self, mut buf: &mut [u8], target_len: usize) -> Result<usize, Box<dyn Error>>
|
||||||
{
|
{
|
||||||
let mut total_len = 0;
|
let mut base_idx = 0;
|
||||||
|
while base_idx < target_len
|
||||||
loop
|
|
||||||
{
|
{
|
||||||
total_len += self.read(&mut buf)?;
|
base_idx += self.read(&mut buf[base_idx..target_len])?;
|
||||||
|
|
||||||
if total_len == target_len
|
|
||||||
{
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
Ok(base_idx)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Output<W: Write>
|
struct Output<W: Write>
|
||||||
|
@ -602,7 +635,7 @@ impl Output<File>
|
||||||
|
|
||||||
/// Splits the content of buf into cbs-length blocks
|
/// Splits the content of buf into cbs-length blocks
|
||||||
/// Appends padding as specified by conv=block and cbs=N
|
/// Appends padding as specified by conv=block and cbs=N
|
||||||
fn block(buf: Vec<u8>, cbs: usize, rstats: &mut ReadStat) -> Vec<Vec<u8>>
|
fn block(buf: Vec<u8>, cbs: usize, rstat: &mut ReadStat) -> Vec<Vec<u8>>
|
||||||
{
|
{
|
||||||
let mut blocks = buf.split(| &e | e == '\n' as u8)
|
let mut blocks = buf.split(| &e | e == '\n' as u8)
|
||||||
.fold(Vec::new(), | mut blocks, split |
|
.fold(Vec::new(), | mut blocks, split |
|
||||||
|
@ -610,7 +643,7 @@ fn block(buf: Vec<u8>, cbs: usize, rstats: &mut ReadStat) -> Vec<Vec<u8>>
|
||||||
let mut split = split.to_vec();
|
let mut split = split.to_vec();
|
||||||
if split.len() > cbs
|
if split.len() > cbs
|
||||||
{
|
{
|
||||||
rstats.records_truncated += 1;
|
rstat.records_truncated += 1;
|
||||||
}
|
}
|
||||||
split.resize(cbs, ' ' as u8);
|
split.resize(cbs, ' ' as u8);
|
||||||
blocks.push(split);
|
blocks.push(split);
|
||||||
|
@ -683,7 +716,7 @@ fn unblock(buf: Vec<u8>, cbs: usize) -> Vec<u8>
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn conv_block_unblock_helper<R: Read, W: Write>(mut buf: Vec<u8>, i: &mut Input<R>, o: &Output<W>, rstats: &mut ReadStat) -> Result<Vec<u8>, Box<dyn Error>>
|
fn conv_block_unblock_helper<R: Read, W: Write>(mut buf: Vec<u8>, i: &mut Input<R>, o: &Output<W>, rstat: &mut ReadStat) -> Result<Vec<u8>, Box<dyn Error>>
|
||||||
{
|
{
|
||||||
// Local Predicate Fns -------------------------------------------------
|
// Local Predicate Fns -------------------------------------------------
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -737,7 +770,7 @@ fn conv_block_unblock_helper<R: Read, W: Write>(mut buf: Vec<u8>, i: &mut Input<
|
||||||
{ // ascii input so perform the block first
|
{ // ascii input so perform the block first
|
||||||
let cbs = i.cflags.block.unwrap();
|
let cbs = i.cflags.block.unwrap();
|
||||||
|
|
||||||
let mut blocks = block(buf, cbs, rstats);
|
let mut blocks = block(buf, cbs, rstat);
|
||||||
|
|
||||||
if let Some(ct) = i.cflags.ctable
|
if let Some(ct) = i.cflags.ctable
|
||||||
{
|
{
|
||||||
|
@ -762,7 +795,7 @@ fn conv_block_unblock_helper<R: Read, W: Write>(mut buf: Vec<u8>, i: &mut Input<
|
||||||
apply_ct(&mut buf, &ct);
|
apply_ct(&mut buf, &ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
let blocks = block(buf, cbs, rstats)
|
let blocks = block(buf, cbs, rstat)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -860,7 +893,7 @@ fn read_helper<R: Read, W: Write>(i: &mut Input<R>, o: &mut Output<W>, bsize: us
|
||||||
{
|
{
|
||||||
// Read
|
// Read
|
||||||
let mut buf = vec![BUF_INIT_BYTE; bsize];
|
let mut buf = vec![BUF_INIT_BYTE; bsize];
|
||||||
let mut rstats = match i.cflags.sync
|
let mut rstat = match i.cflags.sync
|
||||||
{
|
{
|
||||||
Some(ch) =>
|
Some(ch) =>
|
||||||
i.fill_blocks(&mut buf, o.obs, ch)?,
|
i.fill_blocks(&mut buf, o.obs, ch)?,
|
||||||
|
@ -868,9 +901,9 @@ fn read_helper<R: Read, W: Write>(i: &mut Input<R>, o: &mut Output<W>, bsize: us
|
||||||
i.fill_consecutive(&mut buf)?,
|
i.fill_consecutive(&mut buf)?,
|
||||||
};
|
};
|
||||||
// Return early if no data
|
// Return early if no data
|
||||||
if rstats.reads_complete == 0 && rstats.reads_partial == 0
|
if rstat.reads_complete == 0 && rstat.reads_partial == 0
|
||||||
{
|
{
|
||||||
return Ok((rstats,buf));
|
return Ok((rstat,buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform any conv=x[,x...] options
|
// Perform any conv=x[,x...] options
|
||||||
|
@ -880,12 +913,12 @@ fn read_helper<R: Read, W: Write>(i: &mut Input<R>, o: &mut Output<W>, bsize: us
|
||||||
}
|
}
|
||||||
if is_conv(&i) || is_block(&i) || is_unblock(&i)
|
if is_conv(&i) || is_block(&i) || is_unblock(&i)
|
||||||
{
|
{
|
||||||
let buf = conv_block_unblock_helper(buf, i, o, &mut rstats)?;
|
let buf = conv_block_unblock_helper(buf, i, o, &mut rstat)?;
|
||||||
Ok((rstats, buf))
|
Ok((rstat, buf))
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Ok((rstats, buf))
|
Ok((rstat, buf))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -935,13 +968,13 @@ fn print_xfer_stats(update: &ProgUpdate)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a progress updater that tracks progress, receives updates, and TODO: responds to signals.
|
/// Generate a progress updater that tracks progress, receives updates, and responds to signals.
|
||||||
fn gen_prog_updater(rx: mpsc::Receiver<ProgUpdate>, xfer_stats: Option<StatusLevel>) -> impl Fn() -> ()
|
fn gen_prog_updater(rx: mpsc::Receiver<ProgUpdate>, xfer_stats: Option<StatusLevel>) -> impl Fn() -> ()
|
||||||
{
|
{
|
||||||
// --------------------------------------------------------------
|
// --------------------------------------------------------------
|
||||||
fn posixly_correct() -> bool
|
fn posixly_correct() -> bool
|
||||||
{
|
{
|
||||||
!env::var("POSIXLY_CORRECT").is_err()
|
env::var("POSIXLY_CORRECT").is_ok()
|
||||||
}
|
}
|
||||||
// --------------------------------------------------------------
|
// --------------------------------------------------------------
|
||||||
move || {
|
move || {
|
||||||
|
@ -951,7 +984,7 @@ fn gen_prog_updater(rx: mpsc::Receiver<ProgUpdate>, xfer_stats: Option<StatusLev
|
||||||
|
|
||||||
// TODO: SIGINFO seems to only exist for BSD (and therefore MACOS)
|
// TODO: SIGINFO seems to only exist for BSD (and therefore MACOS)
|
||||||
// I will probably want put this behind a feature-gate and may need to pass the value to handle as my own constant.
|
// I will probably want put this behind a feature-gate and may need to pass the value to handle as my own constant.
|
||||||
// This may involve some finagling with the library.
|
// This may involve some finagling with the signals library.
|
||||||
// see -> https://unix.stackexchange.com/questions/179481/siginfo-on-gnu-linux-arch-linux-missing
|
// see -> https://unix.stackexchange.com/questions/179481/siginfo-on-gnu-linux-arch-linux-missing
|
||||||
// if let Err(e) = signal_hook::flag::register_usize(signal::SIGINFO, sigval.clone(), signal::SIGINFO as usize)
|
// if let Err(e) = signal_hook::flag::register_usize(signal::SIGINFO, sigval.clone(), signal::SIGINFO as usize)
|
||||||
// {
|
// {
|
||||||
|
@ -980,12 +1013,9 @@ fn gen_prog_updater(rx: mpsc::Receiver<ProgUpdate>, xfer_stats: Option<StatusLev
|
||||||
{
|
{
|
||||||
update
|
update
|
||||||
},
|
},
|
||||||
(Err(e), _) =>
|
(Err(_), _) =>
|
||||||
{
|
// recv only fails permenantly
|
||||||
debug_println!("Internal dd Warning: Error in progress update thread\n\t{}", e);
|
break,
|
||||||
|
|
||||||
continue;
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
// Handle signals
|
// Handle signals
|
||||||
match sigval.load(Ordering::Relaxed)
|
match sigval.load(Ordering::Relaxed)
|
||||||
|
@ -1014,17 +1044,64 @@ fn calc_bsize(ibs: usize, obs: usize) -> usize
|
||||||
lcm
|
lcm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Calculate the buffer size appropriate for this loop iteration, respecting
|
||||||
|
/// a count=N if present.
|
||||||
|
fn calc_loop_bsize(count: &Option<CountType>, rstat: &ReadStat, wstat: &WriteStat, ibs: usize, ideal_bsize: usize) -> usize
|
||||||
|
{
|
||||||
|
match count
|
||||||
|
{
|
||||||
|
Some(CountType::Reads(rmax)) =>
|
||||||
|
{
|
||||||
|
let rmax: u64 = (*rmax).try_into().unwrap();
|
||||||
|
let rsofar = rstat.reads_complete + rstat.reads_partial;
|
||||||
|
let rremain: usize = (rmax - rsofar).try_into().unwrap();
|
||||||
|
cmp::min(ideal_bsize, rremain*ibs)
|
||||||
|
},
|
||||||
|
Some(CountType::Bytes(bmax)) =>
|
||||||
|
{
|
||||||
|
let bmax: u128 = (*bmax).try_into().unwrap();
|
||||||
|
let bremain: usize = (bmax - wstat.bytes_total).try_into().unwrap();
|
||||||
|
cmp::min(ideal_bsize, bremain)
|
||||||
|
},
|
||||||
|
None =>
|
||||||
|
ideal_bsize,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decide if the current progress is below a count=N limit or return
|
||||||
|
/// true if no such limit is set.
|
||||||
|
fn below_count_limit(count: &Option<CountType>, rstat: &ReadStat, wstat: &WriteStat) -> bool
|
||||||
|
{
|
||||||
|
match count
|
||||||
|
{
|
||||||
|
Some(CountType::Reads(n)) =>
|
||||||
|
{
|
||||||
|
let n = (*n).try_into().unwrap();
|
||||||
|
// debug_assert!(rstat.reads_complete + rstat.reads_partial >= n);
|
||||||
|
rstat.reads_complete + rstat.reads_partial <= n
|
||||||
|
},
|
||||||
|
Some(CountType::Bytes(n)) =>
|
||||||
|
{
|
||||||
|
let n = (*n).try_into().unwrap();
|
||||||
|
// debug_assert!(wstat.bytes_total >= n);
|
||||||
|
wstat.bytes_total <= n
|
||||||
|
},
|
||||||
|
None =>
|
||||||
|
true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Perform the copy/convert opertaions. Stdout version
|
/// Perform the copy/convert opertaions. Stdout version
|
||||||
// Note: Some of dd's functionality depends on whether the output is actually a file. This breaks the Output<Write> abstraction,
|
// Note: Some of dd's functionality depends on whether the output is actually a file. This breaks the Output<Write> abstraction,
|
||||||
// and should be fixed in the future.
|
// and should be fixed in the future.
|
||||||
fn dd_stdout<R: Read>(mut i: Input<R>, mut o: Output<io::Stdout>) -> Result<(), Box<dyn Error>>
|
fn dd_stdout<R: Read>(mut i: Input<R>, mut o: Output<io::Stdout>) -> Result<(), Box<dyn Error>>
|
||||||
{
|
{
|
||||||
let mut rstats = ReadStat {
|
let mut rstat = ReadStat {
|
||||||
reads_complete: 0,
|
reads_complete: 0,
|
||||||
reads_partial: 0,
|
reads_partial: 0,
|
||||||
records_truncated: 0,
|
records_truncated: 0,
|
||||||
};
|
};
|
||||||
let mut wstats = WriteStat {
|
let mut wstat = WriteStat {
|
||||||
writes_complete: 0,
|
writes_complete: 0,
|
||||||
writes_partial: 0,
|
writes_partial: 0,
|
||||||
bytes_total: 0,
|
bytes_total: 0,
|
||||||
|
@ -1038,37 +1115,30 @@ fn dd_stdout<R: Read>(mut i: Input<R>, mut o: Output<io::Stdout>) -> Result<(),
|
||||||
tx
|
tx
|
||||||
};
|
};
|
||||||
|
|
||||||
loop
|
while below_count_limit(&i.count, &rstat, &wstat)
|
||||||
{
|
{
|
||||||
// Read/Write
|
// Read/Write
|
||||||
match read_helper(&mut i, &mut o, bsize)?
|
let loop_bsize = calc_loop_bsize(&i.count, &rstat, &wstat, i.ibs, bsize);
|
||||||
|
match read_helper(&mut i, &mut o, loop_bsize)?
|
||||||
{
|
{
|
||||||
(ReadStat { reads_complete: 0, reads_partial: 0, .. }, _) =>
|
(ReadStat { reads_complete: 0, reads_partial: 0, .. }, _) =>
|
||||||
break,
|
break,
|
||||||
(rstat_update, buf) =>
|
(rstat_update, buf) =>
|
||||||
{
|
{
|
||||||
let wstats_update = o.write_blocks(buf)?;
|
let wstat_update = o.write_blocks(buf)?;
|
||||||
|
|
||||||
rstats = ReadStat {
|
rstat += rstat_update;
|
||||||
reads_complete: rstats.reads_complete + rstat_update.reads_complete,
|
wstat += wstat_update;
|
||||||
reads_partial: rstats.reads_partial + rstat_update.reads_partial,
|
},
|
||||||
records_truncated: rstats.records_truncated + rstat_update.records_truncated,
|
|
||||||
};
|
|
||||||
wstats = WriteStat {
|
|
||||||
writes_complete: wstats.writes_complete + wstats_update.writes_complete,
|
|
||||||
writes_partial: wstats.writes_partial + wstats_update.writes_partial,
|
|
||||||
bytes_total: wstats.bytes_total + wstats_update.bytes_total,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
// Update Prog
|
// Update Prog
|
||||||
prog_tx.send(ProgUpdate {
|
prog_tx.send(ProgUpdate {
|
||||||
reads_complete: rstats.reads_complete,
|
reads_complete: rstat.reads_complete,
|
||||||
reads_partial: rstats.reads_partial,
|
reads_partial: rstat.reads_partial,
|
||||||
writes_complete: wstats.writes_complete,
|
writes_complete: wstat.writes_complete,
|
||||||
writes_partial: wstats.writes_partial,
|
writes_partial: wstat.writes_partial,
|
||||||
bytes_total: wstats.bytes_total,
|
bytes_total: wstat.bytes_total,
|
||||||
records_truncated: rstats.records_truncated,
|
records_truncated: rstat.records_truncated,
|
||||||
duration: start.elapsed(),
|
duration: start.elapsed(),
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
@ -1088,12 +1158,12 @@ fn dd_stdout<R: Read>(mut i: Input<R>, mut o: Output<io::Stdout>) -> Result<(),
|
||||||
Some(StatusLevel::None) => {},
|
Some(StatusLevel::None) => {},
|
||||||
_ =>
|
_ =>
|
||||||
print_xfer_stats(&ProgUpdate {
|
print_xfer_stats(&ProgUpdate {
|
||||||
reads_complete: rstats.reads_complete,
|
reads_complete: rstat.reads_complete,
|
||||||
reads_partial: rstats.reads_partial,
|
reads_partial: rstat.reads_partial,
|
||||||
writes_complete: wstats.writes_complete,
|
writes_complete: wstat.writes_complete,
|
||||||
writes_partial: wstats.writes_partial,
|
writes_partial: wstat.writes_partial,
|
||||||
bytes_total: wstats.bytes_total,
|
bytes_total: wstat.bytes_total,
|
||||||
records_truncated: rstats.records_truncated,
|
records_truncated: rstat.records_truncated,
|
||||||
duration: start.elapsed(),
|
duration: start.elapsed(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
@ -1105,12 +1175,12 @@ fn dd_stdout<R: Read>(mut i: Input<R>, mut o: Output<io::Stdout>) -> Result<(),
|
||||||
// and should be fixed in the future.
|
// and should be fixed in the future.
|
||||||
fn dd_fileout<R: Read>(mut i: Input<R>, mut o: Output<File>) -> Result<(), Box<dyn Error>>
|
fn dd_fileout<R: Read>(mut i: Input<R>, mut o: Output<File>) -> Result<(), Box<dyn Error>>
|
||||||
{
|
{
|
||||||
let mut rstats = ReadStat {
|
let mut rstat = ReadStat {
|
||||||
reads_complete: 0,
|
reads_complete: 0,
|
||||||
reads_partial: 0,
|
reads_partial: 0,
|
||||||
records_truncated: 0,
|
records_truncated: 0,
|
||||||
};
|
};
|
||||||
let mut wstats = WriteStat {
|
let mut wstat = WriteStat {
|
||||||
writes_complete: 0,
|
writes_complete: 0,
|
||||||
writes_partial: 0,
|
writes_partial: 0,
|
||||||
bytes_total: 0,
|
bytes_total: 0,
|
||||||
|
@ -1124,37 +1194,30 @@ fn dd_fileout<R: Read>(mut i: Input<R>, mut o: Output<File>) -> Result<(), Box<d
|
||||||
tx
|
tx
|
||||||
};
|
};
|
||||||
|
|
||||||
loop
|
while below_count_limit(&i.count, &rstat, &wstat)
|
||||||
{
|
{
|
||||||
// Read/Write
|
// Read/Write
|
||||||
match read_helper(&mut i, &mut o, bsize)?
|
let loop_bsize = calc_loop_bsize(&i.count, &rstat, &wstat, i.ibs, bsize);
|
||||||
|
match read_helper(&mut i, &mut o, loop_bsize)?
|
||||||
{
|
{
|
||||||
(ReadStat { reads_complete: 0, reads_partial: 0, .. }, _) =>
|
(ReadStat { reads_complete: 0, reads_partial: 0, .. }, _) =>
|
||||||
break,
|
break,
|
||||||
(rstat_update, buf) =>
|
(rstat_update, buf) =>
|
||||||
{
|
{
|
||||||
let wstats_update = o.write_blocks(buf)?;
|
let wstat_update = o.write_blocks(buf)?;
|
||||||
|
|
||||||
rstats = ReadStat {
|
rstat += rstat_update;
|
||||||
reads_complete: rstats.reads_complete + rstat_update.reads_complete,
|
wstat += wstat_update;
|
||||||
reads_partial: rstats.reads_partial + rstat_update.reads_partial,
|
|
||||||
records_truncated: rstats.records_truncated + rstat_update.records_truncated,
|
|
||||||
};
|
|
||||||
wstats = WriteStat {
|
|
||||||
writes_complete: wstats.writes_complete + wstats_update.writes_complete,
|
|
||||||
writes_partial: wstats.writes_partial + wstats_update.writes_partial,
|
|
||||||
bytes_total: wstats.bytes_total + wstats_update.bytes_total,
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
// Update Prog
|
// Update Prog
|
||||||
prog_tx.send(ProgUpdate {
|
prog_tx.send(ProgUpdate {
|
||||||
reads_complete: rstats.reads_complete,
|
reads_complete: rstat.reads_complete,
|
||||||
reads_partial: rstats.reads_partial,
|
reads_partial: rstat.reads_partial,
|
||||||
writes_complete: wstats.writes_complete,
|
writes_complete: wstat.writes_complete,
|
||||||
writes_partial: wstats.writes_partial,
|
writes_partial: wstat.writes_partial,
|
||||||
bytes_total: wstats.bytes_total,
|
bytes_total: wstat.bytes_total,
|
||||||
records_truncated: rstats.records_truncated,
|
records_truncated: rstat.records_truncated,
|
||||||
duration: start.elapsed(),
|
duration: start.elapsed(),
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
@ -1174,12 +1237,12 @@ fn dd_fileout<R: Read>(mut i: Input<R>, mut o: Output<File>) -> Result<(), Box<d
|
||||||
Some(StatusLevel::None) => {},
|
Some(StatusLevel::None) => {},
|
||||||
_ =>
|
_ =>
|
||||||
print_xfer_stats(&ProgUpdate {
|
print_xfer_stats(&ProgUpdate {
|
||||||
reads_complete: rstats.reads_complete,
|
reads_complete: rstat.reads_complete,
|
||||||
reads_partial: rstats.reads_partial,
|
reads_partial: rstat.reads_partial,
|
||||||
writes_complete: wstats.writes_complete,
|
writes_complete: wstat.writes_complete,
|
||||||
writes_partial: wstats.writes_partial,
|
writes_partial: wstat.writes_partial,
|
||||||
bytes_total: wstats.bytes_total,
|
bytes_total: wstat.bytes_total,
|
||||||
records_truncated: rstats.records_truncated,
|
records_truncated: rstat.records_truncated,
|
||||||
duration: start.elapsed(),
|
duration: start.elapsed(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ macro_rules! make_block_test (
|
||||||
non_ascii: false,
|
non_ascii: false,
|
||||||
ibs: 512,
|
ibs: 512,
|
||||||
xfer_stats: None,
|
xfer_stats: None,
|
||||||
|
count: None,
|
||||||
cflags: IConvFlags {
|
cflags: IConvFlags {
|
||||||
ctable: None,
|
ctable: None,
|
||||||
block: $block,
|
block: $block,
|
||||||
|
@ -56,6 +57,7 @@ macro_rules! make_unblock_test (
|
||||||
non_ascii: false,
|
non_ascii: false,
|
||||||
ibs: 512,
|
ibs: 512,
|
||||||
xfer_stats: None,
|
xfer_stats: None,
|
||||||
|
count: None,
|
||||||
cflags: IConvFlags {
|
cflags: IConvFlags {
|
||||||
ctable: None,
|
ctable: None,
|
||||||
block: None,
|
block: None,
|
||||||
|
|
|
@ -24,6 +24,7 @@ macro_rules! make_sync_test (
|
||||||
non_ascii: false,
|
non_ascii: false,
|
||||||
ibs: $ibs,
|
ibs: $ibs,
|
||||||
xfer_stats: None,
|
xfer_stats: None,
|
||||||
|
count: None,
|
||||||
cflags: IConvFlags {
|
cflags: IConvFlags {
|
||||||
ctable: None,
|
ctable: None,
|
||||||
block: None,
|
block: None,
|
||||||
|
|
|
@ -10,6 +10,7 @@ macro_rules! make_conv_test (
|
||||||
non_ascii: false,
|
non_ascii: false,
|
||||||
ibs: 512,
|
ibs: 512,
|
||||||
xfer_stats: None,
|
xfer_stats: None,
|
||||||
|
count: None,
|
||||||
cflags: icf!($ctable),
|
cflags: icf!($ctable),
|
||||||
iflags: DEFAULT_IFLAGS,
|
iflags: DEFAULT_IFLAGS,
|
||||||
},
|
},
|
||||||
|
@ -35,6 +36,7 @@ macro_rules! make_icf_test (
|
||||||
non_ascii: false,
|
non_ascii: false,
|
||||||
ibs: 512,
|
ibs: 512,
|
||||||
xfer_stats: None,
|
xfer_stats: None,
|
||||||
|
count: None,
|
||||||
cflags: $icf,
|
cflags: $icf,
|
||||||
iflags: DEFAULT_IFLAGS,
|
iflags: DEFAULT_IFLAGS,
|
||||||
},
|
},
|
||||||
|
@ -138,6 +140,7 @@ fn all_valid_ascii_ebcdic_ascii_roundtrip_conv_test()
|
||||||
non_ascii: false,
|
non_ascii: false,
|
||||||
ibs: 128,
|
ibs: 128,
|
||||||
xfer_stats: None,
|
xfer_stats: None,
|
||||||
|
count: None,
|
||||||
cflags: icf!(Some(&ASCII_TO_EBCDIC)),
|
cflags: icf!(Some(&ASCII_TO_EBCDIC)),
|
||||||
iflags: DEFAULT_IFLAGS,
|
iflags: DEFAULT_IFLAGS,
|
||||||
};
|
};
|
||||||
|
@ -160,6 +163,7 @@ fn all_valid_ascii_ebcdic_ascii_roundtrip_conv_test()
|
||||||
non_ascii: false,
|
non_ascii: false,
|
||||||
ibs: 256,
|
ibs: 256,
|
||||||
xfer_stats: None,
|
xfer_stats: None,
|
||||||
|
count: None,
|
||||||
cflags: icf!(Some(&EBCDIC_TO_ASCII)),
|
cflags: icf!(Some(&EBCDIC_TO_ASCII)),
|
||||||
iflags: DEFAULT_IFLAGS,
|
iflags: DEFAULT_IFLAGS,
|
||||||
};
|
};
|
||||||
|
|
|
@ -95,6 +95,7 @@ macro_rules! make_spec_test (
|
||||||
non_ascii: false,
|
non_ascii: false,
|
||||||
ibs: 512,
|
ibs: 512,
|
||||||
xfer_stats: None,
|
xfer_stats: None,
|
||||||
|
count: None,
|
||||||
cflags: icf!(),
|
cflags: icf!(),
|
||||||
iflags: DEFAULT_IFLAGS,
|
iflags: DEFAULT_IFLAGS,
|
||||||
},
|
},
|
||||||
|
@ -116,11 +117,13 @@ macro_rules! make_spec_test (
|
||||||
dd_fileout($i,$o).unwrap();
|
dd_fileout($i,$o).unwrap();
|
||||||
|
|
||||||
let res = File::open($tmp_fname).unwrap();
|
let res = File::open($tmp_fname).unwrap();
|
||||||
|
// Check test file isn't empty (unless spec file is too)
|
||||||
assert_eq!(res.metadata().unwrap().len(), $spec.metadata().unwrap().len());
|
assert_eq!(res.metadata().unwrap().len(), $spec.metadata().unwrap().len());
|
||||||
|
|
||||||
let spec = BufReader::new($spec);
|
let spec = BufReader::new($spec);
|
||||||
let res = BufReader::new(res);
|
let res = BufReader::new(res);
|
||||||
|
|
||||||
|
// Check all bytes match
|
||||||
for (b_res, b_spec) in res.bytes().zip(spec.bytes())
|
for (b_res, b_spec) in res.bytes().zip(spec.bytes())
|
||||||
{
|
{
|
||||||
assert_eq!(b_res.unwrap(),
|
assert_eq!(b_res.unwrap(),
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
const DST_PLACEHOLDER: Vec<u8> = Vec::new();
|
||||||
|
|
||||||
|
macro_rules! make_io_test (
|
||||||
|
( $test_id:ident, $test_name:expr, $i:expr, $o:expr, $spec:expr ) =>
|
||||||
|
{
|
||||||
|
make_spec_test!($test_id,
|
||||||
|
$test_name,
|
||||||
|
$i,
|
||||||
|
Output {
|
||||||
|
dst: File::create(format!("./test-resources/FAILED-{}.test", $test_name)).unwrap(),
|
||||||
|
obs: $o.obs,
|
||||||
|
cflags: $o.cflags,
|
||||||
|
oflags: $o.oflags,
|
||||||
|
},
|
||||||
|
$spec,
|
||||||
|
format!("./test-resources/FAILED-{}.test", $test_name)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
);
|
||||||
|
|
||||||
make_spec_test!(
|
make_spec_test!(
|
||||||
zeros_4k_test,
|
zeros_4k_test,
|
||||||
"zeros-4k",
|
"zeros-4k",
|
||||||
|
@ -24,7 +44,7 @@ make_spec_test!(
|
||||||
File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap()
|
File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap()
|
||||||
);
|
);
|
||||||
|
|
||||||
make_spec_test!(
|
make_io_test!(
|
||||||
random_73k_test_not_a_multiple_obs_gt_ibs,
|
random_73k_test_not_a_multiple_obs_gt_ibs,
|
||||||
"random-73k-not-a-multiple-obs-gt-ibs",
|
"random-73k-not-a-multiple-obs-gt-ibs",
|
||||||
Input {
|
Input {
|
||||||
|
@ -32,20 +52,20 @@ make_spec_test!(
|
||||||
non_ascii: false,
|
non_ascii: false,
|
||||||
ibs: 521,
|
ibs: 521,
|
||||||
xfer_stats: None,
|
xfer_stats: None,
|
||||||
|
count: None,
|
||||||
cflags: icf!(),
|
cflags: icf!(),
|
||||||
iflags: DEFAULT_IFLAGS,
|
iflags: DEFAULT_IFLAGS,
|
||||||
},
|
},
|
||||||
Output {
|
Output {
|
||||||
dst: File::create(format!("./test-resources/FAILED-{}.test", "random-73k-not-a-multiple-obs-gt-ibs")).unwrap(),
|
dst: DST_PLACEHOLDER,
|
||||||
obs: 1031,
|
obs: 1031,
|
||||||
cflags: DEFAULT_CFO,
|
cflags: DEFAULT_CFO,
|
||||||
oflags: DEFAULT_OFLAGS,
|
oflags: DEFAULT_OFLAGS,
|
||||||
},
|
},
|
||||||
File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap(),
|
File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap()
|
||||||
format!("./test-resources/FAILED-{}.test", "random-73k-not-a-multiple-obs-gt-ibs")
|
|
||||||
);
|
);
|
||||||
|
|
||||||
make_spec_test!(
|
make_io_test!(
|
||||||
random_73k_test_obs_lt_not_a_multiple_ibs,
|
random_73k_test_obs_lt_not_a_multiple_ibs,
|
||||||
"random-73k-obs-lt-not-a-multiple-ibs",
|
"random-73k-obs-lt-not-a-multiple-ibs",
|
||||||
Input {
|
Input {
|
||||||
|
@ -53,17 +73,143 @@ make_spec_test!(
|
||||||
non_ascii: false,
|
non_ascii: false,
|
||||||
ibs: 1031,
|
ibs: 1031,
|
||||||
xfer_stats: None,
|
xfer_stats: None,
|
||||||
|
count: None,
|
||||||
cflags: icf!(),
|
cflags: icf!(),
|
||||||
iflags: DEFAULT_IFLAGS,
|
iflags: DEFAULT_IFLAGS,
|
||||||
},
|
},
|
||||||
Output {
|
Output {
|
||||||
dst: File::create(format!("./test-resources/FAILED-{}.test", "random-73k-obs-lt-not-a-multiple-ibs")).unwrap(),
|
dst: DST_PLACEHOLDER,
|
||||||
obs: 521,
|
obs: 521,
|
||||||
cflags: DEFAULT_CFO,
|
cflags: DEFAULT_CFO,
|
||||||
oflags: DEFAULT_OFLAGS,
|
oflags: DEFAULT_OFLAGS,
|
||||||
},
|
},
|
||||||
File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap(),
|
File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap()
|
||||||
format!("./test-resources/FAILED-{}.test", "random-73k-obs-lt-not-a-multiple-ibs")
|
);
|
||||||
|
|
||||||
|
make_io_test!(
|
||||||
|
deadbeef_all_32k_test_count_reads,
|
||||||
|
"deadbeef_all_32k_test_count_reads",
|
||||||
|
Input {
|
||||||
|
src: File::open("./test-resources/deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test").unwrap(),
|
||||||
|
non_ascii: false,
|
||||||
|
ibs: 1024,
|
||||||
|
xfer_stats: None,
|
||||||
|
count: Some(CountType::Reads(32)),
|
||||||
|
cflags: icf!(),
|
||||||
|
iflags: DEFAULT_IFLAGS,
|
||||||
|
},
|
||||||
|
Output {
|
||||||
|
dst: DST_PLACEHOLDER,
|
||||||
|
obs: 1024,
|
||||||
|
cflags: DEFAULT_CFO,
|
||||||
|
oflags: DEFAULT_OFLAGS,
|
||||||
|
},
|
||||||
|
File::open("./test-resources/deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test").unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
make_io_test!(
|
||||||
|
deadbeef_all_32k_test_count_bytes,
|
||||||
|
"deadbeef_all_32k_test_count_bytes",
|
||||||
|
Input {
|
||||||
|
src: File::open("./test-resources/deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test").unwrap(),
|
||||||
|
non_ascii: false,
|
||||||
|
ibs: 531,
|
||||||
|
xfer_stats: None,
|
||||||
|
count: Some(CountType::Bytes(32*1024)),
|
||||||
|
cflags: icf!(),
|
||||||
|
iflags: DEFAULT_IFLAGS,
|
||||||
|
},
|
||||||
|
Output {
|
||||||
|
dst: DST_PLACEHOLDER,
|
||||||
|
obs: 1031,
|
||||||
|
cflags: DEFAULT_CFO,
|
||||||
|
oflags: DEFAULT_OFLAGS,
|
||||||
|
},
|
||||||
|
File::open("./test-resources/deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test").unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
make_io_test!(
|
||||||
|
deadbeef_32k_to_16k_test_count_reads,
|
||||||
|
"deadbeef_32k_test_count_reads",
|
||||||
|
Input {
|
||||||
|
src: File::open("./test-resources/deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test").unwrap(),
|
||||||
|
non_ascii: false,
|
||||||
|
ibs: 1024,
|
||||||
|
xfer_stats: None,
|
||||||
|
count: Some(CountType::Reads(16)),
|
||||||
|
cflags: icf!(),
|
||||||
|
iflags: DEFAULT_IFLAGS,
|
||||||
|
},
|
||||||
|
Output {
|
||||||
|
dst: DST_PLACEHOLDER,
|
||||||
|
obs: 1031,
|
||||||
|
cflags: DEFAULT_CFO,
|
||||||
|
oflags: DEFAULT_OFLAGS,
|
||||||
|
},
|
||||||
|
File::open("./test-resources/gnudd-deadbeef-first-16k.spec").unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
make_io_test!(
|
||||||
|
deadbeef_32k_to_12345_test_count_bytes,
|
||||||
|
"deadbeef_32k_to_12345_test_count_bytes",
|
||||||
|
Input {
|
||||||
|
src: File::open("./test-resources/deadbeef-18d99661a1de1fc9af21b0ec2cd67ba3.test").unwrap(),
|
||||||
|
non_ascii: false,
|
||||||
|
ibs: 531,
|
||||||
|
xfer_stats: None,
|
||||||
|
count: Some(CountType::Bytes(12345)),
|
||||||
|
cflags: icf!(),
|
||||||
|
iflags: DEFAULT_IFLAGS,
|
||||||
|
},
|
||||||
|
Output {
|
||||||
|
dst: DST_PLACEHOLDER,
|
||||||
|
obs: 1031,
|
||||||
|
cflags: DEFAULT_CFO,
|
||||||
|
oflags: DEFAULT_OFLAGS,
|
||||||
|
},
|
||||||
|
File::open("./test-resources/gnudd-deadbeef-first-12345.spec").unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
make_io_test!(
|
||||||
|
random_73k_test_count_reads,
|
||||||
|
"random-73k-test-count-reads",
|
||||||
|
Input {
|
||||||
|
src: File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap(),
|
||||||
|
non_ascii: false,
|
||||||
|
ibs: 1024,
|
||||||
|
xfer_stats: None,
|
||||||
|
count: Some(CountType::Reads(32)),
|
||||||
|
cflags: icf!(),
|
||||||
|
iflags: DEFAULT_IFLAGS,
|
||||||
|
},
|
||||||
|
Output {
|
||||||
|
dst: DST_PLACEHOLDER,
|
||||||
|
obs: 1024,
|
||||||
|
cflags: DEFAULT_CFO,
|
||||||
|
oflags: DEFAULT_OFLAGS,
|
||||||
|
},
|
||||||
|
File::open("./test-resources/gnudd-random-first-32k.spec").unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
make_io_test!(
|
||||||
|
random_73k_test_count_bytes,
|
||||||
|
"random-73k-test-count-bytes",
|
||||||
|
Input {
|
||||||
|
src: File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap(),
|
||||||
|
non_ascii: false,
|
||||||
|
ibs: 521,
|
||||||
|
xfer_stats: None,
|
||||||
|
count: Some(CountType::Bytes(32*1024)),
|
||||||
|
cflags: icf!(),
|
||||||
|
iflags: DEFAULT_IFLAGS,
|
||||||
|
},
|
||||||
|
Output {
|
||||||
|
dst: DST_PLACEHOLDER,
|
||||||
|
obs: 1031,
|
||||||
|
cflags: DEFAULT_CFO,
|
||||||
|
oflags: DEFAULT_OFLAGS,
|
||||||
|
},
|
||||||
|
File::open("./test-resources/gnudd-random-first-32k.spec").unwrap()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test internal buffer size fn
|
// Test internal buffer size fn
|
||||||
|
|
|
@ -3,6 +3,7 @@ mod unit_tests;
|
||||||
|
|
||||||
use crate::conversion_tables::*;
|
use crate::conversion_tables::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
CountType,
|
||||||
IConvFlags, OConvFlags,
|
IConvFlags, OConvFlags,
|
||||||
StatusLevel,
|
StatusLevel,
|
||||||
};
|
};
|
||||||
|
@ -759,6 +760,27 @@ 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<Option<CountType>, ParseError>
|
||||||
|
{
|
||||||
|
if let Some(amt) = matches.opt_str("count")
|
||||||
|
{
|
||||||
|
let n = parse_bytes_with_opt_multiplier(amt)?;
|
||||||
|
if iflags.count_bytes
|
||||||
|
{
|
||||||
|
Ok(Some(CountType::Bytes(n)))
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Ok(Some(CountType::Reads(n)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse whether the args indicate the input is not ascii
|
/// Parse whether the args indicate the input is not ascii
|
||||||
pub fn parse_input_non_ascii(matches: &getopts::Matches) -> Result<bool, ParseError>
|
pub fn parse_input_non_ascii(matches: &getopts::Matches) -> Result<bool, ParseError>
|
||||||
{
|
{
|
||||||
|
|
1
src/uu/dd/test-resources/gnudd-deadbeef-first-12345.spec
Normal file
1
src/uu/dd/test-resources/gnudd-deadbeef-first-12345.spec
Normal file
File diff suppressed because one or more lines are too long
1
src/uu/dd/test-resources/gnudd-deadbeef-first-16k.spec
Normal file
1
src/uu/dd/test-resources/gnudd-deadbeef-first-16k.spec
Normal file
File diff suppressed because one or more lines are too long
BIN
src/uu/dd/test-resources/gnudd-random-first-32k.spec
Normal file
BIN
src/uu/dd/test-resources/gnudd-random-first-32k.spec
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue