1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-30 12:37:49 +00:00

dd: move ConversionMode parsing to dd.rs

Move parsing of the `ConversionMode` outside of
`conv_block_unblock_helper()` and up to the code that calls it.
This commit is contained in:
Jeffrey Finkelstein 2022-03-06 23:35:03 -05:00 committed by Sylvestre Ledru
parent bd626df70e
commit b98bccf9cc
2 changed files with 71 additions and 75 deletions

View file

@ -8,8 +8,6 @@
use crate::conversion_tables::ConversionTable; use crate::conversion_tables::ConversionTable;
use crate::datastructures::ConversionMode; use crate::datastructures::ConversionMode;
use crate::progress::ReadStat; use crate::progress::ReadStat;
use crate::Input;
use std::io::Read;
const NEWLINE: u8 = b'\n'; const NEWLINE: u8 = b'\n';
const SPACE: u8 = b' '; const SPACE: u8 = b' ';
@ -65,57 +63,23 @@ fn unblock(buf: &[u8], cbs: usize) -> Vec<u8> {
}) })
} }
/// Given the various command-line parameters, determine the conversion mode. /// Apply the specified conversion, blocking, and/or unblocking in the right order.
/// ///
/// The `conv` command-line option can take many different values, /// The `mode` specifies the combination of conversion, blocking, and
/// each of which may combine with others. For example, `conv=ascii`, /// unblocking to apply and the order in which to apply it. This
/// `conv=lcase`, `conv=sync`, and so on. The arguments to this /// function is responsible only for applying the operations.
/// function represent the settings of those various command-line ///
/// parameters. This function translates those settings to a /// `buf` is the buffer of input bytes to transform. This function
/// [`ConversionMode`]. /// mutates this input and also returns a new buffer of bytes
fn conversion_mode( /// representing the result of the transformation.
ctable: Option<&ConversionTable>, ///
block: Option<usize>, /// `rstat` maintains a running total of the number of partial and
unblock: Option<usize>, /// complete blocks read before calling this function. In certain
non_ascii: bool, /// settings of `mode`, this function will update the number of
is_sync: bool, /// records truncated; that's why `rstat` is borrowed mutably.
) -> Option<ConversionMode> { pub(crate) fn conv_block_unblock_helper(
match (ctable, block, unblock) {
(Some(ct), None, None) => Some(ConversionMode::ConvertOnly(ct)),
(Some(ct), Some(cbs), None) => {
if non_ascii {
Some(ConversionMode::ConvertThenBlock(ct, cbs, is_sync))
} else {
Some(ConversionMode::BlockThenConvert(ct, cbs, is_sync))
}
}
(Some(ct), None, Some(cbs)) => {
if non_ascii {
Some(ConversionMode::ConvertThenUnblock(ct, cbs))
} else {
Some(ConversionMode::UnblockThenConvert(ct, cbs))
}
}
(None, Some(cbs), None) => Some(ConversionMode::BlockOnly(cbs, is_sync)),
(None, None, Some(cbs)) => Some(ConversionMode::UnblockOnly(cbs)),
(None, None, None) => None,
// The remaining variants should never happen because the
// argument parsing above should result in an error before
// getting to this line of code.
_ => unreachable!(),
}
}
/// A helper for teasing out which options must be applied and in which order.
/// Some user options, such as the presence of conversion tables, will determine whether the input is assumed to be ascii. The parser sets the Input::non_ascii flag accordingly.
/// Examples:
/// - If conv=ebcdic or conv=ibm is specified then block, unblock or swab must be performed before the conversion happens since the source will start in ascii.
/// - If conv=ascii is specified then block, unblock or swab must be performed after the conversion since the source starts in ebcdic.
/// - If no conversion is specified then the source is assumed to be in ascii.
/// For more info see `info dd`
pub(crate) fn conv_block_unblock_helper<R: Read>(
mut buf: Vec<u8>, mut buf: Vec<u8>,
i: &mut Input<R>, mode: &ConversionMode,
rstat: &mut ReadStat, rstat: &mut ReadStat,
) -> Vec<u8> { ) -> Vec<u8> {
// TODO This function has a mutable input `buf` but also returns a // TODO This function has a mutable input `buf` but also returns a
@ -128,15 +92,7 @@ pub(crate) fn conv_block_unblock_helper<R: Read>(
} }
} }
let mode = conversion_mode( match mode {
i.cflags.ctable,
i.cflags.block,
i.cflags.unblock,
i.non_ascii,
i.cflags.sync.is_some(),
)
.unwrap();
match &mode {
ConversionMode::ConvertOnly(ct) => { ConversionMode::ConvertOnly(ct) => {
apply_conversion(&mut buf, ct); apply_conversion(&mut buf, ct);
buf buf

View file

@ -605,18 +605,49 @@ impl Write for Output<io::Stdout> {
} }
} }
/// Given the various command-line parameters, determine the conversion mode.
///
/// The `conv` command-line option can take many different values,
/// each of which may combine with others. For example, `conv=ascii`,
/// `conv=lcase`, `conv=sync`, and so on. The arguments to this
/// function represent the settings of those various command-line
/// parameters. This function translates those settings to a
/// [`ConversionMode`].
fn conversion_mode(
ctable: Option<&ConversionTable>,
block: Option<usize>,
unblock: Option<usize>,
non_ascii: bool,
is_sync: bool,
) -> Option<ConversionMode> {
match (ctable, block, unblock) {
(Some(ct), None, None) => Some(ConversionMode::ConvertOnly(ct)),
(Some(ct), Some(cbs), None) => {
if non_ascii {
Some(ConversionMode::ConvertThenBlock(ct, cbs, is_sync))
} else {
Some(ConversionMode::BlockThenConvert(ct, cbs, is_sync))
}
}
(Some(ct), None, Some(cbs)) => {
if non_ascii {
Some(ConversionMode::ConvertThenUnblock(ct, cbs))
} else {
Some(ConversionMode::UnblockThenConvert(ct, cbs))
}
}
(None, Some(cbs), None) => Some(ConversionMode::BlockOnly(cbs, is_sync)),
(None, None, Some(cbs)) => Some(ConversionMode::UnblockOnly(cbs)),
(None, None, None) => None,
// The remaining variants should never happen because the
// argument parsing above should result in an error before
// getting to this line of code.
_ => unreachable!(),
}
}
/// Read helper performs read operations common to all dd reads, and dispatches the buffer to relevant helper functions as dictated by the operations requested by the user. /// Read helper performs read operations common to all dd reads, and dispatches the buffer to relevant helper functions as dictated by the operations requested by the user.
fn read_helper<R: Read>(i: &mut Input<R>, bsize: usize) -> std::io::Result<(ReadStat, Vec<u8>)> { fn read_helper<R: Read>(i: &mut Input<R>, bsize: usize) -> std::io::Result<(ReadStat, Vec<u8>)> {
// Local Predicate Fns -----------------------------------------------
fn is_conv<R: Read>(i: &Input<R>) -> bool {
i.cflags.ctable.is_some()
}
fn is_block<R: Read>(i: &Input<R>) -> bool {
i.cflags.block.is_some()
}
fn is_unblock<R: Read>(i: &Input<R>) -> bool {
i.cflags.unblock.is_some()
}
// Local Helper Fns ------------------------------------------------- // Local Helper Fns -------------------------------------------------
fn perform_swab(buf: &mut [u8]) { fn perform_swab(buf: &mut [u8]) {
for base in (1..buf.len()).step_by(2) { for base in (1..buf.len()).step_by(2) {
@ -639,11 +670,20 @@ fn read_helper<R: Read>(i: &mut Input<R>, bsize: usize) -> std::io::Result<(Read
if i.cflags.swab { if i.cflags.swab {
perform_swab(&mut buf); perform_swab(&mut buf);
} }
if is_conv(i) || is_block(i) || is_unblock(i) {
let buf = conv_block_unblock_helper(buf, i, &mut rstat); let mode = conversion_mode(
Ok((rstat, buf)) i.cflags.ctable,
} else { i.cflags.block,
Ok((rstat, buf)) i.cflags.unblock,
i.non_ascii,
i.cflags.sync.is_some(),
);
match mode {
Some(ref mode) => {
let buf = conv_block_unblock_helper(buf, mode, &mut rstat);
Ok((rstat, buf))
}
None => Ok((rstat, buf)),
} }
} }