diff --git a/Cargo.lock b/Cargo.lock index 66fe84236..bd990d93c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1202,7 +1202,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1260,7 +1260,7 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.46" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2055,7 +2055,7 @@ dependencies = [ name = "uu_seq" version = "0.0.1" dependencies = [ - "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)", "uucore 0.0.4 (git+https://github.com/uutils/uucore.git?branch=canary)", "uucore_procs 0.0.4 (git+https://github.com/uutils/uucore.git?branch=canary)", ] @@ -2398,7 +2398,7 @@ source = "git+https://github.com/uutils/uucore.git?branch=canary#869573459f00ba0 dependencies = [ "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2450,7 +2450,7 @@ dependencies = [ "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen-shared 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2470,7 +2470,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen-backend 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen-shared 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2684,7 +2684,7 @@ dependencies = [ "checksum sha3 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "26405905b6a56a94c60109cfda62610507ac14a65be531f5767dec5c5a8dd6a0" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" -"checksum syn 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "5ad5de3220ea04da322618ded2c42233d02baca219d6f160a3e9c87cda16c942" +"checksum syn 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" diff --git a/src/uu/seq/Cargo.toml b/src/uu/seq/Cargo.toml index 29d1eb1cf..b7cf3901c 100644 --- a/src/uu/seq/Cargo.toml +++ b/src/uu/seq/Cargo.toml @@ -15,7 +15,7 @@ edition = "2018" path = "src/seq.rs" [dependencies] -getopts = "0.2.18" +clap = "2.33" uucore = { version="0.0.4", package="uucore", git="https://github.com/uutils/uucore.git", branch="canary" } uucore_procs = { version="0.0.4", package="uucore_procs", git="https://github.com/uutils/uucore.git", branch="canary" } diff --git a/src/uu/seq/src/seq.rs b/src/uu/seq/src/seq.rs index 57890ab28..64a66d848 100644 --- a/src/uu/seq/src/seq.rs +++ b/src/uu/seq/src/seq.rs @@ -3,17 +3,25 @@ // spell-checker:ignore (ToDO) istr chiter argptr ilen -extern crate getopts; +extern crate clap; #[macro_use] extern crate uucore; +use clap::{App, Arg}; use std::cmp; use std::io::{stdout, Write}; -static NAME: &str = "seq"; static VERSION: &str = env!("CARGO_PKG_VERSION"); +static ABOUT: &str = "Print sequences of numbers"; +static OPT_SEPARATOR: &str = "separator"; +static OPT_TERMINATOR: &str = "terminator"; +static OPT_WIDTHS: &str = "widths"; +static OPT_NUMBERS: &str = "numbers"; +fn get_usage() -> String { + format!("{0} [OPTION]... [FILE]...", executable!()) +} #[derive(Clone)] struct SeqOptions { separator: String, @@ -38,162 +46,57 @@ fn escape_sequences(s: &str) -> String { s.replace("\\n", "\n").replace("\\t", "\t") } -fn parse_options(args: Vec, options: &mut SeqOptions) -> Result, i32> { - let mut seq_args = vec![]; - let mut iter = args.into_iter().skip(1); - while let Some(arg) = iter.next() { - match &arg[..] { - "--help" | "-h" => { - print_help(); - return Err(0); - } - "--version" | "-V" => { - print_version(); - return Err(0); - } - "-s" | "--separator" => match iter.next() { - Some(sep) => options.separator = sep, - None => { - show_error!("expected a separator after {}", arg); - return Err(1); - } - }, - "-t" | "--terminator" => match iter.next() { - Some(term) => options.terminator = Some(term), - None => { - show_error!("expected a terminator after '{}'", arg); - return Err(1); - } - }, - "-w" | "--widths" => options.widths = true, - "--" => { - seq_args.extend(iter); - break; - } - _ => { - if arg.len() > 1 && arg.starts_with('-') { - let argptr: *const String = &arg; // escape from the borrow checker - let mut chiter = unsafe { &(*argptr)[..] }.chars().skip(1); - let mut ch = ' '; - while match chiter.next() { - Some(m) => { - ch = m; - true - } - None => false, - } { - match ch { - 'h' => { - print_help(); - return Err(0); - } - 'V' => { - print_version(); - return Err(0); - } - 's' => match iter.next() { - Some(sep) => { - options.separator = sep; - let next = chiter.next(); - if let Some(n) = next { - show_error!("unexpected character ('{}')", n); - return Err(1); - } - } - None => { - show_error!("expected a separator after {}", arg); - return Err(1); - } - }, - 't' => match iter.next() { - Some(term) => { - options.terminator = Some(term); - let next = chiter.next(); - if let Some(n) = next { - show_error!("unexpected character ('{}')", n); - return Err(1); - } - } - None => { - show_error!("expected a terminator after {}", arg); - return Err(1); - } - }, - 'w' => options.widths = true, - _ => { - seq_args.push(arg); - break; - } - } - } - } else { - seq_args.push(arg); - } - } - }; - } - Ok(seq_args) -} - -fn print_help() { - let mut opts = getopts::Options::new(); - - opts.optopt( - "s", - "separator", - "Separator character (defaults to \\n)", - "", - ); - opts.optopt( - "t", - "terminator", - "Terminator character (defaults to separator)", - "", - ); - opts.optflag( - "w", - "widths", - "Equalize widths of all numbers by padding with zeros", - ); - opts.optflag("h", "help", "print this help text and exit"); - opts.optflag("V", "version", "print version and exit"); - - println!("{} {}\n", NAME, VERSION); - println!( - "Usage:\n {} [-w] [-s string] [-t string] [first [step]] last\n", - NAME - ); - println!("{}", opts.usage("Print sequences of numbers")); -} - -fn print_version() { - println!("{} {}", NAME, VERSION); -} - pub fn uumain(args: impl uucore::Args) -> i32 { - let args = args.collect_str(); + let usage = get_usage(); + let matches = App::new(executable!()) + .version(VERSION) + .about(ABOUT) + .usage(&usage[..]) + .arg( + Arg::with_name(OPT_SEPARATOR) + .short("s") + .long("separator") + .help("Separator character (defaults to \\n)") + .takes_value(true) + .number_of_values(1), + ) + .arg( + Arg::with_name(OPT_TERMINATOR) + .short("t") + .long("terminator") + .help("Terminator character (defaults to separator)") + .takes_value(true) + .number_of_values(1), + ) + .arg( + Arg::with_name(OPT_WIDTHS) + .short("w") + .long("widths") + .help("Equalize widths of all numbers by padding with zeros"), + ) + .arg( + Arg::with_name(OPT_NUMBERS) + .multiple(true) + .takes_value(true) + .max_values(3), + ) + .get_matches_from(args); + + let numbers = matches.values_of(OPT_NUMBERS).unwrap().collect::>(); let mut options = SeqOptions { separator: "\n".to_owned(), terminator: None, widths: false, }; - let free = match parse_options(args, &mut options) { - Ok(m) => m, - Err(f) => return f, - }; - if free.is_empty() || free.len() > 3 { - crash!( - 1, - "too {} operands.\nTry '{} --help' for more information.", - if free.is_empty() { "few" } else { "many" }, - NAME - ); - } + options.separator = matches.value_of(OPT_SEPARATOR).unwrap_or("\n").to_string(); + options.terminator = matches.value_of(OPT_TERMINATOR).map(String::from); + options.widths = matches.is_present(OPT_WIDTHS); + let mut largest_dec = 0; let mut padding = 0; - let first = if free.len() > 1 { - let slice = &free[0][..]; + let first = if numbers.len() > 1 { + let slice = &numbers[0][..]; let len = slice.len(); let dec = slice.find('.').unwrap_or(len); largest_dec = len - dec; @@ -208,8 +111,8 @@ pub fn uumain(args: impl uucore::Args) -> i32 { } else { 1.0 }; - let step = if free.len() > 2 { - let slice = &free[1][..]; + let step = if numbers.len() > 2 { + let slice = &numbers[1][..]; let len = slice.len(); let dec = slice.find('.').unwrap_or(len); largest_dec = cmp::max(largest_dec, len - dec); @@ -225,7 +128,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { 1.0 }; let last = { - let slice = &free[free.len() - 1][..]; + let slice = &numbers[numbers.len() - 1][..]; padding = cmp::max(padding, slice.find('.').unwrap_or_else(|| slice.len())); match parse_float(slice) { Ok(n) => n,