From 3ca21940f8c8f75c3948ed07465a26cf0dc0f960 Mon Sep 17 00:00:00 2001 From: Rein F Date: Sat, 27 Mar 2021 08:55:31 +0100 Subject: [PATCH] nl: move from getopts to clap (#1921) --- src/uu/nl/Cargo.toml | 2 +- src/uu/nl/src/helper.rs | 26 +++--- src/uu/nl/src/nl.rs | 202 +++++++++++++++++++++------------------- 3 files changed, 119 insertions(+), 111 deletions(-) diff --git a/src/uu/nl/Cargo.toml b/src/uu/nl/Cargo.toml index d5cddbde2..41f7c60ab 100644 --- a/src/uu/nl/Cargo.toml +++ b/src/uu/nl/Cargo.toml @@ -15,8 +15,8 @@ edition = "2018" path = "src/nl.rs" [dependencies] +clap = "2.33.3" aho-corasick = "0.7.3" -getopts = "0.2.18" libc = "0.2.42" memchr = "2.2.0" regex = "1.0.1" diff --git a/src/uu/nl/src/helper.rs b/src/uu/nl/src/helper.rs index 9b98129f1..94ff835d7 100644 --- a/src/uu/nl/src/helper.rs +++ b/src/uu/nl/src/helper.rs @@ -1,5 +1,7 @@ // spell-checker:ignore (ToDO) conv +use crate::options; + // parse_style parses a style string into a NumberingStyle. fn parse_style(chars: &[char]) -> Result { if chars.len() == 1 && chars[0] == 'a' { @@ -23,17 +25,17 @@ fn parse_style(chars: &[char]) -> Result { // parse_options loads the options into the settings, returning an array of // error messages. -pub fn parse_options(settings: &mut crate::Settings, opts: &getopts::Matches) -> Vec { +pub fn parse_options(settings: &mut crate::Settings, opts: &clap::ArgMatches) -> Vec { // This vector holds error messages encountered. let mut errs: Vec = vec![]; - settings.renumber = !opts.opt_present("p"); - match opts.opt_str("s") { + settings.renumber = !opts.is_present(options::NO_RENUMBER); + match opts.value_of(options::NUMER_SEPARATOR) { None => {} Some(val) => { - settings.number_separator = val; + settings.number_separator = val.to_owned(); } } - match opts.opt_str("n") { + match opts.value_of(options::NUMBER_FORMAT) { None => {} Some(val) => match val.as_ref() { "ln" => { @@ -50,7 +52,7 @@ pub fn parse_options(settings: &mut crate::Settings, opts: &getopts::Matches) -> } }, } - match opts.opt_str("b") { + match opts.value_of(options::BODY_NUMBERING) { None => {} Some(val) => { let chars: Vec = val.chars().collect(); @@ -64,7 +66,7 @@ pub fn parse_options(settings: &mut crate::Settings, opts: &getopts::Matches) -> } } } - match opts.opt_str("f") { + match opts.value_of(options::FOOTER_NUMBERING) { None => {} Some(val) => { let chars: Vec = val.chars().collect(); @@ -78,7 +80,7 @@ pub fn parse_options(settings: &mut crate::Settings, opts: &getopts::Matches) -> } } } - match opts.opt_str("h") { + match opts.value_of(options::HEADER_NUMBERING) { None => {} Some(val) => { let chars: Vec = val.chars().collect(); @@ -92,7 +94,7 @@ pub fn parse_options(settings: &mut crate::Settings, opts: &getopts::Matches) -> } } } - match opts.opt_str("i") { + match opts.value_of(options::LINE_INCREMENT) { None => {} Some(val) => { let conv: Option = val.parse().ok(); @@ -104,7 +106,7 @@ pub fn parse_options(settings: &mut crate::Settings, opts: &getopts::Matches) -> } } } - match opts.opt_str("w") { + match opts.value_of(options::NUMBER_WIDTH) { None => {} Some(val) => { let conv: Option = val.parse().ok(); @@ -116,7 +118,7 @@ pub fn parse_options(settings: &mut crate::Settings, opts: &getopts::Matches) -> } } } - match opts.opt_str("v") { + match opts.value_of(options::STARTING_LINE_NUMER) { None => {} Some(val) => { let conv: Option = val.parse().ok(); @@ -128,7 +130,7 @@ pub fn parse_options(settings: &mut crate::Settings, opts: &getopts::Matches) -> } } } - match opts.opt_str("l") { + match opts.value_of(options::JOIN_BLANK_LINES) { None => {} Some(val) => { let conv: Option = val.parse().ok(); diff --git a/src/uu/nl/src/nl.rs b/src/uu/nl/src/nl.rs index 47b6c3ae9..3b5b5a2e8 100644 --- a/src/uu/nl/src/nl.rs +++ b/src/uu/nl/src/nl.rs @@ -11,6 +11,7 @@ #[macro_use] extern crate uucore; +use clap::{App, Arg}; use std::fs::File; use std::io::{stdin, BufRead, BufReader, Read}; use std::iter::repeat; @@ -67,78 +68,106 @@ enum NumberFormat { RightZero, } +pub mod options { + pub const FILE: &str = "file"; + pub const BODY_NUMBERING: &str = "body-numbering"; + pub const SECTION_DELIMITER: &str = "section-delimiter"; + pub const FOOTER_NUMBERING: &str = "footer-numbering"; + pub const HEADER_NUMBERING: &str = "header-numbering"; + pub const LINE_INCREMENT: &str = "line-increment"; + pub const JOIN_BLANK_LINES: &str = "join-blank-lines"; + pub const NUMBER_FORMAT: &str = "number-format"; + pub const NO_RENUMBER: &str = "no-renumber"; + pub const NUMER_SEPARATOR: &str = "number-separator"; + pub const STARTING_LINE_NUMER: &str = "starting-line-number"; + pub const NUMBER_WIDTH: &str = "number-width"; +} + pub fn uumain(args: impl uucore::Args) -> i32 { let args = args.collect_str(); - let mut opts = getopts::Options::new(); - - opts.optopt( - "b", - "body-numbering", - "use STYLE for numbering body lines", - "STYLE", - ); - opts.optopt( - "d", - "section-delimiter", - "use CC for separating logical pages", - "CC", - ); - opts.optopt( - "f", - "footer-numbering", - "use STYLE for numbering footer lines", - "STYLE", - ); - opts.optopt( - "h", - "header-numbering", - "use STYLE for numbering header lines", - "STYLE", - ); - opts.optopt( - "i", - "line-increment", - "line number increment at each line", - "", - ); - opts.optopt( - "l", - "join-blank-lines", - "group of NUMBER empty lines counted as one", - "NUMBER", - ); - opts.optopt( - "n", - "number-format", - "insert line numbers according to FORMAT", - "FORMAT", - ); - opts.optflag( - "p", - "no-renumber", - "do not reset line numbers at logical pages", - ); - opts.optopt( - "s", - "number-separator", - "add STRING after (possible) line number", - "STRING", - ); - opts.optopt( - "v", - "starting-line-number", - "first line number on each logical page", - "NUMBER", - ); - opts.optopt( - "w", - "number-width", - "use NUMBER columns for line numbers", - "NUMBER", - ); - opts.optflag("", "help", "display this help and exit"); - opts.optflag("V", "version", "version"); + let matches = App::new(executable!()) + .name(NAME) + .version(VERSION) + .usage(USAGE) + .arg(Arg::with_name(options::FILE).hidden(true).multiple(true)) + .arg( + Arg::with_name(options::BODY_NUMBERING) + .short("b") + .long(options::BODY_NUMBERING) + .help("use STYLE for numbering body lines") + .value_name("SYNTAX"), + ) + .arg( + Arg::with_name(options::SECTION_DELIMITER) + .short("d") + .long(options::SECTION_DELIMITER) + .help("use CC for separating logical pages") + .value_name("CC"), + ) + .arg( + Arg::with_name(options::FOOTER_NUMBERING) + .short("f") + .long(options::FOOTER_NUMBERING) + .help("use STYLE for numbering footer lines") + .value_name("STYLE"), + ) + .arg( + Arg::with_name(options::HEADER_NUMBERING) + .short("h") + .long(options::HEADER_NUMBERING) + .help("use STYLE for numbering header lines") + .value_name("STYLE"), + ) + .arg( + Arg::with_name(options::LINE_INCREMENT) + .short("i") + .long(options::LINE_INCREMENT) + .help("line number increment at each line") + .value_name("NUMBER"), + ) + .arg( + Arg::with_name(options::JOIN_BLANK_LINES) + .short("l") + .long(options::JOIN_BLANK_LINES) + .help("group of NUMBER empty lines counted as one") + .value_name("NUMBER"), + ) + .arg( + Arg::with_name(options::NUMBER_FORMAT) + .short("n") + .long(options::NUMBER_FORMAT) + .help("insert line numbers according to FORMAT") + .value_name("FORMAT"), + ) + .arg( + Arg::with_name(options::NO_RENUMBER) + .short("p") + .long(options::NO_RENUMBER) + .help("do not reset line numbers at logical pages"), + ) + .arg( + Arg::with_name(options::NUMER_SEPARATOR) + .short("s") + .long(options::NUMER_SEPARATOR) + .help("add STRING after (possible) line number") + .value_name("STRING"), + ) + .arg( + Arg::with_name(options::STARTING_LINE_NUMER) + .short("v") + .long(options::STARTING_LINE_NUMER) + .help("first line number on each logical page") + .value_name("NUMBER"), + ) + .arg( + Arg::with_name(options::NUMBER_WIDTH) + .short("w") + .long(options::NUMBER_WIDTH) + .help("use NUMBER columns for line numbers") + .value_name("NUMBER"), + ) + .get_matches_from(args); // A mutable settings object, initialized with the defaults. let mut settings = Settings { @@ -155,27 +184,9 @@ pub fn uumain(args: impl uucore::Args) -> i32 { number_separator: String::from("\t"), }; - let given_options = match opts.parse(&args[1..]) { - Ok(m) => m, - Err(f) => { - show_error!("{}", f); - print_usage(&opts); - return 1; - } - }; - - if given_options.opt_present("help") { - print_usage(&opts); - return 0; - } - if given_options.opt_present("version") { - version(); - return 0; - } - // Update the settings from the command line options, and terminate the // program if some options could not successfully be parsed. - let parse_errors = helper::parse_options(&mut settings, &given_options); + let parse_errors = helper::parse_options(&mut settings, &matches); if !parse_errors.is_empty() { show_error!("Invalid arguments supplied."); for message in &parse_errors { @@ -184,8 +195,11 @@ pub fn uumain(args: impl uucore::Args) -> i32 { return 1; } - let files = given_options.free; - let mut read_stdin = files.is_empty(); + let mut read_stdin = false; + let files: Vec = match matches.values_of(options::FILE) { + Some(v) => v.clone().map(|v| v.to_owned()).collect(), + None => vec!["-".to_owned()], + }; for file in &files { if file == "-" { @@ -370,11 +384,3 @@ fn pass_none(_: &str, _: ®ex::Regex) -> bool { fn pass_all(_: &str, _: ®ex::Regex) -> bool { true } - -fn print_usage(opts: &getopts::Options) { - println!("{}", opts.usage(USAGE)); -} - -fn version() { - println!("{} {}", NAME, VERSION); -}