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:
parent
bd626df70e
commit
b98bccf9cc
2 changed files with 71 additions and 75 deletions
|
@ -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
|
||||||
|
|
|
@ -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)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue