mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2026-01-20 04:01:06 +00:00
Continues impl
- Completes impl of skip=N, and seek=N - Parses cbs=N
This commit is contained in:
parent
4d7be2f098
commit
d97672dfd3
7 changed files with 101 additions and 33 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
BIN
src/uu/dd/test-resources/seq-byte-values-odd.spec
Normal file
BIN
src/uu/dd/test-resources/seq-byte-values-odd.spec
Normal file
Binary file not shown.
BIN
src/uu/dd/test-resources/seq-byte-values-odd.test
Normal file
BIN
src/uu/dd/test-resources/seq-byte-values-odd.test
Normal file
Binary file not shown.
BIN
src/uu/dd/test-resources/seq-byte-values.test
Normal file
BIN
src/uu/dd/test-resources/seq-byte-values.test
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue