From 0bf14da490c49bacfa078d8acfee14def48ed701 Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Fri, 28 May 2021 21:12:03 +0200 Subject: [PATCH] tail: use "parse_size" from uucore --- src/uu/tail/src/tail.rs | 124 +++++-------------------------------- tests/by-util/test_tail.rs | 36 ----------- 2 files changed, 16 insertions(+), 144 deletions(-) diff --git a/src/uu/tail/src/tail.rs b/src/uu/tail/src/tail.rs index 15a819d35..a4634714c 100644 --- a/src/uu/tail/src/tail.rs +++ b/src/uu/tail/src/tail.rs @@ -21,13 +21,13 @@ use chunks::ReverseChunks; use clap::{App, Arg}; use std::collections::VecDeque; -use std::error::Error; use std::fmt; use std::fs::File; use std::io::{stdin, stdout, BufRead, BufReader, Read, Seek, SeekFrom, Write}; use std::path::Path; use std::thread::sleep; use std::time::Duration; +use uucore::parse_size::parse_size; use uucore::ringbuffer::RingBuffer; pub mod options { @@ -47,8 +47,8 @@ pub mod options { static ARG_FILES: &str = "files"; enum FilterMode { - Bytes(u64), - Lines(u64, u8), // (number of lines, delimiter) + Bytes(usize), + Lines(usize, u8), // (number of lines, delimiter) } struct Settings { @@ -174,31 +174,31 @@ pub fn uumain(args: impl uucore::Args) -> i32 { match matches.value_of(options::LINES) { Some(n) => { let mut slice: &str = n; - if slice.chars().next().unwrap_or('_') == '+' { - settings.beginning = true; + let c = slice.chars().next().unwrap_or('_'); + if c == '+' || c == '-' { slice = &slice[1..]; + if c == '+' { + settings.beginning = true; + } } match parse_size(slice) { Ok(m) => settings.mode = FilterMode::Lines(m, b'\n'), - Err(e) => { - show_error!("{}", e.to_string()); - return 1; - } + Err(e) => crash!(1, "invalid number of bytes: {}", e.to_string()), } } None => { if let Some(n) = matches.value_of(options::BYTES) { let mut slice: &str = n; - if slice.chars().next().unwrap_or('_') == '+' { - settings.beginning = true; + let c = slice.chars().next().unwrap_or('_'); + if c == '+' || c == '-' { slice = &slice[1..]; + if c == '+' { + settings.beginning = true; + } } match parse_size(slice) { Ok(m) => settings.mode = FilterMode::Bytes(m), - Err(e) => { - show_error!("{}", e.to_string()); - return 1; - } + Err(e) => crash!(1, "invalid number of bytes: {}", e.to_string()), } } } @@ -264,98 +264,6 @@ pub fn uumain(args: impl uucore::Args) -> i32 { 0 } -#[derive(Debug, PartialEq, Eq)] -pub enum ParseSizeErr { - ParseFailure(String), - SizeTooBig(String), -} - -impl Error for ParseSizeErr { - fn description(&self) -> &str { - match *self { - ParseSizeErr::ParseFailure(ref s) => &*s, - ParseSizeErr::SizeTooBig(ref s) => &*s, - } - } -} - -impl fmt::Display for ParseSizeErr { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - let s = match self { - ParseSizeErr::ParseFailure(s) => s, - ParseSizeErr::SizeTooBig(s) => s, - }; - write!(f, "{}", s) - } -} - -impl ParseSizeErr { - fn parse_failure(s: &str) -> ParseSizeErr { - ParseSizeErr::ParseFailure(format!("invalid size: '{}'", s)) - } - - fn size_too_big(s: &str) -> ParseSizeErr { - ParseSizeErr::SizeTooBig(format!( - "invalid size: '{}': Value too large to be stored in data type", - s - )) - } -} - -pub type ParseSizeResult = Result; - -pub fn parse_size(mut size_slice: &str) -> Result { - let mut base = if size_slice.chars().last().unwrap_or('_') == 'B' { - size_slice = &size_slice[..size_slice.len() - 1]; - 1000u64 - } else { - 1024u64 - }; - - let exponent = if !size_slice.is_empty() { - let mut has_suffix = true; - let exp = match size_slice.chars().last().unwrap_or('_') { - 'K' | 'k' => 1u64, - 'M' => 2u64, - 'G' => 3u64, - 'T' => 4u64, - 'P' => 5u64, - 'E' => 6u64, - 'Z' | 'Y' => { - return Err(ParseSizeErr::size_too_big(size_slice)); - } - 'b' => { - base = 512u64; - 1u64 - } - _ => { - has_suffix = false; - 0u64 - } - }; - if has_suffix { - size_slice = &size_slice[..size_slice.len() - 1]; - } - exp - } else { - 0u64 - }; - - let mut multiplier = 1u64; - for _ in 0u64..exponent { - multiplier *= base; - } - if base == 1000u64 && exponent == 0u64 { - // sole B is not a valid suffix - Err(ParseSizeErr::parse_failure(size_slice)) - } else { - let value: Option = size_slice.parse().ok(); - value - .map(|v| Ok((multiplier as i64 * v.abs()) as u64)) - .unwrap_or_else(|| Err(ParseSizeErr::parse_failure(size_slice))) - } -} - fn follow(readers: &mut [BufReader], filenames: &[String], settings: &Settings) { assert!(settings.follow); let mut last = readers.len() - 1; @@ -469,7 +377,7 @@ fn bounded_tail(file: &mut File, settings: &Settings) { /// If any element of `iter` is an [`Err`], then this function panics. fn unbounded_tail_collect( iter: impl Iterator>, - count: u64, + count: usize, beginning: bool, ) -> VecDeque where diff --git a/tests/by-util/test_tail.rs b/tests/by-util/test_tail.rs index f3c9a7b11..27e94a78f 100644 --- a/tests/by-util/test_tail.rs +++ b/tests/by-util/test_tail.rs @@ -1,6 +1,5 @@ extern crate tail; -use self::tail::parse_size; use crate::common::util::*; use std::char::from_digit; use std::io::Write; @@ -236,41 +235,6 @@ fn test_bytes_big() { } } -#[test] -fn test_parse_size() { - // No suffix. - assert_eq!(Ok(1234), parse_size("1234")); - - // kB is 1000 - assert_eq!(Ok(9 * 1000), parse_size("9kB")); - - // K is 1024 - assert_eq!(Ok(2 * 1024), parse_size("2K")); - - let suffixes = [ - ('M', 2u32), - ('G', 3u32), - ('T', 4u32), - ('P', 5u32), - ('E', 6u32), - ]; - - for &(c, exp) in &suffixes { - let s = format!("2{}B", c); - assert_eq!(Ok(2 * (1000 as u64).pow(exp)), parse_size(&s)); - - let s = format!("2{}", c); - assert_eq!(Ok(2 * (1024 as u64).pow(exp)), parse_size(&s)); - } - - // Sizes that are too big. - assert!(parse_size("1Z").is_err()); - assert!(parse_size("1Y").is_err()); - - // Bad number - assert!(parse_size("328hdsf3290").is_err()); -} - #[test] fn test_lines_with_size_suffix() { const FILE: &'static str = "test_lines_with_size_suffix.txt";