1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-30 04:27:45 +00:00

cut: move to clap

This commit is contained in:
Yagiz Degirmenci 2021-04-03 20:19:30 +03:00
parent 20d071a482
commit cfc3d52be4
3 changed files with 124 additions and 28 deletions

1
Cargo.lock generated
View file

@ -1679,6 +1679,7 @@ dependencies = [
name = "uu_cut" name = "uu_cut"
version = "0.0.6" version = "0.0.6"
dependencies = [ dependencies = [
"clap",
"uucore", "uucore",
"uucore_procs", "uucore_procs",
] ]

View file

@ -15,6 +15,7 @@ edition = "2018"
path = "src/cut.rs" path = "src/cut.rs"
[dependencies] [dependencies]
clap = "2.33"
uucore = { version=">=0.0.8", package="uucore", path="../../uucore" } uucore = { version=">=0.0.8", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" } uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }

View file

@ -10,6 +10,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, stdout, BufRead, BufReader, Read, Stdout, Write}; use std::io::{stdin, stdout, BufRead, BufReader, Read, Stdout, Write};
use std::path::Path; use std::path::Path;
@ -20,6 +21,8 @@ use uucore::ranges::Range;
mod buffer; mod buffer;
mod searcher; mod searcher;
static NAME: &str = "cut";
static VERSION: &str = env!("CARGO_PKG_VERSION");
static SYNTAX: &str = static SYNTAX: &str =
"[-d] [-s] [-z] [--output-delimiter] ((-f|-b|-c) {{sequence}}) {{sourcefile}}+"; "[-d] [-s] [-z] [--output-delimiter] ((-f|-b|-c) {{sequence}}) {{sourcefile}}+";
static SUMMARY: &str = static SUMMARY: &str =
@ -422,34 +425,119 @@ fn cut_files(mut filenames: Vec<String>, mode: Mode) -> i32 {
exit_code exit_code
} }
mod options {
pub const BYTES: &str = "bytes";
pub const CHARACTERS: &str = "characters";
pub const DELIMITER: &str = "delimiter";
pub const FIELDS: &str = "fields";
pub const LEGACY_OPTION: &str = "legacy-option";
pub const ZERO_TERMINATED: &str = "zero-terminated";
pub const ONLY_DELIMITED: &str = "only-delimited";
pub const OUTPUT_DELIMITER: &str = "output-delimiter";
pub const COMPLEMENT: &str = "complement";
pub const FILE: &str = "file";
}
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 matches = app!(SYNTAX, SUMMARY, LONG_HELP) let matches = App::new(executable!())
.optopt("b", "bytes", "filter byte columns from the input source", "sequence") .name(NAME)
.optopt("c", "characters", "alias for character mode", "sequence") .version(VERSION)
.optopt("d", "delimiter", "specify the delimiter character that separates fields in the input source. Defaults to Tab.", "delimiter") .usage(SYNTAX)
.optopt("f", "fields", "filter field columns from the input source", "sequence") .about(SUMMARY)
.optflag("n", "", "legacy option - has no effect.") .after_help(LONG_HELP)
.optflag("", "complement", "invert the filter - instead of displaying only the filtered columns, display all but those columns") .arg(
.optflag("s", "only-delimited", "in field mode, only print lines which contain the delimiter") Arg::with_name(options::BYTES)
.optflag("z", "zero-terminated", "instead of filtering columns based on line, filter columns based on \\0 (NULL character)") .short("b")
.optopt("", "output-delimiter", "in field mode, replace the delimiter in output lines with this option's argument", "new delimiter") .long(options::BYTES)
.parse(args); .takes_value(true)
let complement = matches.opt_present("complement"); .help("filter byte columns from the input source")
.allow_hyphen_values(true)
.value_name("LIST"),
)
.arg(
Arg::with_name(options::CHARACTERS)
.short("c")
.long(options::CHARACTERS)
.help("alias for character mode")
.takes_value(true)
.allow_hyphen_values(true)
.value_name("LIST"),
)
.arg(
Arg::with_name(options::DELIMITER)
.short("d")
.long(options::DELIMITER)
.help("specify the delimiter character that separates fields in the input source. Defaults to Tab.")
.takes_value(true)
.value_name("DELIM"),
)
.arg(
Arg::with_name(options::FIELDS)
.short("f")
.long(options::FIELDS)
.help("filter field columns from the input source")
.takes_value(true)
.allow_hyphen_values(true)
.value_name("LIST"),
)
.arg(
Arg::with_name(options::LEGACY_OPTION)
.short("n")
.long(options::LEGACY_OPTION)
.help("legacy option - has no effect.")
.takes_value(false)
)
.arg(
Arg::with_name(options::COMPLEMENT)
.long(options::COMPLEMENT)
.help("invert the filter - instead of displaying only the filtered columns, display all but those columns")
.takes_value(false)
)
.arg(
Arg::with_name(options::ONLY_DELIMITED)
.short("s")
.long(options::ONLY_DELIMITED)
.help("in field mode, only print lines which contain the delimiter")
.takes_value(false)
)
.arg(
Arg::with_name(options::ZERO_TERMINATED)
.short("z")
.long(options::ZERO_TERMINATED)
.help("instead of filtering columns based on line, filter columns based on \\0 (NULL character)")
.takes_value(false)
)
.arg(
Arg::with_name(options::OUTPUT_DELIMITER)
.long(options::OUTPUT_DELIMITER)
.help("in field mode, replace the delimiter in output lines with this option's argument")
.takes_value(true)
.value_name("NEW_DELIM")
)
.arg(
Arg::with_name(options::FILE)
.hidden(true)
.multiple(true)
)
.get_matches_from(args);
let complement = matches.is_present("complement");
let mode_parse = match ( let mode_parse = match (
matches.opt_str("bytes"), matches.value_of(options::BYTES),
matches.opt_str("characters"), matches.value_of(options::CHARACTERS),
matches.opt_str("fields"), matches.value_of(options::FIELDS),
) { ) {
(Some(byte_ranges), None, None) => { (Some(byte_ranges), None, None) => {
list_to_ranges(&byte_ranges[..], complement).map(|ranges| { list_to_ranges(&byte_ranges[..], complement).map(|ranges| {
Mode::Bytes( Mode::Bytes(
ranges, ranges,
Options { Options {
out_delim: matches.opt_str("output-delimiter"), out_delim: Some(matches.value_of(options::OUTPUT_DELIMITER).unwrap_or_default().to_owned()),
zero_terminated: matches.opt_present("zero-terminated"), zero_terminated: matches.is_present(options::ZERO_TERMINATED),
}, },
) )
}) })
@ -459,29 +547,29 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
Mode::Characters( Mode::Characters(
ranges, ranges,
Options { Options {
out_delim: matches.opt_str("output-delimiter"), out_delim: Some(matches.value_of(options::OUTPUT_DELIMITER).unwrap_or_default().to_owned()),
zero_terminated: matches.opt_present("zero-terminated"), zero_terminated: matches.is_present(options::ZERO_TERMINATED),
}, },
) )
}) })
} }
(None, None, Some(field_ranges)) => { (None, None, Some(field_ranges)) => {
list_to_ranges(&field_ranges[..], complement).and_then(|ranges| { list_to_ranges(&field_ranges[..], complement).and_then(|ranges| {
let out_delim = match matches.opt_str("output-delimiter") { let out_delim = match matches.value_of(options::OUTPUT_DELIMITER) {
Some(s) => { Some(s) => {
if s.is_empty() { if s.is_empty() {
Some("\0".to_owned()) Some("\0".to_owned())
} else { } else {
Some(s) Some(s.to_owned())
} }
} }
None => None, None => None,
}; };
let only_delimited = matches.opt_present("only-delimited"); let only_delimited = matches.is_present(options::ONLY_DELIMITED);
let zero_terminated = matches.opt_present("zero-terminated"); let zero_terminated = matches.is_present(options::ZERO_TERMINATED);
match matches.opt_str("delimiter") { match matches.value_of(options::DELIMITER) {
Some(delim) => { Some(delim) => {
if delim.chars().count() > 1 { if delim.chars().count() > 1 {
Err(msg_opt_invalid_should_be!( Err(msg_opt_invalid_should_be!(
@ -494,7 +582,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let delim = if delim.is_empty() { let delim = if delim.is_empty() {
"\0".to_owned() "\0".to_owned()
} else { } else {
delim delim.to_owned()
}; };
Ok(Mode::Fields( Ok(Mode::Fields(
@ -533,10 +621,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let mode_parse = match mode_parse { let mode_parse = match mode_parse {
Err(_) => mode_parse, Err(_) => mode_parse,
Ok(mode) => match mode { Ok(mode) => match mode {
Mode::Bytes(_, _) | Mode::Characters(_, _) if matches.opt_present("delimiter") => Err( Mode::Bytes(_, _) | Mode::Characters(_, _) if matches.is_present("delimiter") => Err(
msg_opt_only_usable_if!("printing a sequence of fields", "--delimiter", "-d"), msg_opt_only_usable_if!("printing a sequence of fields", "--delimiter", "-d"),
), ),
Mode::Bytes(_, _) | Mode::Characters(_, _) if matches.opt_present("only-delimited") => { Mode::Bytes(_, _) | Mode::Characters(_, _) if matches.is_present("only-delimited") => {
Err(msg_opt_only_usable_if!( Err(msg_opt_only_usable_if!(
"printing a sequence of fields", "printing a sequence of fields",
"--only-delimited", "--only-delimited",
@ -547,8 +635,14 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
}, },
}; };
let files: Vec<String> = matches
.values_of(options::FILE)
.unwrap_or_default()
.map(str::to_owned)
.collect();
match mode_parse { match mode_parse {
Ok(mode) => cut_files(matches.free, mode), Ok(mode) => cut_files(files, mode),
Err(err_msg) => { Err(err_msg) => {
show_error!("{}", err_msg); show_error!("{}", err_msg);
1 1