1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-29 12:07:46 +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"
version = "0.0.6"
dependencies = [
"clap",
"uucore",
"uucore_procs",
]

View file

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

View file

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