diff --git a/src/uu/dd/src/blocks.rs b/src/uu/dd/src/blocks.rs index 292f9ce09..3f7c59c27 100644 --- a/src/uu/dd/src/blocks.rs +++ b/src/uu/dd/src/blocks.rs @@ -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 { }) } -/// 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, - unblock: Option, - non_ascii: bool, - is_sync: bool, -) -> Option { - 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( +/// 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, - i: &mut Input, + mode: &ConversionMode, rstat: &mut ReadStat, ) -> Vec { // TODO This function has a mutable input `buf` but also returns a @@ -128,15 +92,7 @@ pub(crate) fn conv_block_unblock_helper( } } - 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 diff --git a/src/uu/dd/src/dd.rs b/src/uu/dd/src/dd.rs index d004a592d..33135bf02 100644 --- a/src/uu/dd/src/dd.rs +++ b/src/uu/dd/src/dd.rs @@ -605,18 +605,49 @@ impl Write for Output { } } +/// 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, + unblock: Option, + non_ascii: bool, + is_sync: bool, +) -> Option { + 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(i: &mut Input, bsize: usize) -> std::io::Result<(ReadStat, Vec)> { - // Local Predicate Fns ----------------------------------------------- - fn is_conv(i: &Input) -> bool { - i.cflags.ctable.is_some() - } - fn is_block(i: &Input) -> bool { - i.cflags.block.is_some() - } - fn is_unblock(i: &Input) -> 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(i: &mut Input, 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)), } }