1
Fork 0
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:
Tyler 2021-04-27 12:21:35 -07:00
parent 4d7be2f098
commit d97672dfd3
7 changed files with 101 additions and 33 deletions

View file

@ -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 {

View file

@ -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,

View file

@ -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
{

View file

@ -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.