From ce064dc62ecdf8a7613d3b5c49f8b5f3c9a9a78b Mon Sep 17 00:00:00 2001 From: Anuvrat Parashar Date: Sun, 10 May 2020 21:31:58 +0200 Subject: [PATCH] feature(head): Introduce NLines to handle negative lines parameters --- src/uu/head/src/head.rs | 30 ++++++++++++++++++++++++++---- tests/test_head.rs | 9 +++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/uu/head/src/head.rs b/src/uu/head/src/head.rs index c9542d108..f330c0320 100644 --- a/src/uu/head/src/head.rs +++ b/src/uu/head/src/head.rs @@ -14,6 +14,7 @@ #[macro_use] extern crate uucore; +use std::collections::VecDeque; use std::fs::File; use std::io::{stdin, BufRead, BufReader, Read}; use std::path::Path; @@ -26,6 +27,7 @@ static LONG_HELP: &str = ""; enum FilterMode { Bytes(usize), Lines(usize), + NLines(usize), } struct Settings { @@ -74,7 +76,6 @@ pub fn uumain(args: Vec) -> i32 { .parse(new_args); let use_bytes = matches.opt_present("c"); - // TODO: suffixes (e.g. b, kB, etc.) match matches.opt_str("n") { Some(n) => { @@ -82,8 +83,17 @@ pub fn uumain(args: Vec) -> i32 { show_error!("cannot specify both --bytes and --lines."); return 1; } - match n.parse::() { - Ok(m) => settings.mode = FilterMode::Lines(m), + + match n.parse::() { + Ok(m) => { + settings.mode = if m < 0 { + let m: usize = m.abs() as usize; + FilterMode::NLines(m) + } else { + let m: usize = m.abs() as usize; + FilterMode::Lines(m) + } + } Err(e) => { show_error!("invalid line count '{}': {}", n, e); return 1; @@ -158,10 +168,11 @@ fn obsolete(options: &[String]) -> (Vec, Option) { let b = options.len(); while a < b { + let previous = options[a - 1].clone(); let current = options[a].clone(); let current = current.as_bytes(); - if current.len() > 1 && current[0] == b'-' { + if previous != "-n" && current.len() > 1 && current[0] == b'-' { let len = current.len(); for pos in 1..len { // Ensure that the argument is only made out of digits @@ -198,6 +209,17 @@ fn head(reader: &mut BufReader, settings: &Settings) -> bool { println!("{}", line.unwrap()); } } + FilterMode::NLines(count) => { + let mut vector: VecDeque = VecDeque::new(); + + for line in reader.lines() { + vector.push_back(line.unwrap()); + if vector.len() <= count { + continue; + } + println!("{}", vector.pop_front().unwrap()); + } + } } true } diff --git a/tests/test_head.rs b/tests/test_head.rs index 57f02b3d7..4dc34715c 100644 --- a/tests/test_head.rs +++ b/tests/test_head.rs @@ -28,6 +28,15 @@ fn test_stdin_1_line() { .stdout_is_fixture("lorem_ipsum_1_line.expected"); } +#[test] +fn test_stdin_negative_23_line() { + new_ucmd!() + .args(&["-n", "-23"]) + .pipe_in_fixture(INPUT) + .run() + .stdout_is_fixture("lorem_ipsum_1_line.expected"); +} + #[test] fn test_stdin_5_chars() { new_ucmd!()