mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-08-01 21:47:46 +00:00
Merge pull request #3146 from ndd7xv/split-suffix-check
split: error when num. of chunks is greater than num. of possible filenames
This commit is contained in:
commit
938c5acbbe
2 changed files with 37 additions and 19 deletions
|
@ -36,19 +36,19 @@ pub enum SuffixType {
|
|||
Alphabetic,
|
||||
|
||||
/// Decimal numbers.
|
||||
NumericDecimal,
|
||||
Decimal,
|
||||
|
||||
/// Hexadecimal numbers.
|
||||
NumericHexadecimal,
|
||||
Hexadecimal,
|
||||
}
|
||||
|
||||
impl SuffixType {
|
||||
/// The radix to use when representing the suffix string as digits.
|
||||
fn radix(&self) -> u8 {
|
||||
pub fn radix(&self) -> u8 {
|
||||
match self {
|
||||
SuffixType::Alphabetic => 26,
|
||||
SuffixType::NumericDecimal => 10,
|
||||
SuffixType::NumericHexadecimal => 16,
|
||||
SuffixType::Decimal => 10,
|
||||
SuffixType::Hexadecimal => 16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ impl SuffixType {
|
|||
/// assert_eq!(it.next().unwrap(), "chunk_ac.txt");
|
||||
/// ```
|
||||
///
|
||||
/// For decimal numeric filenames, use `SuffixType::NumericDecimal`:
|
||||
/// For decimal numeric filenames, use `SuffixType::Decimal`:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// use crate::filenames::FilenameIterator;
|
||||
|
@ -99,7 +99,7 @@ impl SuffixType {
|
|||
/// let prefix = "chunk_".to_string();
|
||||
/// let suffix = ".txt".to_string();
|
||||
/// let width = 2;
|
||||
/// let suffix_type = SuffixType::NumericDecimal;
|
||||
/// let suffix_type = SuffixType::Decimal;
|
||||
/// let it = FilenameIterator::new(prefix, suffix, width, suffix_type);
|
||||
///
|
||||
/// assert_eq!(it.next().unwrap(), "chunk_00.txt");
|
||||
|
@ -173,12 +173,12 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_filename_iterator_numeric_fixed_width() {
|
||||
let mut it = FilenameIterator::new("chunk_", ".txt", 2, SuffixType::NumericDecimal);
|
||||
let mut it = FilenameIterator::new("chunk_", ".txt", 2, SuffixType::Decimal);
|
||||
assert_eq!(it.next().unwrap(), "chunk_00.txt");
|
||||
assert_eq!(it.next().unwrap(), "chunk_01.txt");
|
||||
assert_eq!(it.next().unwrap(), "chunk_02.txt");
|
||||
|
||||
let mut it = FilenameIterator::new("chunk_", ".txt", 2, SuffixType::NumericDecimal);
|
||||
let mut it = FilenameIterator::new("chunk_", ".txt", 2, SuffixType::Decimal);
|
||||
assert_eq!(it.nth(10 * 10 - 1).unwrap(), "chunk_99.txt");
|
||||
assert_eq!(it.next(), None);
|
||||
}
|
||||
|
@ -198,12 +198,12 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_filename_iterator_numeric_dynamic_width() {
|
||||
let mut it = FilenameIterator::new("chunk_", ".txt", 0, SuffixType::NumericDecimal);
|
||||
let mut it = FilenameIterator::new("chunk_", ".txt", 0, SuffixType::Decimal);
|
||||
assert_eq!(it.next().unwrap(), "chunk_00.txt");
|
||||
assert_eq!(it.next().unwrap(), "chunk_01.txt");
|
||||
assert_eq!(it.next().unwrap(), "chunk_02.txt");
|
||||
|
||||
let mut it = FilenameIterator::new("chunk_", ".txt", 0, SuffixType::NumericDecimal);
|
||||
let mut it = FilenameIterator::new("chunk_", ".txt", 0, SuffixType::Decimal);
|
||||
assert_eq!(it.nth(10 * 9 - 1).unwrap(), "chunk_89.txt");
|
||||
assert_eq!(it.next().unwrap(), "chunk_9000.txt");
|
||||
assert_eq!(it.next().unwrap(), "chunk_9001.txt");
|
||||
|
|
|
@ -158,7 +158,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
|||
.long(OPT_HEX_SUFFIXES)
|
||||
.takes_value(true)
|
||||
.default_missing_value("0")
|
||||
.help("use hex suffixes starting at 0, not alphabetic"),
|
||||
.help("use hex suffixes instead of alphabetic"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(OPT_VERBOSE)
|
||||
|
@ -271,9 +271,9 @@ impl Strategy {
|
|||
/// Parse the suffix type from the command-line arguments.
|
||||
fn suffix_type_from(matches: &ArgMatches) -> SuffixType {
|
||||
if matches.occurrences_of(OPT_NUMERIC_SUFFIXES) > 0 {
|
||||
SuffixType::NumericDecimal
|
||||
SuffixType::Decimal
|
||||
} else if matches.occurrences_of(OPT_HEX_SUFFIXES) > 0 {
|
||||
SuffixType::NumericHexadecimal
|
||||
SuffixType::Hexadecimal
|
||||
} else {
|
||||
SuffixType::Alphabetic
|
||||
}
|
||||
|
@ -311,11 +311,14 @@ enum SettingsError {
|
|||
Strategy(StrategyError),
|
||||
|
||||
/// Invalid suffix length parameter.
|
||||
SuffixLength(String),
|
||||
SuffixNotParsable(String),
|
||||
|
||||
/// Suffix contains a directory separator, which is not allowed.
|
||||
SuffixContainsSeparator(String),
|
||||
|
||||
/// Suffix is not large enough to split into specified chunks
|
||||
SuffixTooSmall(usize),
|
||||
|
||||
/// The `--filter` option is not supported on Windows.
|
||||
#[cfg(windows)]
|
||||
NotSupported,
|
||||
|
@ -335,7 +338,8 @@ impl fmt::Display for SettingsError {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Strategy(e) => e.fmt(f),
|
||||
Self::SuffixLength(s) => write!(f, "invalid suffix length: {}", s.quote()),
|
||||
Self::SuffixNotParsable(s) => write!(f, "invalid suffix length: {}", s.quote()),
|
||||
Self::SuffixTooSmall(i) => write!(f, "the suffix length needs to be at least {}", i),
|
||||
Self::SuffixContainsSeparator(s) => write!(
|
||||
f,
|
||||
"invalid suffix {}, contains directory separator",
|
||||
|
@ -358,15 +362,29 @@ impl Settings {
|
|||
if additional_suffix.contains('/') {
|
||||
return Err(SettingsError::SuffixContainsSeparator(additional_suffix));
|
||||
}
|
||||
let strategy = Strategy::from(matches).map_err(SettingsError::Strategy)?;
|
||||
let suffix_type = suffix_type_from(matches);
|
||||
let suffix_length_str = matches.value_of(OPT_SUFFIX_LENGTH).unwrap();
|
||||
let suffix_length: usize = suffix_length_str
|
||||
.parse()
|
||||
.map_err(|_| SettingsError::SuffixNotParsable(suffix_length_str.to_string()))?;
|
||||
if let Strategy::Number(chunks) = strategy {
|
||||
if suffix_length != 0 {
|
||||
let required_suffix_length =
|
||||
(chunks as f64).log(suffix_type.radix() as f64).ceil() as usize;
|
||||
if suffix_length < required_suffix_length {
|
||||
return Err(SettingsError::SuffixTooSmall(required_suffix_length));
|
||||
}
|
||||
}
|
||||
}
|
||||
let result = Self {
|
||||
suffix_length: suffix_length_str
|
||||
.parse()
|
||||
.map_err(|_| SettingsError::SuffixLength(suffix_length_str.to_string()))?,
|
||||
suffix_type: suffix_type_from(matches),
|
||||
.map_err(|_| SettingsError::SuffixNotParsable(suffix_length_str.to_string()))?,
|
||||
suffix_type,
|
||||
additional_suffix,
|
||||
verbose: matches.occurrences_of("verbose") > 0,
|
||||
strategy: Strategy::from(matches).map_err(SettingsError::Strategy)?,
|
||||
strategy,
|
||||
input: matches.value_of(ARG_INPUT).unwrap().to_owned(),
|
||||
prefix: matches.value_of(ARG_PREFIX).unwrap().to_owned(),
|
||||
filter: matches.value_of(OPT_FILTER).map(|s| s.to_owned()),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue