From 388f249716f6e036fc6bbe5c8ec317e2ff62c481 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Thu, 13 Jul 2023 15:31:15 +0200 Subject: [PATCH] nl: allow negative values for -i and -v --- src/uu/nl/src/helper.rs | 28 +++-------------- src/uu/nl/src/nl.rs | 14 +++++---- tests/by-util/test_nl.rs | 68 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 80 insertions(+), 30 deletions(-) diff --git a/src/uu/nl/src/helper.rs b/src/uu/nl/src/helper.rs index 341f116c3..2a90cb130 100644 --- a/src/uu/nl/src/helper.rs +++ b/src/uu/nl/src/helper.rs @@ -79,18 +79,6 @@ pub fn parse_options(settings: &mut crate::Settings, opts: &clap::ArgMatches) -> } } } - match opts.get_one::(options::LINE_INCREMENT) { - None => {} - Some(val) => { - let conv: Option = val.parse().ok(); - match conv { - None => { - errs.push(String::from("Illegal value for -i")); - } - Some(num) => settings.line_increment = num, - } - } - } match opts.get_one::(options::NUMBER_WIDTH) { None => {} Some(num) if *num > 0 => settings.number_width = *num, @@ -98,17 +86,11 @@ pub fn parse_options(settings: &mut crate::Settings, opts: &clap::ArgMatches) -> "Invalid line number field width: ‘0’: Numerical result out of range", )), } - match opts.get_one::(options::STARTING_LINE_NUMBER) { - None => {} - Some(val) => { - let conv: Option = val.parse().ok(); - match conv { - None => { - errs.push(String::from("Illegal value for -v")); - } - Some(num) => settings.starting_line_number = num, - } - } + if let Some(num) = opts.get_one::(options::LINE_INCREMENT) { + settings.line_increment = *num; + } + if let Some(num) = opts.get_one::(options::STARTING_LINE_NUMBER) { + settings.starting_line_number = *num; } match opts.get_one::(options::JOIN_BLANK_LINES) { None => {} diff --git a/src/uu/nl/src/nl.rs b/src/uu/nl/src/nl.rs index 8c0e89a44..b2edaa83b 100644 --- a/src/uu/nl/src/nl.rs +++ b/src/uu/nl/src/nl.rs @@ -29,8 +29,8 @@ pub struct Settings { // The variable corresponding to -d section_delimiter: [char; 2], // The variables corresponding to the options -v, -i, -l, -w. - starting_line_number: u64, - line_increment: u64, + starting_line_number: i64, + line_increment: i64, join_blank_lines: u64, number_width: usize, // Used with String::from_char, hence usize. // The format of the number and the (default value for) @@ -208,7 +208,8 @@ pub fn uu_app() -> Command { .short('i') .long(options::LINE_INCREMENT) .help("line number increment at each line") - .value_name("NUMBER"), + .value_name("NUMBER") + .value_parser(clap::value_parser!(i64)), ) .arg( Arg::new(options::JOIN_BLANK_LINES) @@ -244,7 +245,8 @@ pub fn uu_app() -> Command { .short('v') .long(options::STARTING_LINE_NUMBER) .help("first line number on each logical page") - .value_name("NUMBER"), + .value_name("NUMBER") + .value_parser(clap::value_parser!(i64)), ) .arg( Arg::new(options::NUMBER_WIDTH) @@ -267,7 +269,7 @@ fn nl(reader: &mut BufReader, settings: &Settings) -> UResult<()> { let line_no_width_initial = line_no_width; // Stores the smallest integer with one more digit than line_no, so that // when line_no >= line_no_threshold, we need to use one more digit. - let mut line_no_threshold = 10u64.pow(line_no_width as u32); + let mut line_no_threshold = 10i64.pow(line_no_width as u32); let mut empty_line_count: u64 = 0; let fill_char = match settings.number_format { NumberFormat::RightZero => '0', @@ -329,7 +331,7 @@ fn nl(reader: &mut BufReader, settings: &Settings) -> UResult<()> { if settings.renumber { line_no = settings.starting_line_number; line_no_width = line_no_width_initial; - line_no_threshold = 10u64.pow(line_no_width as u32); + line_no_threshold = 10i64.pow(line_no_width as u32); } &settings.header_numbering } diff --git a/tests/by-util/test_nl.rs b/tests/by-util/test_nl.rs index f75f3f483..7325dfe8c 100644 --- a/tests/by-util/test_nl.rs +++ b/tests/by-util/test_nl.rs @@ -1,4 +1,4 @@ -// spell-checker:ignore ninvalid winvalid +// spell-checker:ignore iinvalid ninvalid vinvalid winvalid use crate::common::util::TestScenario; #[test] @@ -13,6 +13,7 @@ fn test_stdin_no_newline() { .run() .stdout_is(" 1\tNo Newline\n"); } + #[test] fn test_stdin_newline() { new_ucmd!() @@ -167,3 +168,68 @@ fn test_number_separator() { .stdout_is(" 1:-:test\n"); } } + +#[test] +fn test_starting_line_number() { + for arg in ["-v10", "--starting-line-number=10"] { + new_ucmd!() + .arg(arg) + .pipe_in("test") + .succeeds() + .stdout_is(" 10\ttest\n"); + } +} + +#[test] +fn test_negative_starting_line_number() { + for arg in ["-v-10", "--starting-line-number=-10"] { + new_ucmd!() + .arg(arg) + .pipe_in("test") + .succeeds() + .stdout_is(" -10\ttest\n"); + } +} + +#[test] +fn test_invalid_starting_line_number() { + for arg in ["-vinvalid", "--starting-line-number=invalid"] { + new_ucmd!() + .arg(arg) + .fails() + .stderr_contains("invalid value 'invalid'"); + } +} + +#[test] +fn test_line_increment() { + for arg in ["-i10", "--line-increment=10"] { + new_ucmd!() + .arg(arg) + .pipe_in("a\nb") + .succeeds() + .stdout_is(" 1\ta\n 11\tb\n"); + } +} + +#[test] +fn test_negative_line_increment() { + // TODO make this test work with -10 + for arg in ["-i-1", "--line-increment=-1"] { + new_ucmd!() + .arg(arg) + .pipe_in("a\nb") + .succeeds() + .stdout_is(" 1\ta\n 0\tb\n"); + } +} + +#[test] +fn test_invalid_line_increment() { + for arg in ["-iinvalid", "--line-increment=invalid"] { + new_ucmd!() + .arg(arg) + .fails() + .stderr_contains("invalid value 'invalid'"); + } +}