1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 19:47:45 +00:00

head: use "parse_size" from uucore

This commit is contained in:
Jan Scheer 2021-06-01 09:30:43 +02:00
parent 8bf1e33b5d
commit 84f2bff778
3 changed files with 42 additions and 127 deletions

View file

@ -107,12 +107,7 @@ where
{ {
match parse::parse_num(src) { match parse::parse_num(src) {
Ok((n, last)) => Ok((closure(n), last)), Ok((n, last)) => Ok((closure(n), last)),
Err(reason) => match reason { Err(e) => Err(e.to_string()),
parse::ParseError::Syntax => Err(format!("'{}'", src)),
parse::ParseError::Overflow => {
Err(format!("'{}': Value too large for defined datatype", src))
}
},
} }
} }
@ -473,7 +468,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let args = match HeadOptions::get_from(args) { let args = match HeadOptions::get_from(args) {
Ok(o) => o, Ok(o) => o,
Err(s) => { Err(s) => {
crash!(EXIT_FAILURE, "head: {}", s); crash!(EXIT_FAILURE, "{}", s);
} }
}; };
match uu_head(&args) { match uu_head(&args) {

View file

@ -1,5 +1,5 @@
use std::convert::TryFrom;
use std::ffi::OsString; use std::ffi::OsString;
use uucore::parse_size::{parse_size, ParseSizeError};
#[derive(PartialEq, Debug)] #[derive(PartialEq, Debug)]
pub enum ParseError { pub enum ParseError {
@ -92,92 +92,25 @@ pub fn parse_obsolete(src: &str) -> Option<Result<impl Iterator<Item = OsString>
} }
/// Parses an -c or -n argument, /// Parses an -c or -n argument,
/// the bool specifies whether to read from the end /// the bool specifies whether to read from the end
pub fn parse_num(src: &str) -> Result<(usize, bool), ParseError> { pub fn parse_num(src: &str) -> Result<(usize, bool), ParseSizeError> {
let mut num_start = 0; let mut size_string = src.trim();
let mut chars = src.char_indices(); let mut all_but_last = false;
let (mut chars, all_but_last) = match chars.next() {
Some((_, c)) => { if let Some(c) = size_string.chars().next() {
if c == '-' { if c == '-' {
num_start += 1; size_string = &size_string[1..];
(chars, true) all_but_last = true;
} else {
(src.char_indices(), false)
}
}
None => return Err(ParseError::Syntax),
};
let mut num_end = 0usize;
let mut last_char = 0 as char;
let mut num_count = 0usize;
for (n, c) in &mut chars {
if c.is_numeric() {
num_end = n;
num_count += 1;
} else {
last_char = c;
break;
} }
} else {
return Err(ParseSizeError::ParseFailure(src.to_string()));
} }
let num = if num_count > 0 { match parse_size(&size_string) {
match src[num_start..=num_end].parse::<usize>() { Ok(n) => Ok((n, all_but_last)),
Ok(n) => Some(n), Err(e) => Err(e),
Err(_) => return Err(ParseError::Overflow),
}
} else {
None
};
if last_char == 0 as char {
if let Some(n) = num {
Ok((n, all_but_last))
} else {
Err(ParseError::Syntax)
}
} else {
let base: u128 = match chars.next() {
Some((_, c)) => {
let b = match c {
'B' if last_char != 'b' => 1000,
'i' if last_char != 'b' => {
if let Some((_, 'B')) = chars.next() {
1024
} else {
return Err(ParseError::Syntax);
}
}
_ => return Err(ParseError::Syntax),
};
if chars.next().is_some() {
return Err(ParseError::Syntax);
} else {
b
}
}
None => 1024,
};
let mul = match last_char.to_lowercase().next().unwrap() {
'b' => 512,
'k' => base.pow(1),
'm' => base.pow(2),
'g' => base.pow(3),
't' => base.pow(4),
'p' => base.pow(5),
'e' => base.pow(6),
'z' => base.pow(7),
'y' => base.pow(8),
_ => return Err(ParseError::Syntax),
};
let mul = match usize::try_from(mul) {
Ok(n) => n,
Err(_) => return Err(ParseError::Overflow),
};
match num.unwrap_or(1).checked_mul(mul) {
Some(n) => Ok((n, all_but_last)),
None => Err(ParseError::Overflow),
}
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -195,44 +128,6 @@ mod tests {
Some(Ok(src.iter().map(|s| s.to_string()).collect())) Some(Ok(src.iter().map(|s| s.to_string()).collect()))
} }
#[test] #[test]
#[cfg(not(target_pointer_width = "128"))]
fn test_parse_overflow_x64() {
assert_eq!(parse_num("1Y"), Err(ParseError::Overflow));
assert_eq!(parse_num("1Z"), Err(ParseError::Overflow));
assert_eq!(parse_num("100E"), Err(ParseError::Overflow));
assert_eq!(parse_num("100000P"), Err(ParseError::Overflow));
assert_eq!(parse_num("1000000000T"), Err(ParseError::Overflow));
assert_eq!(
parse_num("10000000000000000000000"),
Err(ParseError::Overflow)
);
}
#[test]
#[cfg(target_pointer_width = "32")]
fn test_parse_overflow_x32() {
assert_eq!(parse_num("1T"), Err(ParseError::Overflow));
assert_eq!(parse_num("1000G"), Err(ParseError::Overflow));
}
#[test]
fn test_parse_bad_syntax() {
assert_eq!(parse_num("5MiB nonsense"), Err(ParseError::Syntax));
assert_eq!(parse_num("Nonsense string"), Err(ParseError::Syntax));
assert_eq!(parse_num("5mib"), Err(ParseError::Syntax));
assert_eq!(parse_num("biB"), Err(ParseError::Syntax));
assert_eq!(parse_num("-"), Err(ParseError::Syntax));
assert_eq!(parse_num(""), Err(ParseError::Syntax));
}
#[test]
fn test_parse_numbers() {
assert_eq!(parse_num("k"), Ok((1024, false)));
assert_eq!(parse_num("MiB"), Ok((1024 * 1024, false)));
assert_eq!(parse_num("-5"), Ok((5, true)));
assert_eq!(parse_num("b"), Ok((512, false)));
assert_eq!(parse_num("-2GiB"), Ok((2 * 1024 * 1024 * 1024, true)));
assert_eq!(parse_num("5M"), Ok((5 * 1024 * 1024, false)));
assert_eq!(parse_num("5MB"), Ok((5 * 1000 * 1000, false)));
}
#[test]
fn test_parse_numbers_obsolete() { fn test_parse_numbers_obsolete() {
assert_eq!(obsolete("-5"), obsolete_result(&["-n", "5"])); assert_eq!(obsolete("-5"), obsolete_result(&["-n", "5"]));
assert_eq!(obsolete("-100"), obsolete_result(&["-n", "100"])); assert_eq!(obsolete("-100"), obsolete_result(&["-n", "100"]));

View file

@ -242,3 +242,28 @@ hello
", ",
); );
} }
#[test]
fn test_head_invalid_num() {
new_ucmd!()
.args(&["-c", "1024R", "emptyfile.txt"])
.fails()
.stderr_is("head: invalid number of bytes: 1024R");
new_ucmd!()
.args(&["-n", "1024R", "emptyfile.txt"])
.fails()
.stderr_is("head: invalid number of lines: 1024R");
#[cfg(not(target_pointer_width = "128"))]
new_ucmd!()
.args(&["-c", "1Y", "emptyfile.txt"])
.fails()
.stderr_is(
"head: invalid number of bytes: 1Y: Value too large to be stored in data type",
);
#[cfg(not(target_pointer_width = "128"))]
new_ucmd!()
.args(&["-n", "1Y", "emptyfile.txt"])
.fails()
.stderr_is(
"head: invalid number of lines: 1Y: Value too large to be stored in data type",
);
}