mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-29 12:07:46 +00:00
Implements status=LEVEL parser.
This commit is contained in:
parent
8141919064
commit
06dcdc0f1f
3 changed files with 171 additions and 31 deletions
|
@ -164,7 +164,7 @@ pub struct OFlags
|
|||
|
||||
/// The value of the status cl-option.
|
||||
/// Controls printing of transfer stats
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum StatusLevel
|
||||
{
|
||||
Progress,
|
||||
|
@ -1316,6 +1316,43 @@ macro_rules! build_app (
|
|||
"Set the conversion block size to BYTES. When converting variable-length records to fixed-length ones (‘conv=block’) or the reverse (‘conv=unblock’), use BYTES as the fixed record length.",
|
||||
"BYTES"
|
||||
)
|
||||
.optopt(
|
||||
"",
|
||||
"status",
|
||||
"Specify the amount of information printed. If this operand is
|
||||
given multiple times, the last one takes precedence. The LEVEL
|
||||
value can be one of the following:
|
||||
|
||||
‘none’
|
||||
Do not print any informational or warning messages to stderr.
|
||||
Error messages are output as normal.
|
||||
|
||||
‘noxfer’
|
||||
Do not print the final transfer rate and volume statistics
|
||||
that normally make up the last status line.
|
||||
|
||||
‘progress’
|
||||
Print the transfer rate and volume statistics on stderr, when
|
||||
processing each input block. Statistics are output on a
|
||||
single line at most once every second, but updates can be
|
||||
delayed when waiting on I/O.
|
||||
|
||||
Transfer information is normally output to stderr upon receipt of
|
||||
the ‘INFO’ signal or when ‘dd’ exits, and defaults to the following
|
||||
form in the C locale:
|
||||
|
||||
7287+1 records in
|
||||
116608+0 records out
|
||||
59703296 bytes (60 MB, 57 MiB) copied, 0.0427974 s, 1.4 GB/s
|
||||
|
||||
The notation ‘W+P’ stands for W whole blocks and P partial blocks.
|
||||
A partial block occurs when a read or write operation succeeds but
|
||||
transfers less data than the block size. An additional line like
|
||||
‘1 truncated record’ or ‘10 truncated records’ is output after the
|
||||
‘records out’ line if ‘conv=block’ processing truncated one or more
|
||||
input records.",
|
||||
"LEVEL"
|
||||
)
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ pub enum ParseError
|
|||
ByteStringContainsNoValue(String),
|
||||
MultiplierStringWouldOverflow(String),
|
||||
BlockUnblockWithoutCBS,
|
||||
StatusLevelNotRecognized(String),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ParseError
|
||||
|
@ -189,6 +190,26 @@ impl std::str::FromStr for Flag
|
|||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for StatusLevel
|
||||
{
|
||||
type Err = ParseError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err>
|
||||
{
|
||||
match s
|
||||
{
|
||||
"none" =>
|
||||
Ok(StatusLevel::None),
|
||||
"noxfer" =>
|
||||
Ok(StatusLevel::Noxfer),
|
||||
"progress" =>
|
||||
Ok(StatusLevel::Progress),
|
||||
_ =>
|
||||
Err(ParseError::StatusLevelNotRecognized(s.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_multiplier<'a>(s: &'a str) -> Result<usize, ParseError>
|
||||
{
|
||||
match s
|
||||
|
@ -251,7 +272,7 @@ fn parse_bytes_with_opt_multiplier(s: String) -> Result<usize, ParseError>
|
|||
{
|
||||
if let Some(idx) = s.find(char::is_alphabetic)
|
||||
{
|
||||
let base = parse_bytes_only(&s[0..idx])?;
|
||||
let base = parse_bytes_only(&s[..idx])?;
|
||||
let mult = parse_multiplier(&s[idx..])?;
|
||||
|
||||
if let Some(bytes) = base.checked_mul(mult)
|
||||
|
@ -300,7 +321,16 @@ fn parse_cbs(matches: &getopts::Matches) -> Result<Option<usize>, ParseError>
|
|||
|
||||
pub fn parse_status_level(matches: &getopts::Matches) -> Result<Option<StatusLevel>, ParseError>
|
||||
{
|
||||
unimplemented!()
|
||||
match matches.opt_str("status")
|
||||
{
|
||||
Some(s) =>
|
||||
{
|
||||
let st = s.parse()?;
|
||||
Ok(Some(st))
|
||||
},
|
||||
None =>
|
||||
Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_obs(matches: &getopts::Matches) -> Result<usize, ParseError>
|
||||
|
@ -321,45 +351,55 @@ pub fn parse_obs(matches: &getopts::Matches) -> Result<usize, ParseError>
|
|||
|
||||
fn parse_ctable(fmt: Option<ConvFlag>, case: Option<ConvFlag>) -> Option<&'static ConversionTable>
|
||||
{
|
||||
fn parse_conv_and_case_table(fmt: &ConvFlag, case: &ConvFlag) -> Option<&'static ConversionTable>
|
||||
{
|
||||
match (fmt, case)
|
||||
{
|
||||
(ConvFlag::FmtAtoE, ConvFlag::UCase) =>
|
||||
Some(&ASCII_TO_EBCDIC_LCASE_TO_UCASE),
|
||||
(ConvFlag::FmtAtoE, ConvFlag::LCase) =>
|
||||
Some(&ASCII_TO_EBCDIC_UCASE_TO_LCASE),
|
||||
(ConvFlag::FmtEtoA, ConvFlag::UCase) =>
|
||||
Some(&EBCDIC_TO_ASCII_LCASE_TO_UCASE),
|
||||
(ConvFlag::FmtEtoA, ConvFlag::LCase) =>
|
||||
Some(&EBCDIC_TO_ASCII_UCASE_TO_LCASE),
|
||||
(ConvFlag::FmtAtoI, ConvFlag::UCase) =>
|
||||
Some(&ASCII_TO_IBM_UCASE_TO_LCASE),
|
||||
(ConvFlag::FmtAtoI, ConvFlag::LCase) =>
|
||||
Some(&ASCII_TO_IBM_LCASE_TO_UCASE),
|
||||
(_, _) =>
|
||||
None,
|
||||
}
|
||||
}
|
||||
fn parse_conv_table_only(fmt: &ConvFlag) -> Option<&'static ConversionTable>
|
||||
{
|
||||
match fmt
|
||||
{
|
||||
ConvFlag::FmtAtoE =>
|
||||
Some(&ASCII_TO_EBCDIC),
|
||||
ConvFlag::FmtEtoA =>
|
||||
Some(&EBCDIC_TO_ASCII),
|
||||
ConvFlag::FmtAtoI =>
|
||||
Some(&ASCII_TO_IBM),
|
||||
_ =>
|
||||
None,
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
match (fmt, case)
|
||||
{
|
||||
// Both [ascii | ebcdic | ibm] and [lcase | ucase] specified
|
||||
(Some(fmt), Some(case)) =>
|
||||
match (fmt, case)
|
||||
{
|
||||
(ConvFlag::FmtAtoE, ConvFlag::UCase) =>
|
||||
Some(&ASCII_TO_EBCDIC_LCASE_TO_UCASE),
|
||||
(ConvFlag::FmtAtoE, ConvFlag::LCase) =>
|
||||
Some(&ASCII_TO_EBCDIC_UCASE_TO_LCASE),
|
||||
(ConvFlag::FmtEtoA, ConvFlag::UCase) =>
|
||||
Some(&EBCDIC_TO_ASCII_LCASE_TO_UCASE),
|
||||
(ConvFlag::FmtEtoA, ConvFlag::LCase) =>
|
||||
Some(&EBCDIC_TO_ASCII_UCASE_TO_LCASE),
|
||||
(ConvFlag::FmtAtoI, ConvFlag::UCase) =>
|
||||
Some(&ASCII_TO_IBM_UCASE_TO_LCASE),
|
||||
(ConvFlag::FmtAtoI, ConvFlag::LCase) =>
|
||||
Some(&ASCII_TO_IBM_LCASE_TO_UCASE),
|
||||
(_, _) =>
|
||||
None,
|
||||
},
|
||||
parse_conv_and_case_table(&fmt, &case),
|
||||
// Only [ascii | ebcdic | ibm] specified
|
||||
(Some(fmt), None) =>
|
||||
match fmt
|
||||
{
|
||||
ConvFlag::FmtAtoE =>
|
||||
Some(&ASCII_TO_EBCDIC),
|
||||
ConvFlag::FmtEtoA =>
|
||||
Some(&EBCDIC_TO_ASCII),
|
||||
ConvFlag::FmtAtoI =>
|
||||
Some(&ASCII_TO_IBM),
|
||||
_ =>
|
||||
None,
|
||||
},
|
||||
parse_conv_table_only(&fmt),
|
||||
// Only [lcase | ucase] specified
|
||||
(None, Some(ConvFlag::UCase)) =>
|
||||
Some(&ASCII_LCASE_TO_UCASE),
|
||||
(None, Some(ConvFlag::LCase)) =>
|
||||
Some(&ASCII_UCASE_TO_LCASE),
|
||||
// ST else...
|
||||
(_, _) =>
|
||||
None,
|
||||
}
|
||||
|
|
|
@ -7,6 +7,69 @@ use crate::{
|
|||
StatusLevel,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_status_level_absent()
|
||||
{
|
||||
let args = vec![
|
||||
String::from("dd"),
|
||||
String::from("--if=foo.file"),
|
||||
String::from("--of=bar.file"),
|
||||
];
|
||||
|
||||
let matches = build_app!().parse(args);
|
||||
let st = parse_status_level(&matches).unwrap();
|
||||
|
||||
assert_eq!(st, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_status_level_none()
|
||||
{
|
||||
let args = vec![
|
||||
String::from("dd"),
|
||||
String::from("--status=none"),
|
||||
String::from("--if=foo.file"),
|
||||
String::from("--of=bar.file"),
|
||||
];
|
||||
|
||||
let matches = build_app!().parse(args);
|
||||
let st = parse_status_level(&matches).unwrap().unwrap();
|
||||
|
||||
assert_eq!(st, StatusLevel::None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_status_level_progress()
|
||||
{
|
||||
let args = vec![
|
||||
String::from("dd"),
|
||||
String::from("--if=foo.file"),
|
||||
String::from("--of=bar.file"),
|
||||
String::from("--status=progress"),
|
||||
];
|
||||
|
||||
let matches = build_app!().parse(args);
|
||||
let st = parse_status_level(&matches).unwrap().unwrap();
|
||||
|
||||
assert_eq!(st, StatusLevel::Progress);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_status_level_noxfer()
|
||||
{
|
||||
let args = vec![
|
||||
String::from("dd"),
|
||||
String::from("--if=foo.file"),
|
||||
String::from("--status=noxfer"),
|
||||
String::from("--of=bar.file"),
|
||||
];
|
||||
|
||||
let matches = build_app!().parse(args);
|
||||
let st = parse_status_level(&matches).unwrap().unwrap();
|
||||
|
||||
assert_eq!(st, StatusLevel::Noxfer);
|
||||
}
|
||||
|
||||
// ----- IConvFlags/Output -----
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue