1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-29 12:07:46 +00:00

uucore: parse_size_max and split

This commit is contained in:
zhitkoff 2023-09-04 12:05:26 -04:00
parent 420965a3ab
commit 636c2bb7ae
2 changed files with 40 additions and 20 deletions

View file

@ -21,7 +21,7 @@ use std::io::{stdin, BufRead, BufReader, BufWriter, ErrorKind, Read, Write};
use std::path::Path; use std::path::Path;
use uucore::display::Quotable; use uucore::display::Quotable;
use uucore::error::{FromIo, UIoError, UResult, USimpleError, UUsageError}; use uucore::error::{FromIo, UIoError, UResult, USimpleError, UUsageError};
use uucore::parse_size::{parse_size, ParseSizeError}; use uucore::parse_size::{parse_size_max, ParseSizeError};
use uucore::uio_error; use uucore::uio_error;
use uucore::{format_usage, help_about, help_section, help_usage}; use uucore::{format_usage, help_about, help_section, help_usage};
@ -419,8 +419,7 @@ impl NumberType {
let parts: Vec<&str> = s.split('/').collect(); let parts: Vec<&str> = s.split('/').collect();
match &parts[..] { match &parts[..] {
[n_str] => { [n_str] => {
let num_chunks = n_str let num_chunks = parse_size_max(n_str)
.parse()
.map_err(|_| NumberTypeError::NumberOfChunks(n_str.to_string()))?; .map_err(|_| NumberTypeError::NumberOfChunks(n_str.to_string()))?;
if num_chunks > 0 { if num_chunks > 0 {
Ok(Self::Bytes(num_chunks)) Ok(Self::Bytes(num_chunks))
@ -429,32 +428,26 @@ impl NumberType {
} }
} }
["l", n_str] => { ["l", n_str] => {
let num_chunks = n_str let num_chunks = parse_size_max(n_str)
.parse()
.map_err(|_| NumberTypeError::NumberOfChunks(n_str.to_string()))?; .map_err(|_| NumberTypeError::NumberOfChunks(n_str.to_string()))?;
Ok(Self::Lines(num_chunks)) Ok(Self::Lines(num_chunks))
} }
["l", k_str, n_str] => { ["l", k_str, n_str] => {
let num_chunks = n_str let num_chunks = parse_size_max(n_str)
.parse()
.map_err(|_| NumberTypeError::NumberOfChunks(n_str.to_string()))?; .map_err(|_| NumberTypeError::NumberOfChunks(n_str.to_string()))?;
let chunk_number = k_str let chunk_number = parse_size_max(k_str)
.parse()
.map_err(|_| NumberTypeError::ChunkNumber(k_str.to_string()))?; .map_err(|_| NumberTypeError::ChunkNumber(k_str.to_string()))?;
Ok(Self::KthLines(chunk_number, num_chunks)) Ok(Self::KthLines(chunk_number, num_chunks))
} }
["r", n_str] => { ["r", n_str] => {
let num_chunks = n_str let num_chunks = parse_size_max(n_str)
.parse()
.map_err(|_| NumberTypeError::NumberOfChunks(n_str.to_string()))?; .map_err(|_| NumberTypeError::NumberOfChunks(n_str.to_string()))?;
Ok(Self::RoundRobin(num_chunks)) Ok(Self::RoundRobin(num_chunks))
} }
["r", k_str, n_str] => { ["r", k_str, n_str] => {
let num_chunks = n_str let num_chunks = parse_size_max(n_str)
.parse()
.map_err(|_| NumberTypeError::NumberOfChunks(n_str.to_string()))?; .map_err(|_| NumberTypeError::NumberOfChunks(n_str.to_string()))?;
let chunk_number = k_str let chunk_number = parse_size_max(k_str)
.parse()
.map_err(|_| NumberTypeError::ChunkNumber(k_str.to_string()))?; .map_err(|_| NumberTypeError::ChunkNumber(k_str.to_string()))?;
Ok(Self::KthRoundRobin(chunk_number, num_chunks)) Ok(Self::KthRoundRobin(chunk_number, num_chunks))
} }
@ -523,7 +516,7 @@ impl Strategy {
error: fn(ParseSizeError) -> StrategyError, error: fn(ParseSizeError) -> StrategyError,
) -> Result<Strategy, StrategyError> { ) -> Result<Strategy, StrategyError> {
let s = matches.get_one::<String>(option).unwrap(); let s = matches.get_one::<String>(option).unwrap();
let n = parse_size(s).map_err(error)?; let n = parse_size_max(s).map_err(error)?;
if n > 0 { if n > 0 {
Ok(strategy(n)) Ok(strategy(n))
} else { } else {
@ -542,7 +535,7 @@ impl Strategy {
matches.value_source(OPT_NUMBER) == Some(ValueSource::CommandLine), matches.value_source(OPT_NUMBER) == Some(ValueSource::CommandLine),
) { ) {
(Some(v), false, false, false, false) => { (Some(v), false, false, false, false) => {
let v = parse_size(v).map_err(|_| { let v = parse_size_max(v).map_err(|_| {
StrategyError::Lines(ParseSizeError::ParseFailure(v.to_string())) StrategyError::Lines(ParseSizeError::ParseFailure(v.to_string()))
})?; })?;
Ok(Self::Lines(v)) Ok(Self::Lines(v))
@ -687,7 +680,6 @@ impl Settings {
if additional_suffix.contains('/') { if additional_suffix.contains('/') {
return Err(SettingsError::SuffixContainsSeparator(additional_suffix)); return Err(SettingsError::SuffixContainsSeparator(additional_suffix));
} }
let strategy = Strategy::from(matches, obs_lines).map_err(SettingsError::Strategy)?; let strategy = Strategy::from(matches, obs_lines).map_err(SettingsError::Strategy)?;
let (suffix_type, suffix_start) = suffix_type_from(matches)?; let (suffix_type, suffix_start) = suffix_type_from(matches)?;
let suffix_length_str = matches.get_one::<String>(OPT_SUFFIX_LENGTH).unwrap(); let suffix_length_str = matches.get_one::<String>(OPT_SUFFIX_LENGTH).unwrap();

View file

@ -7,6 +7,7 @@
use std::error::Error; use std::error::Error;
use std::fmt; use std::fmt;
use std::num::IntErrorKind;
use crate::display::Quotable; use crate::display::Quotable;
@ -201,8 +202,10 @@ impl<'parser> Parser<'parser> {
radix: u32, radix: u32,
original_size: &str, original_size: &str,
) -> Result<u64, ParseSizeError> { ) -> Result<u64, ParseSizeError> {
u64::from_str_radix(numeric_string, radix) u64::from_str_radix(numeric_string, radix).map_err(|e| match e.kind() {
.map_err(|_| ParseSizeError::ParseFailure(original_size.to_string())) IntErrorKind::PosOverflow => ParseSizeError::size_too_big(original_size),
_ => ParseSizeError::ParseFailure(original_size.to_string()),
})
} }
} }
@ -232,6 +235,23 @@ pub fn parse_size(size: &str) -> Result<u64, ParseSizeError> {
Parser::default().parse(size) Parser::default().parse(size)
} }
/// Same as `parse_size()`, except returns `u64::MAX` on overflow
/// GNU lib/coreutils include similar functionality
/// and GNU test suite checks this behavior for some utils
pub fn parse_size_max(size: &str) -> Result<u64, ParseSizeError> {
let result = Parser::default().parse(size);
match result {
Ok(_) => result,
Err(error) => {
if let ParseSizeError::SizeTooBig(_) = error {
Ok(u64::MAX)
} else {
Err(error)
}
}
}
}
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub enum ParseSizeError { pub enum ParseSizeError {
InvalidSuffix(String), // Suffix InvalidSuffix(String), // Suffix
@ -392,6 +412,14 @@ mod tests {
); );
} }
#[test]
#[cfg(not(target_pointer_width = "128"))]
fn overflow_to_max_x64() {
assert_eq!(Ok(u64::MAX), parse_size_max("18446744073709551616"));
assert_eq!(Ok(u64::MAX), parse_size_max("10000000000000000000000"));
assert_eq!(Ok(u64::MAX), parse_size_max("1Y"));
}
#[test] #[test]
fn invalid_suffix() { fn invalid_suffix() {
let test_strings = ["5mib", "1eb", "1H"]; let test_strings = ["5mib", "1eb", "1H"];