1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
use super::{Kind, Result, Unimplemented};
bitflags!{
/// Conversion flags
pub struct Conv: u32 {
/// Translate from EBCDIC to ASCII
const ASCII = 0x0001 ;
/// Translate from ASCII to EBCDIC
const EBCDIC= 0x0002;
/// <NOT IMPLEMENTED> Translate from ASCII to IBM
const IBM = 0x0004;
/// <NOT IMPLEMENTED> Translate from EBCDIC to old ASCII
const OLDASCII = 0x0008 ;
/// <NOT IMPLEMENTED> Translate from ASCII to old EBCDIC
const OLDEBCDIC = 0x0010 ;
/// <NOT IMPLEMENTED> Translate from ASCII to old IBM
const OLDIBM = 0x0020 ;
/// "block" mode: Treats the input as a sequence of newline or end-of-file terminated variable length records independent of input and output block bound-
/// aries. Any trailing newline character is discarded. Each input record is converted to a fixed length output record where the length is
/// specified by the cbs operand. Input records shorter than the conversion record size are padded with spaces. Input records longer than
/// the conversion record size are truncated. The number of truncated input records, if any, are reported to the standard error output at
/// the completion of the copy.
const BLOCK = 0x0040;
/// Treats the input as a sequence of fixed length records independent of input and output block boundaries. The length of the input records
/// is specified by the cbs operand. Any trailing space characters are discarded and a newline character is appended.
const UNBLOCK = 0x0080 ;
/// Transform uppercase [A-Z] characters into lowercase [a-z] characters.
const LCASE = 0x0100;
/// Transform lowercase [a-z] characters into uppercase [A-Z] characters
const UCASE = 0x0200;
/// Pad every input block to the input buffer size. Spaces are used for pad bytes if a
/// block oriented conversion value is specified, otherwise NUL bytes are used.
const SYNC = 0x0400;
/// <NOT IMPLEMENTED> Pad the final output block to the full output block size. If the input file is not a multiple of the output block size after conversion,
/// this conversion forces the final output block to be the same size as preceding blocks for use on devices that require regularly sized
/// blocks to be written. This option is incompatible with use of the bs=n block size specification.
/// sparse If one or more output blocks would consist solely of NUL bytes, try to seek the output file by the required space instead of filling them
/// with NULs, resulting in a sparse file.
const OSYNC = 0x0800;
/// <NOT IMPLEMENTED> Do not stop processing on an input error. When an input error occurs, a diagnostic message followed by the current input and output
/// block counts will be written to the standard error output in the same format as the standard completion message. If the sync conversion
/// is also specified, any missing input data will be replaced with NUL bytes (or with spaces if a block oriented conversion value was speci-
/// fied) and processed as a normal input buffer. If the sync conversion is not specified, the input block is omitted from the output. On
/// input files which are not tapes or pipes, the file offset will be positioned past the block in which the error occurred using lseek(2).
const NOERROR = 0x1000;
/// Do not truncate the output file. This will preserve any blocks in the output file not explicitly written by dd. The notrunc value is
/// not supported for tapes.
const NOTRUNC = 0x2000;
/// If one or more output blocks would consist solely of NUL bytes, try to seek the out-
/// put file by the required space instead of filling them with NULs, resulting in a
/// sparse file.
const SPARSE = 0x4000;
/// Swap every pair of input bytes. If an input buffer has an odd number of bytes, the last byte will be ignored during swapping.
const SWAB = 0x8000;
}
}
impl Conv {
pub fn new(s: &str) -> Result<Self> {
let mut flags = Conv::default();
for flag in s.split(',').map(str::trim).filter(|s| s.len() > 0) {
Self::check_if_implemented(flag)?;
flags |= Self::from_str(flag)?;
}
Ok(flags)
}
fn from_str(flag: &str) -> Result<Self> {
Ok(match flag {
"ascii" => Self::ASCII,
"ebcdic" => Self::EBCDIC,
"oldascii" => Self::OLDASCII,
"ibm" => Self::IBM,
"oldebcdic" => Self::OLDEBCDIC,
"oldibm" => Self::OLDIBM,
"noerror" => Self::NOERROR,
"osync" => Self::OSYNC,
"block" => Self::BLOCK,
"lcase" => Self::LCASE,
"notrunc" => Self::NOTRUNC,
"sparse" => Self::SPARSE,
"swab" => Self::SWAB,
"sync" => Self::SYNC,
"ucase" => Self::UCASE,
"unblock" => Self::UNBLOCK,
arg => return Self::unknown(arg.to_owned()),
})
}
}
impl Unimplemented for Conv {
const KIND: Kind = Kind::CFlag;
const UNIMPLEMENTED: &'static [&'static str] = &["oldascii", "ibm", "oldebcdic", "noerror", "osync", "oldibm"];
}
impl Default for Conv {
fn default() -> Conv { Conv::empty() }
}