mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2026-01-19 19:51:09 +00:00
Fixes bugs. Prepares for conv=sync
- Splits read fn into conv=sync and standard (consecutive) versions. - Fixes bug in previous read/fill where short reads would copy to wrong position in output buffer. - Fixes bug in unit tests. Empty source would pass (since no bytes failed to match).
This commit is contained in:
parent
787b9696cb
commit
f7eaf96eda
7 changed files with 117 additions and 62 deletions
|
|
@ -36,27 +36,23 @@ const SYNTAX: &str = "dd [OPERAND]...\ndd OPTION";
|
|||
const SUMMARY: &str = "convert, and optionally copy, a file";
|
||||
const LONG_HELP: &str = "";
|
||||
|
||||
const DEFAULT_FILL_BYTE: u8 = 0xDD;
|
||||
const DEFAULT_SKIP_TRIES: u8 = 3;
|
||||
const DEFAULT_INIT_BYTE: u8 = 0xDD;
|
||||
|
||||
const RTN_SUCCESS: i32 = 0;
|
||||
const RTN_FAILURE: i32 = 1;
|
||||
|
||||
// ----- Datatypes -----
|
||||
enum SrcStat
|
||||
{
|
||||
Read(usize),
|
||||
EOF,
|
||||
}
|
||||
|
||||
type Cbs = usize;
|
||||
|
||||
/// Stores all Conv Flags that apply to the input
|
||||
pub struct IConvFlags
|
||||
{
|
||||
ctable: Option<&'static ConversionTable>,
|
||||
block: Option<usize>,
|
||||
unblock: Option<usize>,
|
||||
block: Option<Cbs>,
|
||||
unblock: Option<Cbs>,
|
||||
swab: bool,
|
||||
sync: bool,
|
||||
sync: Option<u8>,
|
||||
noerror: bool,
|
||||
}
|
||||
|
||||
|
|
@ -179,7 +175,7 @@ impl Input<io::Stdin>
|
|||
|
||||
if let Some(amt) = skip
|
||||
{
|
||||
let mut buf = vec![DEFAULT_FILL_BYTE; amt];
|
||||
let mut buf = vec![DEFAULT_INIT_BYTE; amt];
|
||||
|
||||
i.force_fill(&mut buf, amt)?;
|
||||
}
|
||||
|
|
@ -233,43 +229,64 @@ impl<R: Read> Read for Input<R>
|
|||
fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize>
|
||||
{
|
||||
// Read from source, ignore read errors if conv=noerror
|
||||
let len = match self.src.read(&mut buf)
|
||||
match self.src.read(&mut buf)
|
||||
{
|
||||
Ok(len) =>
|
||||
len,
|
||||
Ok(len),
|
||||
Err(e) =>
|
||||
if !self.cflags.noerror
|
||||
{
|
||||
return Err(e);
|
||||
Err(e)
|
||||
}
|
||||
else
|
||||
{
|
||||
return Ok(0);
|
||||
Ok(0)
|
||||
},
|
||||
};
|
||||
|
||||
Ok(len)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read> Input<R>
|
||||
{
|
||||
/// Fills to a given size n, which is expected to be 'obs'.
|
||||
/// Fills a given obs-sized buffer.
|
||||
/// Reads in increments of 'self.ibs'.
|
||||
fn fill_n(&mut self, buf: &mut [u8], obs: usize) -> Result<usize, Box<dyn Error>>
|
||||
fn fill_consecutive(&mut self, buf: &mut [u8]) -> Result<usize, Box<dyn Error>>
|
||||
{
|
||||
let mut base_idx = 0;
|
||||
|
||||
while base_idx < buf.len()
|
||||
{
|
||||
let low_idx = base_idx;
|
||||
let up_idx = cmp::min(low_idx+self.ibs, buf.len()-1);
|
||||
|
||||
let rlen = self.read(&mut buf[low_idx..=up_idx])?;
|
||||
if rlen > 0
|
||||
{
|
||||
base_idx += rlen;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(base_idx)
|
||||
}
|
||||
|
||||
/// Fills a given obs-sized buffer.
|
||||
/// Reads in increments of 'self.ibs'.
|
||||
fn fill_blocks(&mut self, buf: &mut [u8]) -> Result<usize, Box<dyn Error>>
|
||||
{
|
||||
let ibs = self.ibs;
|
||||
let obs = buf.len();
|
||||
let mut bytes_read = 0;
|
||||
|
||||
// TODO: Fix this!
|
||||
// assert!(obs < ibs);
|
||||
|
||||
for n in 0..(obs/ibs) {
|
||||
for n in 0..cmp::max(obs/ibs, 1) {
|
||||
// fill an ibs-len slice from src
|
||||
let this_read = self.read(&mut buf[n*ibs..(n+1)*ibs])?;
|
||||
let rlen = self.read(&mut buf[n*ibs..(n+1)*ibs])?;
|
||||
|
||||
if this_read != 0 {
|
||||
bytes_read += this_read;
|
||||
if rlen != 0 {
|
||||
bytes_read += rlen;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
|
@ -691,13 +708,20 @@ fn read_write_helper<R: Read, W: Write>(i: &mut Input<R>, o: &mut Output<W>) ->
|
|||
else
|
||||
{
|
||||
// Read
|
||||
let mut buf = vec![DEFAULT_FILL_BYTE; o.obs];
|
||||
let rlen = i.fill_n(&mut buf, o.obs)?;
|
||||
buf.resize(rlen, DEFAULT_FILL_BYTE);
|
||||
let mut buf = vec![DEFAULT_INIT_BYTE; o.obs];
|
||||
let rlen = if let Some(ch) = i.cflags.sync
|
||||
{
|
||||
i.fill_blocks(&mut buf)?
|
||||
}
|
||||
else
|
||||
{
|
||||
i.fill_consecutive(&mut buf)?
|
||||
};
|
||||
buf.truncate(rlen);
|
||||
|
||||
if rlen == 0
|
||||
{
|
||||
return Ok((0,Vec::new()));
|
||||
return Ok((0,buf));
|
||||
}
|
||||
|
||||
// Conv etc...
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ macro_rules! make_block_test (
|
|||
block: $block,
|
||||
unblock: None,
|
||||
swab: false,
|
||||
sync: false,
|
||||
sync: None,
|
||||
noerror: false,
|
||||
},
|
||||
iflags: DEFAULT_IFLAGS,
|
||||
|
|
@ -50,7 +50,7 @@ macro_rules! make_unblock_test (
|
|||
block: None,
|
||||
unblock: $unblock,
|
||||
swab: false,
|
||||
sync: false,
|
||||
sync: None,
|
||||
noerror: false,
|
||||
},
|
||||
iflags: DEFAULT_IFLAGS,
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ make_icf_test!(
|
|||
block: None,
|
||||
unblock: None,
|
||||
swab: true,
|
||||
sync: false,
|
||||
sync: None,
|
||||
noerror: false,
|
||||
},
|
||||
File::open("./test-resources/seq-byte-values-swapped.test").unwrap()
|
||||
|
|
@ -216,7 +216,7 @@ make_icf_test!(
|
|||
block: None,
|
||||
unblock: None,
|
||||
swab: true,
|
||||
sync: false,
|
||||
sync: None,
|
||||
noerror: false,
|
||||
},
|
||||
File::open("./test-resources/seq-byte-values-odd.spec").unwrap()
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use super::*;
|
|||
mod sanity_tests;
|
||||
mod conversion_tests;
|
||||
mod block_unblock_tests;
|
||||
mod conv_sync_tests;
|
||||
|
||||
use std::io::prelude::*;
|
||||
use std::io::BufReader;
|
||||
|
|
@ -72,7 +73,7 @@ macro_rules! icf (
|
|||
block: None,
|
||||
unblock: None,
|
||||
swab: false,
|
||||
sync: false,
|
||||
sync: None,
|
||||
noerror: false,
|
||||
}
|
||||
};
|
||||
|
|
@ -115,9 +116,10 @@ macro_rules! make_spec_test (
|
|||
dd_fileout($i,$o).unwrap();
|
||||
|
||||
let res = File::open($tmp_fname).unwrap();
|
||||
let res = BufReader::new(res);
|
||||
assert_eq!(res.metadata().unwrap().len(), $spec.metadata().unwrap().len());
|
||||
|
||||
let spec = BufReader::new($spec);
|
||||
let res = BufReader::new(res);
|
||||
|
||||
for (b_res, b_spec) in res.bytes().zip(spec.bytes())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,3 +23,45 @@ make_spec_test!(
|
|||
"random-73k",
|
||||
File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap()
|
||||
);
|
||||
|
||||
make_spec_test!(
|
||||
random_73k_test_not_a_multiple_obs_gt_ibs,
|
||||
"random-73k-not-a-multiple-obs-gt-ibs",
|
||||
Input {
|
||||
src: File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap(),
|
||||
non_ascii: false,
|
||||
ibs: 521,
|
||||
xfer_stats: StatusLevel::None,
|
||||
cflags: icf!(),
|
||||
iflags: DEFAULT_IFLAGS,
|
||||
},
|
||||
Output {
|
||||
dst: File::create(format!("./test-resources/FAILED-{}.test", "random-73k-not-a-multiple-obs-gt-ibs")).unwrap(),
|
||||
obs: 1031,
|
||||
cflags: DEFAULT_CFO,
|
||||
oflags: DEFAULT_OFLAGS,
|
||||
},
|
||||
File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap(),
|
||||
format!("./test-resources/FAILED-{}.test", "random-73k-not-a-multiple-obs-gt-ibs")
|
||||
);
|
||||
|
||||
make_spec_test!(
|
||||
random_73k_test_obs_lt_not_a_multiple_ibs,
|
||||
"random-73k-obs-lt-not-a-multiple-ibs",
|
||||
Input {
|
||||
src: File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap(),
|
||||
non_ascii: false,
|
||||
ibs: 1031,
|
||||
xfer_stats: StatusLevel::None,
|
||||
cflags: icf!(),
|
||||
iflags: DEFAULT_IFLAGS,
|
||||
},
|
||||
Output {
|
||||
dst: File::create(format!("./test-resources/FAILED-{}.test", "random-73k-obs-lt-not-a-multiple-ibs")).unwrap(),
|
||||
obs: 521,
|
||||
cflags: DEFAULT_CFO,
|
||||
oflags: DEFAULT_OFLAGS,
|
||||
},
|
||||
File::open("./test-resources/random-5828891cb1230748e146f34223bbd3b5.test").unwrap(),
|
||||
format!("./test-resources/FAILED-{}.test", "random-73k-obs-lt-not-a-multiple-ibs")
|
||||
);
|
||||
|
|
|
|||
|
|
@ -475,6 +475,18 @@ pub fn parse_conv_flag_input(matches: &getopts::Matches) -> Result<IConvFlags, P
|
|||
}
|
||||
|
||||
let ctable = parse_ctable(fmt, case);
|
||||
let sync = if sync && (block.is_some() || unblock.is_some())
|
||||
{
|
||||
Some(' ' as u8)
|
||||
}
|
||||
else if sync
|
||||
{
|
||||
Some(0u8)
|
||||
}
|
||||
else
|
||||
{
|
||||
None
|
||||
};
|
||||
|
||||
Ok(IConvFlags {
|
||||
ctable,
|
||||
|
|
|
|||
|
|
@ -9,31 +9,6 @@ use crate::{
|
|||
|
||||
// ----- IConvFlags/Output -----
|
||||
|
||||
#[test]
|
||||
fn build_icf()
|
||||
{
|
||||
let icf_expd = IConvFlags {
|
||||
ctable: Some(&ASCII_TO_IBM),
|
||||
block: None,
|
||||
unblock: None,
|
||||
swab: false,
|
||||
sync: false,
|
||||
noerror: false,
|
||||
};
|
||||
|
||||
let args = vec![
|
||||
String::from("dd"),
|
||||
String::from("--conv=ibm"),
|
||||
];
|
||||
|
||||
let matches = build_app!().parse(args);
|
||||
|
||||
let icf_parsed = parse_conv_flag_input(&matches).unwrap();
|
||||
|
||||
unimplemented!()
|
||||
// assert_eq!(icf_expd, icf_parsed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn icf_ctable_error()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue