1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

nl: move from getopts to clap (#1921)

This commit is contained in:
Rein F 2021-03-27 08:55:31 +01:00 committed by GitHub
parent 955c547adf
commit 3ca21940f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 119 additions and 111 deletions

View file

@ -15,8 +15,8 @@ edition = "2018"
path = "src/nl.rs" path = "src/nl.rs"
[dependencies] [dependencies]
clap = "2.33.3"
aho-corasick = "0.7.3" aho-corasick = "0.7.3"
getopts = "0.2.18"
libc = "0.2.42" libc = "0.2.42"
memchr = "2.2.0" memchr = "2.2.0"
regex = "1.0.1" regex = "1.0.1"

View file

@ -1,5 +1,7 @@
// spell-checker:ignore (ToDO) conv // spell-checker:ignore (ToDO) conv
use crate::options;
// parse_style parses a style string into a NumberingStyle. // parse_style parses a style string into a NumberingStyle.
fn parse_style(chars: &[char]) -> Result<crate::NumberingStyle, String> { fn parse_style(chars: &[char]) -> Result<crate::NumberingStyle, String> {
if chars.len() == 1 && chars[0] == 'a' { if chars.len() == 1 && chars[0] == 'a' {
@ -23,17 +25,17 @@ fn parse_style(chars: &[char]) -> Result<crate::NumberingStyle, String> {
// parse_options loads the options into the settings, returning an array of // parse_options loads the options into the settings, returning an array of
// error messages. // error messages.
pub fn parse_options(settings: &mut crate::Settings, opts: &getopts::Matches) -> Vec<String> { pub fn parse_options(settings: &mut crate::Settings, opts: &clap::ArgMatches) -> Vec<String> {
// This vector holds error messages encountered. // This vector holds error messages encountered.
let mut errs: Vec<String> = vec![]; let mut errs: Vec<String> = vec![];
settings.renumber = !opts.opt_present("p"); settings.renumber = !opts.is_present(options::NO_RENUMBER);
match opts.opt_str("s") { match opts.value_of(options::NUMER_SEPARATOR) {
None => {} None => {}
Some(val) => { 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 => {} None => {}
Some(val) => match val.as_ref() { Some(val) => match val.as_ref() {
"ln" => { "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 => {} None => {}
Some(val) => { Some(val) => {
let chars: Vec<char> = val.chars().collect(); let chars: Vec<char> = 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 => {} None => {}
Some(val) => { Some(val) => {
let chars: Vec<char> = val.chars().collect(); let chars: Vec<char> = 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 => {} None => {}
Some(val) => { Some(val) => {
let chars: Vec<char> = val.chars().collect(); let chars: Vec<char> = 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 => {} None => {}
Some(val) => { Some(val) => {
let conv: Option<u64> = val.parse().ok(); let conv: Option<u64> = 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 => {} None => {}
Some(val) => { Some(val) => {
let conv: Option<usize> = val.parse().ok(); let conv: Option<usize> = 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 => {} None => {}
Some(val) => { Some(val) => {
let conv: Option<u64> = val.parse().ok(); let conv: Option<u64> = 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 => {} None => {}
Some(val) => { Some(val) => {
let conv: Option<u64> = val.parse().ok(); let conv: Option<u64> = val.parse().ok();

View file

@ -11,6 +11,7 @@
#[macro_use] #[macro_use]
extern crate uucore; extern crate uucore;
use clap::{App, Arg};
use std::fs::File; use std::fs::File;
use std::io::{stdin, BufRead, BufReader, Read}; use std::io::{stdin, BufRead, BufReader, Read};
use std::iter::repeat; use std::iter::repeat;
@ -67,78 +68,106 @@ enum NumberFormat {
RightZero, 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 { pub fn uumain(args: impl uucore::Args) -> i32 {
let args = args.collect_str(); let args = args.collect_str();
let mut opts = getopts::Options::new(); let matches = App::new(executable!())
.name(NAME)
opts.optopt( .version(VERSION)
"b", .usage(USAGE)
"body-numbering", .arg(Arg::with_name(options::FILE).hidden(true).multiple(true))
"use STYLE for numbering body lines", .arg(
"STYLE", Arg::with_name(options::BODY_NUMBERING)
); .short("b")
opts.optopt( .long(options::BODY_NUMBERING)
"d", .help("use STYLE for numbering body lines")
"section-delimiter", .value_name("SYNTAX"),
"use CC for separating logical pages", )
"CC", .arg(
); Arg::with_name(options::SECTION_DELIMITER)
opts.optopt( .short("d")
"f", .long(options::SECTION_DELIMITER)
"footer-numbering", .help("use CC for separating logical pages")
"use STYLE for numbering footer lines", .value_name("CC"),
"STYLE", )
); .arg(
opts.optopt( Arg::with_name(options::FOOTER_NUMBERING)
"h", .short("f")
"header-numbering", .long(options::FOOTER_NUMBERING)
"use STYLE for numbering header lines", .help("use STYLE for numbering footer lines")
"STYLE", .value_name("STYLE"),
); )
opts.optopt( .arg(
"i", Arg::with_name(options::HEADER_NUMBERING)
"line-increment", .short("h")
"line number increment at each line", .long(options::HEADER_NUMBERING)
"", .help("use STYLE for numbering header lines")
); .value_name("STYLE"),
opts.optopt( )
"l", .arg(
"join-blank-lines", Arg::with_name(options::LINE_INCREMENT)
"group of NUMBER empty lines counted as one", .short("i")
"NUMBER", .long(options::LINE_INCREMENT)
); .help("line number increment at each line")
opts.optopt( .value_name("NUMBER"),
"n", )
"number-format", .arg(
"insert line numbers according to FORMAT", Arg::with_name(options::JOIN_BLANK_LINES)
"FORMAT", .short("l")
); .long(options::JOIN_BLANK_LINES)
opts.optflag( .help("group of NUMBER empty lines counted as one")
"p", .value_name("NUMBER"),
"no-renumber", )
"do not reset line numbers at logical pages", .arg(
); Arg::with_name(options::NUMBER_FORMAT)
opts.optopt( .short("n")
"s", .long(options::NUMBER_FORMAT)
"number-separator", .help("insert line numbers according to FORMAT")
"add STRING after (possible) line number", .value_name("FORMAT"),
"STRING", )
); .arg(
opts.optopt( Arg::with_name(options::NO_RENUMBER)
"v", .short("p")
"starting-line-number", .long(options::NO_RENUMBER)
"first line number on each logical page", .help("do not reset line numbers at logical pages"),
"NUMBER", )
); .arg(
opts.optopt( Arg::with_name(options::NUMER_SEPARATOR)
"w", .short("s")
"number-width", .long(options::NUMER_SEPARATOR)
"use NUMBER columns for line numbers", .help("add STRING after (possible) line number")
"NUMBER", .value_name("STRING"),
); )
opts.optflag("", "help", "display this help and exit"); .arg(
opts.optflag("V", "version", "version"); 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. // A mutable settings object, initialized with the defaults.
let mut settings = Settings { let mut settings = Settings {
@ -155,27 +184,9 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
number_separator: String::from("\t"), 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 // Update the settings from the command line options, and terminate the
// program if some options could not successfully be parsed. // 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() { if !parse_errors.is_empty() {
show_error!("Invalid arguments supplied."); show_error!("Invalid arguments supplied.");
for message in &parse_errors { for message in &parse_errors {
@ -184,8 +195,11 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
return 1; return 1;
} }
let files = given_options.free; let mut read_stdin = false;
let mut read_stdin = files.is_empty(); let files: Vec<String> = match matches.values_of(options::FILE) {
Some(v) => v.clone().map(|v| v.to_owned()).collect(),
None => vec!["-".to_owned()],
};
for file in &files { for file in &files {
if file == "-" { if file == "-" {
@ -370,11 +384,3 @@ fn pass_none(_: &str, _: &regex::Regex) -> bool {
fn pass_all(_: &str, _: &regex::Regex) -> bool { fn pass_all(_: &str, _: &regex::Regex) -> bool {
true true
} }
fn print_usage(opts: &getopts::Options) {
println!("{}", opts.usage(USAGE));
}
fn version() {
println!("{} {}", NAME, VERSION);
}