mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
Continues impl
- Completes impl of skip=N, and seek=N - Parses cbs=N
This commit is contained in:
+36
-12
@@ -36,6 +36,7 @@ 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 RTN_SUCCESS: i32 = 0;
|
||||
const RTN_FAILURE: i32 = 1;
|
||||
@@ -51,6 +52,7 @@ enum SrcStat
|
||||
pub struct IConvFlags
|
||||
{
|
||||
ctable: Option<&'static ConversionTable>,
|
||||
cbs: Option<usize>,
|
||||
block: bool,
|
||||
unblock: bool,
|
||||
swab: bool,
|
||||
@@ -131,7 +133,12 @@ enum InternalError
|
||||
impl std::fmt::Display for InternalError
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Internal dd error")
|
||||
match self
|
||||
{
|
||||
Self::WrongInputType |
|
||||
Self::WrongOutputType =>
|
||||
write!(f, "Internal dd error"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +191,7 @@ impl Input<io::Stdin>
|
||||
let xfer_stats = parseargs::parse_status_level(matches)?;
|
||||
let cflags = parseargs::parse_conv_flag_input(matches)?;
|
||||
let iflags = parseargs::parse_iflags(matches)?;
|
||||
let skip = parseargs::parse_skip_amt(matches)?;
|
||||
let skip = parseargs::parse_skip_amt(&ibs, &iflags, matches)?;
|
||||
|
||||
let mut i = Input {
|
||||
src: io::stdin(),
|
||||
@@ -194,10 +201,11 @@ impl Input<io::Stdin>
|
||||
iflags,
|
||||
};
|
||||
|
||||
if let Some(skip_amt) = skip
|
||||
if let Some(amt) = skip
|
||||
{
|
||||
let mut buf = vec![DEFAULT_FILL_BYTE; skip_amt];
|
||||
i.read(&mut buf)?;
|
||||
let mut buf = vec![DEFAULT_FILL_BYTE; amt];
|
||||
|
||||
i.force_fill(&mut buf, amt)?;
|
||||
}
|
||||
|
||||
Ok(i)
|
||||
@@ -212,16 +220,16 @@ impl Input<File>
|
||||
let xfer_stats = parseargs::parse_status_level(matches)?;
|
||||
let cflags = parseargs::parse_conv_flag_input(matches)?;
|
||||
let iflags = parseargs::parse_iflags(matches)?;
|
||||
let skip = parseargs::parse_skip_amt(matches)?;
|
||||
let skip = parseargs::parse_skip_amt(&ibs, &iflags, matches)?;
|
||||
|
||||
if let Some(fname) = matches.opt_str("if")
|
||||
{
|
||||
let mut src = File::open(fname)?;
|
||||
|
||||
if let Some(skip_amt) = skip
|
||||
if let Some(amt) = skip
|
||||
{
|
||||
let skip_amt: u64 = skip_amt.try_into()?;
|
||||
src.seek(io::SeekFrom::Start(skip_amt))?;
|
||||
let amt: u64 = amt.try_into()?;
|
||||
src.seek(io::SeekFrom::Start(amt))?;
|
||||
}
|
||||
|
||||
let i = Input {
|
||||
@@ -266,6 +274,21 @@ impl<R: Read> Input<R>
|
||||
Ok(SrcStat::EOF)
|
||||
}
|
||||
}
|
||||
|
||||
fn force_fill(&mut self, mut buf: &mut [u8], len: usize) -> Result<(), Box<dyn Error>>
|
||||
{
|
||||
let mut total_len = 0;
|
||||
|
||||
loop
|
||||
{
|
||||
total_len += self.read(&mut buf)?;
|
||||
|
||||
if total_len == len
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Output<W: Write>
|
||||
@@ -297,8 +320,8 @@ impl Output<File> {
|
||||
{
|
||||
let obs = parseargs::parse_obs(matches)?;
|
||||
let cflags = parseargs::parse_conv_flag_output(matches)?;
|
||||
let seek = parseargs::parse_seek_amt(matches)?;
|
||||
let oflags = parseargs::parse_oflags(matches)?;
|
||||
let seek = parseargs::parse_seek_amt(&obs, &oflags, matches)?;
|
||||
|
||||
if let Some(fname) = matches.opt_str("of")
|
||||
{
|
||||
@@ -308,9 +331,10 @@ impl Output<File> {
|
||||
.truncate(!cflags.notrunc)
|
||||
.open(fname)?;
|
||||
|
||||
if let Some(seek_amt) = seek
|
||||
if let Some(amt) = seek
|
||||
{
|
||||
dst.seek(io::SeekFrom::Start(seek_amt))?;
|
||||
let amt: u64 = amt.try_into()?;
|
||||
dst.seek(io::SeekFrom::Start(amt))?;
|
||||
}
|
||||
|
||||
Ok(Output {
|
||||
|
||||
@@ -65,6 +65,7 @@ macro_rules! icf (
|
||||
{
|
||||
IConvFlags {
|
||||
ctable: $ctable,
|
||||
cbs: None,
|
||||
block: false,
|
||||
unblock: false,
|
||||
swab: false,
|
||||
@@ -95,6 +96,7 @@ macro_rules! make_spec_test (
|
||||
dst: File::create(format!("./test-resources/FAILED-{}.test", $test_name)).unwrap(),
|
||||
obs: 512,
|
||||
cflags: DEFAULT_CFO,
|
||||
oflags: DEFAULT_OFLAGS,
|
||||
},
|
||||
$spec,
|
||||
format!("./test-resources/FAILED-{}.test", $test_name)
|
||||
@@ -139,6 +141,7 @@ macro_rules! make_conv_test (
|
||||
dst: File::create(format!("./test-resources/FAILED-{}.test", $test_name)).unwrap(),
|
||||
obs: 512,
|
||||
cflags: DEFAULT_CFO,
|
||||
oflags: DEFAULT_OFLAGS,
|
||||
},
|
||||
$spec,
|
||||
format!("./test-resources/FAILED-{}.test", $test_name)
|
||||
@@ -162,6 +165,7 @@ macro_rules! make_icf_test (
|
||||
dst: File::create(format!("./test-resources/FAILED-{}.test", $test_name)).unwrap(),
|
||||
obs: 512,
|
||||
cflags: DEFAULT_CFO,
|
||||
oflags: DEFAULT_OFLAGS,
|
||||
},
|
||||
$spec,
|
||||
format!("./test-resources/FAILED-{}.test", $test_name)
|
||||
@@ -288,6 +292,7 @@ fn all_valid_ascii_ebcdic_ascii_roundtrip_conv_test()
|
||||
dst: File::create(&tmp_fname_ae).unwrap(),
|
||||
obs: 1024,
|
||||
cflags: DEFAULT_CFO,
|
||||
oflags: DEFAULT_OFLAGS,
|
||||
};
|
||||
|
||||
dd_fileout(i,o).unwrap();
|
||||
@@ -308,6 +313,7 @@ fn all_valid_ascii_ebcdic_ascii_roundtrip_conv_test()
|
||||
dst: File::create(&tmp_fname_ea).unwrap(),
|
||||
obs: 1024,
|
||||
cflags: DEFAULT_CFO,
|
||||
oflags: DEFAULT_OFLAGS,
|
||||
};
|
||||
|
||||
dd_fileout(i,o).unwrap();
|
||||
@@ -337,6 +343,7 @@ make_icf_test!(
|
||||
File::open("./test-resources/seq-byte-values.test").unwrap(),
|
||||
IConvFlags {
|
||||
ctable: None,
|
||||
cbs: None,
|
||||
block: false,
|
||||
unblock: false,
|
||||
swab: true,
|
||||
@@ -352,6 +359,7 @@ make_icf_test!(
|
||||
File::open("./test-resources/seq-byte-values-odd.test").unwrap(),
|
||||
IConvFlags {
|
||||
ctable: None,
|
||||
cbs: None,
|
||||
block: false,
|
||||
unblock: false,
|
||||
swab: true,
|
||||
|
||||
+52
-18
@@ -23,7 +23,7 @@ pub enum ParseError
|
||||
FlagNoMatch(String),
|
||||
ConvFlagNoMatch(String),
|
||||
NoMatchingMultiplier(String),
|
||||
MultiplierStringContainsNoValue(String),
|
||||
ByteStringContainsNoValue(String),
|
||||
MultiplierStringWouldOverflow(String),
|
||||
}
|
||||
|
||||
@@ -235,15 +235,21 @@ fn parse_multiplier<'a>(s: &'a str) -> Result<usize, ParseError>
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_bytes_only(s: &str) -> Result<usize, ParseError>
|
||||
{
|
||||
let bytes: usize = match s.parse()
|
||||
{
|
||||
Ok(val) => val,
|
||||
Err(_) => return Err(ParseError::ByteStringContainsNoValue(String::from(s))),
|
||||
};
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
fn parse_bytes_with_opt_multiplier(s: String) -> Result<usize, ParseError>
|
||||
{
|
||||
if let Some(idx) = s.find(char::is_alphabetic)
|
||||
{
|
||||
let base: usize = match s[0..idx].parse()
|
||||
{
|
||||
Ok(val) => val,
|
||||
Err(_) => return Err(ParseError::MultiplierStringContainsNoValue(s)),
|
||||
};
|
||||
let base = parse_bytes_only(&s[0..idx])?;
|
||||
let mult = parse_multiplier(&s[idx..])?;
|
||||
|
||||
if let Some(bytes) = base.checked_mul(mult)
|
||||
@@ -257,12 +263,7 @@ fn parse_bytes_with_opt_multiplier(s: String) -> Result<usize, ParseError>
|
||||
}
|
||||
else
|
||||
{
|
||||
let bytes: usize = match s.parse()
|
||||
{
|
||||
Ok(val) => val,
|
||||
Err(_) => return Err(ParseError::MultiplierStringContainsNoValue(s)),
|
||||
};
|
||||
Ok(bytes)
|
||||
parse_bytes_only(&s)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,6 +283,19 @@ pub fn parse_ibs(matches: &getopts::Matches) -> Result<usize, ParseError>
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_cbs(matches: &getopts::Matches) -> Result<Option<usize>, ParseError>
|
||||
{
|
||||
if let Some(s) = matches.opt_str("cbs")
|
||||
{
|
||||
let bytes = parse_bytes_with_opt_multiplier(s)?;
|
||||
Ok(Some(bytes))
|
||||
}
|
||||
else
|
||||
{
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_status_level(matches: &getopts::Matches) -> Result<StatusLevel, ParseError>
|
||||
{
|
||||
// TODO: Impl
|
||||
@@ -371,6 +385,7 @@ fn parse_flag_list<T: std::str::FromStr<Err = ParseError>>(tag: &str, matches: &
|
||||
pub fn parse_conv_flag_input(matches: &getopts::Matches) -> Result<IConvFlags, ParseError>
|
||||
{
|
||||
let flags = parse_flag_list("conv", matches)?;
|
||||
let cbs = parse_cbs(matches)?;
|
||||
|
||||
let mut fmt = None;
|
||||
let mut case = None;
|
||||
@@ -461,6 +476,7 @@ pub fn parse_conv_flag_input(matches: &getopts::Matches) -> Result<IConvFlags, P
|
||||
|
||||
Ok(IConvFlags {
|
||||
ctable,
|
||||
cbs,
|
||||
block,
|
||||
unblock,
|
||||
swab,
|
||||
@@ -691,11 +707,20 @@ pub fn parse_oflags(matches: &getopts::Matches) -> Result<OFlags, ParseError>
|
||||
}
|
||||
|
||||
/// Parse the amount of the input file to skip.
|
||||
pub fn parse_skip_amt(matches: &getopts::Matches) -> Result<Option<usize>, ParseError>
|
||||
pub fn parse_skip_amt(ibs: &usize, iflags: &IFlags, matches: &getopts::Matches) -> Result<Option<usize>, ParseError>
|
||||
{
|
||||
if let Some(skip_amt) = matches.opt_str("skip")
|
||||
if let Some(amt) = matches.opt_str("skip")
|
||||
{
|
||||
unimplemented!()
|
||||
if iflags.skip_bytes
|
||||
{
|
||||
let n = parse_bytes_with_opt_multiplier(amt)?;
|
||||
Ok(Some(n))
|
||||
}
|
||||
else
|
||||
{
|
||||
let n = parse_bytes_only(&amt)?;
|
||||
Ok(Some(ibs*n))
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -704,11 +729,20 @@ pub fn parse_skip_amt(matches: &getopts::Matches) -> Result<Option<usize>, Parse
|
||||
}
|
||||
|
||||
/// Parse the amount of the output file to seek.
|
||||
pub fn parse_seek_amt(matches: &getopts::Matches) -> Result<Option<u64>, ParseError>
|
||||
pub fn parse_seek_amt(obs: &usize, oflags: &OFlags, matches: &getopts::Matches) -> Result<Option<usize>, ParseError>
|
||||
{
|
||||
if let Some(seek_amt) = matches.opt_str("seek")
|
||||
if let Some(amt) = matches.opt_str("seek")
|
||||
{
|
||||
unimplemented!()
|
||||
if oflags.seek_bytes
|
||||
{
|
||||
let n = parse_bytes_with_opt_multiplier(amt)?;
|
||||
Ok(Some(n))
|
||||
}
|
||||
else
|
||||
{
|
||||
let n = parse_bytes_only(&amt)?;
|
||||
Ok(Some(obs*n))
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -14,6 +14,7 @@ fn build_icf()
|
||||
{
|
||||
let icf_expd = IConvFlags {
|
||||
ctable: Some(&ASCII_TO_IBM),
|
||||
cbs: None,
|
||||
block: false,
|
||||
unblock: false,
|
||||
swab: false,
|
||||
@@ -103,7 +104,7 @@ fn parse_icf_token_ibm()
|
||||
];
|
||||
let matches = build_app!().parse(args);
|
||||
|
||||
let act = parse_conv_opts(&matches).unwrap();
|
||||
let act = parse_flag_list::<ConvFlag>("conv", &matches).unwrap();
|
||||
|
||||
assert_eq!(exp.len(), act.len());
|
||||
for cf in &exp
|
||||
@@ -126,7 +127,7 @@ fn parse_icf_tokens_elu()
|
||||
String::from("--conv=ebcdic,lcase,unblock"),
|
||||
];
|
||||
let matches = build_app!().parse(args);
|
||||
let act = parse_conv_opts(&matches).unwrap();
|
||||
let act = parse_flag_list::<ConvFlag>("conv", &matches).unwrap();
|
||||
|
||||
assert_eq!(exp.len(), act.len());
|
||||
for cf in &exp
|
||||
@@ -159,7 +160,8 @@ fn parse_icf_tokens_remaining()
|
||||
String::from("--conv=ascii,ucase,block,sparse,swab,sync,noerror,excl,nocreat,notrunc,noerror,fdatasync,fsync"),
|
||||
];
|
||||
let matches = build_app!().parse(args);
|
||||
let act = parse_conv_opts(&matches).unwrap();
|
||||
|
||||
let act = parse_flag_list::<ConvFlag>("conv", &matches).unwrap();
|
||||
|
||||
assert_eq!(exp.len(), act.len());
|
||||
for cf in &exp
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user