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"
[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"

View file

@ -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<crate::NumberingStyle, String> {
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
// 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.
let mut errs: Vec<String> = 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<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 => {}
Some(val) => {
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 => {}
Some(val) => {
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 => {}
Some(val) => {
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 => {}
Some(val) => {
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 => {}
Some(val) => {
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 => {}
Some(val) => {
let conv: Option<u64> = val.parse().ok();

View file

@ -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<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 {
if file == "-" {
@ -370,11 +384,3 @@ fn pass_none(_: &str, _: &regex::Regex) -> bool {
fn pass_all(_: &str, _: &regex::Regex) -> bool {
true
}
fn print_usage(opts: &getopts::Options) {
println!("{}", opts.usage(USAGE));
}
fn version() {
println!("{} {}", NAME, VERSION);
}