mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-29 12:07:46 +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:
parent
bd626df70e
commit
b98bccf9cc
2 changed files with 71 additions and 75 deletions
|
@ -8,8 +8,6 @@
|
|||
use crate::conversion_tables::ConversionTable;
|
||||
use crate::datastructures::ConversionMode;
|
||||
use crate::progress::ReadStat;
|
||||
use crate::Input;
|
||||
use std::io::Read;
|
||||
|
||||
const NEWLINE: u8 = b'\n';
|
||||
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,
|
||||
/// 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!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// 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>(
|
||||
/// The `mode` specifies the combination of conversion, blocking, and
|
||||
/// unblocking to apply and the order in which to apply it. This
|
||||
/// function is responsible only for applying the operations.
|
||||
///
|
||||
/// `buf` is the buffer of input bytes to transform. This function
|
||||
/// mutates this input and also returns a new buffer of bytes
|
||||
/// representing the result of the transformation.
|
||||
///
|
||||
/// `rstat` maintains a running total of the number of partial and
|
||||
/// complete blocks read before calling this function. In certain
|
||||
/// settings of `mode`, this function will update the number of
|
||||
/// records truncated; that's why `rstat` is borrowed mutably.
|
||||
pub(crate) fn conv_block_unblock_helper(
|
||||
mut buf: Vec<u8>,
|
||||
i: &mut Input<R>,
|
||||
mode: &ConversionMode,
|
||||
rstat: &mut ReadStat,
|
||||
) -> Vec<u8> {
|
||||
// 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(
|
||||
i.cflags.ctable,
|
||||
i.cflags.block,
|
||||
i.cflags.unblock,
|
||||
i.non_ascii,
|
||||
i.cflags.sync.is_some(),
|
||||
)
|
||||
.unwrap();
|
||||
match &mode {
|
||||
match mode {
|
||||
ConversionMode::ConvertOnly(ct) => {
|
||||
apply_conversion(&mut buf, ct);
|
||||
buf
|
||||
|
|
|
@ -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.
|
||||
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 -------------------------------------------------
|
||||
fn perform_swab(buf: &mut [u8]) {
|
||||
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 {
|
||||
perform_swab(&mut buf);
|
||||
}
|
||||
if is_conv(i) || is_block(i) || is_unblock(i) {
|
||||
let buf = conv_block_unblock_helper(buf, i, &mut rstat);
|
||||
Ok((rstat, buf))
|
||||
} else {
|
||||
Ok((rstat, buf))
|
||||
|
||||
let mode = conversion_mode(
|
||||
i.cflags.ctable,
|
||||
i.cflags.block,
|
||||
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)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue