2014-01-25 01:37:51 -06:00
|
|
|
|
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
2012-12-03 18:48:01 -06:00
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
|
//
|
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
|
// except according to those terms.
|
2014-07-14 22:46:04 -05:00
|
|
|
|
//
|
|
|
|
|
// ignore-lexer-test FIXME #15677
|
2012-12-03 18:48:01 -06:00
|
|
|
|
|
2013-09-17 20:42:23 -05:00
|
|
|
|
//! Simple getopt alternative.
|
|
|
|
|
//!
|
2013-09-26 00:51:19 -05:00
|
|
|
|
//! Construct a vector of options, either by using `reqopt`, `optopt`, and `optflag`
|
|
|
|
|
//! or by building them from components yourself, and pass them to `getopts`,
|
|
|
|
|
//! along with a vector of actual arguments (not including `argv[0]`). You'll
|
2013-09-17 20:42:23 -05:00
|
|
|
|
//! either get a failure code back, or a match. You'll have to verify whether
|
2013-09-26 00:51:19 -05:00
|
|
|
|
//! the amount of 'free' arguments in the match is what you expect. Use `opt_*`
|
2013-09-17 20:42:23 -05:00
|
|
|
|
//! accessors to get argument values out of the matches object.
|
|
|
|
|
//!
|
|
|
|
|
//! Single-character options are expected to appear on the command line with a
|
|
|
|
|
//! single preceding dash; multiple-character options are expected to be
|
|
|
|
|
//! proceeded by two dashes. Options that expect an argument accept their
|
|
|
|
|
//! argument following either a space or an equals sign. Single-character
|
|
|
|
|
//! options don't require the space.
|
|
|
|
|
//!
|
|
|
|
|
//! # Example
|
|
|
|
|
//!
|
|
|
|
|
//! The following example shows simple command line parsing for an application
|
|
|
|
|
//! that requires an input file to be specified, accepts an optional output
|
2013-09-26 00:51:19 -05:00
|
|
|
|
//! file name following `-o`, and accepts both `-h` and `--help` as optional flags.
|
2013-09-17 20:42:23 -05:00
|
|
|
|
//!
|
2014-09-16 06:27:34 -05:00
|
|
|
|
//! ```{.rust}
|
2014-02-14 12:10:06 -06:00
|
|
|
|
//! extern crate getopts;
|
2014-02-05 21:51:22 -06:00
|
|
|
|
//! use getopts::{optopt,optflag,getopts,OptGroup};
|
2013-09-17 20:42:23 -05:00
|
|
|
|
//! use std::os;
|
|
|
|
|
//!
|
2014-05-22 18:57:53 -05:00
|
|
|
|
//! fn do_work(inp: &str, out: Option<String>) {
|
2014-01-09 04:06:55 -06:00
|
|
|
|
//! println!("{}", inp);
|
|
|
|
|
//! match out {
|
|
|
|
|
//! Some(x) => println!("{}", x),
|
|
|
|
|
//! None => println!("No Output"),
|
|
|
|
|
//! }
|
2013-09-17 20:42:23 -05:00
|
|
|
|
//! }
|
|
|
|
|
//!
|
2014-02-05 21:51:22 -06:00
|
|
|
|
//! fn print_usage(program: &str, _opts: &[OptGroup]) {
|
2013-09-25 00:16:43 -05:00
|
|
|
|
//! println!("Usage: {} [options]", program);
|
2014-01-09 04:06:55 -06:00
|
|
|
|
//! println!("-o\t\tOutput");
|
|
|
|
|
//! println!("-h --help\tUsage");
|
2013-09-17 20:42:23 -05:00
|
|
|
|
//! }
|
|
|
|
|
//!
|
|
|
|
|
//! fn main() {
|
2014-06-26 01:15:14 -05:00
|
|
|
|
//! let args: Vec<String> = os::args();
|
2013-09-17 20:42:23 -05:00
|
|
|
|
//!
|
2014-07-14 18:37:25 -05:00
|
|
|
|
//! let program = args[0].clone();
|
2013-09-17 20:42:23 -05:00
|
|
|
|
//!
|
2014-04-09 05:02:26 -05:00
|
|
|
|
//! let opts = [
|
2014-02-05 21:51:22 -06:00
|
|
|
|
//! optopt("o", "", "set output file name", "NAME"),
|
|
|
|
|
//! optflag("h", "help", "print this help menu")
|
2013-09-17 20:42:23 -05:00
|
|
|
|
//! ];
|
|
|
|
|
//! let matches = match getopts(args.tail(), opts) {
|
|
|
|
|
//! Ok(m) => { m }
|
2014-06-21 05:39:03 -05:00
|
|
|
|
//! Err(f) => { fail!(f.to_string()) }
|
2013-09-17 20:42:23 -05:00
|
|
|
|
//! };
|
2014-02-05 21:51:22 -06:00
|
|
|
|
//! if matches.opt_present("h") {
|
2014-05-14 23:39:11 -05:00
|
|
|
|
//! print_usage(program.as_slice(), opts);
|
2013-09-17 20:42:23 -05:00
|
|
|
|
//! return;
|
|
|
|
|
//! }
|
|
|
|
|
//! let output = matches.opt_str("o");
|
2014-05-14 23:39:11 -05:00
|
|
|
|
//! let input = if !matches.free.is_empty() {
|
2014-07-14 18:37:25 -05:00
|
|
|
|
//! matches.free[0].clone()
|
2013-09-17 20:42:23 -05:00
|
|
|
|
//! } else {
|
2014-05-14 23:39:11 -05:00
|
|
|
|
//! print_usage(program.as_slice(), opts);
|
2013-09-17 20:42:23 -05:00
|
|
|
|
//! return;
|
|
|
|
|
//! };
|
2014-05-14 23:39:11 -05:00
|
|
|
|
//! do_work(input.as_slice(), output);
|
2013-09-17 20:42:23 -05:00
|
|
|
|
//! }
|
2014-09-16 06:27:34 -05:00
|
|
|
|
//! ```
|
2013-05-17 17:28:44 -05:00
|
|
|
|
|
2014-07-01 09:12:04 -05:00
|
|
|
|
#![crate_name = "getopts"]
|
2014-06-18 00:13:36 -05:00
|
|
|
|
#![experimental]
|
2014-03-21 20:05:05 -05:00
|
|
|
|
#![crate_type = "rlib"]
|
|
|
|
|
#![crate_type = "dylib"]
|
|
|
|
|
#![license = "MIT/ASL2"]
|
|
|
|
|
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
|
|
|
|
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
2014-10-09 12:47:22 -05:00
|
|
|
|
html_root_url = "http://doc.rust-lang.org/nightly/",
|
2014-06-06 11:12:18 -05:00
|
|
|
|
html_playground_url = "http://play.rust-lang.org/")]
|
2014-03-21 20:05:05 -05:00
|
|
|
|
#![feature(globs, phase)]
|
2014-08-12 22:31:30 -05:00
|
|
|
|
#![feature(import_shadowing)]
|
2014-03-21 20:05:05 -05:00
|
|
|
|
#![deny(missing_doc)]
|
log: Introduce liblog, the old std::logging
This commit moves all logging out of the standard library into an external
crate. This crate is the new crate which is responsible for all logging macros
and logging implementation. A few reasons for this change are:
* The crate map has always been a bit of a code smell among rust programs. It
has difficulty being loaded on almost all platforms, and it's used almost
exclusively for logging and only logging. Removing the crate map is one of the
end goals of this movement.
* The compiler has a fair bit of special support for logging. It has the
__log_level() expression as well as generating a global word per module
specifying the log level. This is unfairly favoring the built-in logging
system, and is much better done purely in libraries instead of the compiler
itself.
* Initialization of logging is much easier to do if there is no reliance on a
magical crate map being available to set module log levels.
* If the logging library can be written outside of the standard library, there's
no reason that it shouldn't be. It's likely that we're not going to build the
highest quality logging library of all time, so third-party libraries should
be able to provide just as high-quality logging systems as the default one
provided in the rust distribution.
With a migration such as this, the change does not come for free. There are some
subtle changes in the behavior of liblog vs the previous logging macros:
* The core change of this migration is that there is no longer a physical
log-level per module. This concept is still emulated (it is quite useful), but
there is now only a global log level, not a local one. This global log level
is a reflection of the maximum of all log levels specified. The previously
generated logging code looked like:
if specified_level <= __module_log_level() {
println!(...)
}
The newly generated code looks like:
if specified_level <= ::log::LOG_LEVEL {
if ::log::module_enabled(module_path!()) {
println!(...)
}
}
Notably, the first layer of checking is still intended to be "super fast" in
that it's just a load of a global word and a compare. The second layer of
checking is executed to determine if the current module does indeed have
logging turned on.
This means that if any module has a debug log level turned on, all modules
with debug log levels get a little bit slower (they all do more expensive
dynamic checks to determine if they're turned on or not).
Semantically, this migration brings no change in this respect, but
runtime-wise, this will have a perf impact on some code.
* A `RUST_LOG=::help` directive will no longer print out a list of all modules
that can be logged. This is because the crate map will no longer specify the
log levels of all modules, so the list of modules is not known. Additionally,
warnings can no longer be provided if a malformed logging directive was
supplied.
The new "hello world" for logging looks like:
#[phase(syntax, link)]
extern crate log;
fn main() {
debug!("Hello, world!");
}
2014-03-09 00:11:44 -06:00
|
|
|
|
|
2014-06-11 20:47:09 -05:00
|
|
|
|
#[cfg(test)] #[phase(plugin, link)] extern crate log;
|
2014-02-02 17:20:32 -06:00
|
|
|
|
|
2014-05-29 19:45:07 -05:00
|
|
|
|
use std::cmp::PartialEq;
|
2014-06-13 20:11:09 -05:00
|
|
|
|
use std::fmt;
|
2013-06-28 17:32:26 -05:00
|
|
|
|
use std::result::{Err, Ok};
|
|
|
|
|
use std::result;
|
2014-05-22 18:57:53 -05:00
|
|
|
|
use std::string::String;
|
2011-05-21 18:30:04 -05:00
|
|
|
|
|
2013-09-17 20:42:23 -05:00
|
|
|
|
/// Name of an option. Either a string or a single char.
|
2014-06-13 20:20:47 -05:00
|
|
|
|
#[deriving(Clone, PartialEq, Eq)]
|
2013-01-08 21:37:25 -06:00
|
|
|
|
pub enum Name {
|
2014-03-16 15:33:19 -05:00
|
|
|
|
/// A string representing the long name of an option.
|
|
|
|
|
/// For example: "help"
|
2014-05-22 18:57:53 -05:00
|
|
|
|
Long(String),
|
2014-03-16 15:33:19 -05:00
|
|
|
|
/// A char representing the short name of an option.
|
|
|
|
|
/// For example: 'h'
|
2012-08-27 18:26:35 -05:00
|
|
|
|
Short(char),
|
|
|
|
|
}
|
2011-06-15 13:19:50 -05:00
|
|
|
|
|
2013-09-17 20:42:23 -05:00
|
|
|
|
/// Describes whether an option has an argument.
|
2014-06-13 20:20:47 -05:00
|
|
|
|
#[deriving(Clone, PartialEq, Eq)]
|
2013-07-02 14:47:32 -05:00
|
|
|
|
pub enum HasArg {
|
2014-03-16 15:33:19 -05:00
|
|
|
|
/// The option requires an argument.
|
2013-07-02 14:47:32 -05:00
|
|
|
|
Yes,
|
2014-08-04 14:43:30 -05:00
|
|
|
|
/// The option takes no argument.
|
2013-07-02 14:47:32 -05:00
|
|
|
|
No,
|
2014-08-04 14:43:30 -05:00
|
|
|
|
/// The option argument is optional.
|
2013-07-02 14:47:32 -05:00
|
|
|
|
Maybe,
|
|
|
|
|
}
|
2011-06-15 13:19:50 -05:00
|
|
|
|
|
2013-09-17 20:42:23 -05:00
|
|
|
|
/// Describes how often an option may occur.
|
2014-06-13 20:20:47 -05:00
|
|
|
|
#[deriving(Clone, PartialEq, Eq)]
|
2013-07-02 14:47:32 -05:00
|
|
|
|
pub enum Occur {
|
2014-03-16 15:33:19 -05:00
|
|
|
|
/// The option occurs once.
|
2013-07-02 14:47:32 -05:00
|
|
|
|
Req,
|
2014-08-04 14:43:30 -05:00
|
|
|
|
/// The option occurs at most once.
|
2013-07-02 14:47:32 -05:00
|
|
|
|
Optional,
|
2014-08-04 14:43:30 -05:00
|
|
|
|
/// The option occurs zero or more times.
|
2013-07-02 14:47:32 -05:00
|
|
|
|
Multi,
|
|
|
|
|
}
|
2011-04-26 10:46:54 -05:00
|
|
|
|
|
2013-09-17 20:42:23 -05:00
|
|
|
|
/// A description of a possible option.
|
2014-06-13 20:20:47 -05:00
|
|
|
|
#[deriving(Clone, PartialEq, Eq)]
|
2012-12-11 19:03:22 -06:00
|
|
|
|
pub struct Opt {
|
2013-09-17 20:42:23 -05:00
|
|
|
|
/// Name of the option
|
2014-03-27 17:10:18 -05:00
|
|
|
|
pub name: Name,
|
2013-12-14 23:34:14 -06:00
|
|
|
|
/// Whether it has an argument
|
2014-03-27 17:10:18 -05:00
|
|
|
|
pub hasarg: HasArg,
|
2013-10-20 00:51:30 -05:00
|
|
|
|
/// How often it can occur
|
2014-03-27 17:10:18 -05:00
|
|
|
|
pub occur: Occur,
|
2013-09-17 20:42:23 -05:00
|
|
|
|
/// Which options it aliases
|
2014-06-13 20:20:47 -05:00
|
|
|
|
pub aliases: Vec<Opt>,
|
2012-12-11 19:03:22 -06:00
|
|
|
|
}
|
2011-04-26 10:46:54 -05:00
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
/// One group of options, e.g., both -h and --help, along with
|
|
|
|
|
/// their shared description and properties.
|
2014-06-13 20:20:47 -05:00
|
|
|
|
#[deriving(Clone, PartialEq, Eq)]
|
2014-02-03 21:14:40 -06:00
|
|
|
|
pub struct OptGroup {
|
|
|
|
|
/// Short Name of the `OptGroup`
|
2014-05-22 18:57:53 -05:00
|
|
|
|
pub short_name: String,
|
2014-02-03 21:14:40 -06:00
|
|
|
|
/// Long Name of the `OptGroup`
|
2014-05-22 18:57:53 -05:00
|
|
|
|
pub long_name: String,
|
2014-02-03 21:14:40 -06:00
|
|
|
|
/// Hint
|
2014-05-22 18:57:53 -05:00
|
|
|
|
pub hint: String,
|
2014-02-03 21:14:40 -06:00
|
|
|
|
/// Description
|
2014-05-22 18:57:53 -05:00
|
|
|
|
pub desc: String,
|
2014-02-03 21:14:40 -06:00
|
|
|
|
/// Whether it has an argument
|
2014-03-27 17:10:18 -05:00
|
|
|
|
pub hasarg: HasArg,
|
2014-02-03 21:14:40 -06:00
|
|
|
|
/// How often it can occur
|
2014-03-27 17:10:18 -05:00
|
|
|
|
pub occur: Occur
|
2014-02-03 21:14:40 -06:00
|
|
|
|
}
|
|
|
|
|
|
2014-06-08 23:00:52 -05:00
|
|
|
|
/// Describes whether an option is given at all or has a value.
|
2014-06-13 20:20:47 -05:00
|
|
|
|
#[deriving(Clone, PartialEq, Eq)]
|
2013-09-17 20:42:23 -05:00
|
|
|
|
enum Optval {
|
2014-05-22 18:57:53 -05:00
|
|
|
|
Val(String),
|
2013-09-17 20:42:23 -05:00
|
|
|
|
Given,
|
2011-04-26 10:46:54 -05:00
|
|
|
|
}
|
2011-06-15 13:19:50 -05:00
|
|
|
|
|
2013-09-17 20:42:23 -05:00
|
|
|
|
/// The result of checking command line arguments. Contains a vector
|
|
|
|
|
/// of matches and a vector of free strings.
|
2014-06-13 20:20:47 -05:00
|
|
|
|
#[deriving(Clone, PartialEq, Eq)]
|
2013-09-17 20:42:23 -05:00
|
|
|
|
pub struct Matches {
|
|
|
|
|
/// Options that matched
|
2014-06-13 20:20:47 -05:00
|
|
|
|
opts: Vec<Opt>,
|
2013-09-17 20:42:23 -05:00
|
|
|
|
/// Values of the Options that matched
|
2014-06-13 20:20:47 -05:00
|
|
|
|
vals: Vec<Vec<Optval>>,
|
2013-09-17 20:42:23 -05:00
|
|
|
|
/// Free string fragments
|
2014-05-22 18:57:53 -05:00
|
|
|
|
pub free: Vec<String>,
|
2014-03-27 17:10:18 -05:00
|
|
|
|
}
|
2011-06-15 13:19:50 -05:00
|
|
|
|
|
2013-09-17 20:42:23 -05:00
|
|
|
|
/// The type returned when the command line does not conform to the
|
2014-06-13 20:11:09 -05:00
|
|
|
|
/// expected format. Use the `Show` implementation to output detailed
|
|
|
|
|
/// information.
|
2014-06-13 20:20:47 -05:00
|
|
|
|
#[deriving(Clone, PartialEq, Eq)]
|
2013-09-17 20:42:23 -05:00
|
|
|
|
pub enum Fail_ {
|
2014-03-16 15:33:19 -05:00
|
|
|
|
/// The option requires an argument but none was passed.
|
2014-05-22 18:57:53 -05:00
|
|
|
|
ArgumentMissing(String),
|
2014-03-16 15:33:19 -05:00
|
|
|
|
/// The passed option is not declared among the possible options.
|
2014-05-22 18:57:53 -05:00
|
|
|
|
UnrecognizedOption(String),
|
2014-03-16 15:33:19 -05:00
|
|
|
|
/// A required option is not present.
|
2014-05-22 18:57:53 -05:00
|
|
|
|
OptionMissing(String),
|
2014-05-22 07:50:31 -05:00
|
|
|
|
/// A single occurrence option is being used multiple times.
|
2014-05-22 18:57:53 -05:00
|
|
|
|
OptionDuplicated(String),
|
2014-03-16 15:33:19 -05:00
|
|
|
|
/// There's an argument being passed to a non-argument option.
|
2014-05-22 18:57:53 -05:00
|
|
|
|
UnexpectedArgument(String),
|
2011-04-26 10:46:54 -05:00
|
|
|
|
}
|
2011-06-15 13:19:50 -05:00
|
|
|
|
|
2013-12-14 23:34:14 -06:00
|
|
|
|
/// The type of failure that occurred.
|
2014-06-13 20:20:47 -05:00
|
|
|
|
#[deriving(PartialEq, Eq)]
|
2013-10-02 01:26:45 -05:00
|
|
|
|
#[allow(missing_doc)]
|
2013-09-17 20:42:23 -05:00
|
|
|
|
pub enum FailType {
|
|
|
|
|
ArgumentMissing_,
|
|
|
|
|
UnrecognizedOption_,
|
|
|
|
|
OptionMissing_,
|
|
|
|
|
OptionDuplicated_,
|
|
|
|
|
UnexpectedArgument_,
|
2011-04-26 10:46:54 -05:00
|
|
|
|
}
|
2011-06-15 13:19:50 -05:00
|
|
|
|
|
2013-09-17 20:42:23 -05:00
|
|
|
|
/// The result of parsing a command line with a set of options.
|
|
|
|
|
pub type Result = result::Result<Matches, Fail_>;
|
2012-11-17 21:43:39 -06:00
|
|
|
|
|
2013-09-17 20:42:23 -05:00
|
|
|
|
impl Name {
|
|
|
|
|
fn from_str(nm: &str) -> Name {
|
|
|
|
|
if nm.len() == 1u {
|
|
|
|
|
Short(nm.char_at(0u))
|
|
|
|
|
} else {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
Long(nm.to_string())
|
2013-09-17 20:42:23 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
2011-06-15 13:19:50 -05:00
|
|
|
|
|
2014-06-21 05:39:03 -05:00
|
|
|
|
fn to_string(&self) -> String {
|
2013-09-17 20:42:23 -05:00
|
|
|
|
match *self {
|
2014-06-21 05:39:03 -05:00
|
|
|
|
Short(ch) => ch.to_string(),
|
2014-05-25 05:17:19 -05:00
|
|
|
|
Long(ref s) => s.to_string()
|
2013-09-17 20:42:23 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
2011-04-26 10:46:54 -05:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
impl OptGroup {
|
|
|
|
|
/// Translate OptGroup into Opt.
|
|
|
|
|
/// (Both short and long names correspond to different Opts).
|
|
|
|
|
pub fn long_to_short(&self) -> Opt {
|
|
|
|
|
let OptGroup {
|
2014-10-05 19:36:53 -05:00
|
|
|
|
short_name,
|
|
|
|
|
long_name,
|
|
|
|
|
hasarg,
|
|
|
|
|
occur,
|
2014-02-03 21:14:40 -06:00
|
|
|
|
..
|
|
|
|
|
} = (*self).clone();
|
|
|
|
|
|
|
|
|
|
match (short_name.len(), long_name.len()) {
|
|
|
|
|
(0,0) => fail!("this long-format option was given no name"),
|
|
|
|
|
(0,_) => Opt {
|
|
|
|
|
name: Long((long_name)),
|
|
|
|
|
hasarg: hasarg,
|
|
|
|
|
occur: occur,
|
2014-03-05 17:28:08 -06:00
|
|
|
|
aliases: Vec::new()
|
2014-02-03 21:14:40 -06:00
|
|
|
|
},
|
|
|
|
|
(1,0) => Opt {
|
2014-05-14 23:39:11 -05:00
|
|
|
|
name: Short(short_name.as_slice().char_at(0)),
|
2014-02-03 21:14:40 -06:00
|
|
|
|
hasarg: hasarg,
|
|
|
|
|
occur: occur,
|
2014-03-05 17:28:08 -06:00
|
|
|
|
aliases: Vec::new()
|
2014-02-03 21:14:40 -06:00
|
|
|
|
},
|
|
|
|
|
(1,_) => Opt {
|
|
|
|
|
name: Long((long_name)),
|
|
|
|
|
hasarg: hasarg,
|
|
|
|
|
occur: occur,
|
2014-03-05 17:28:08 -06:00
|
|
|
|
aliases: vec!(
|
2014-02-03 21:14:40 -06:00
|
|
|
|
Opt {
|
2014-05-14 23:39:11 -05:00
|
|
|
|
name: Short(short_name.as_slice().char_at(0)),
|
2014-02-03 21:14:40 -06:00
|
|
|
|
hasarg: hasarg,
|
|
|
|
|
occur: occur,
|
2014-03-05 17:28:08 -06:00
|
|
|
|
aliases: Vec::new()
|
2014-02-03 21:14:40 -06:00
|
|
|
|
}
|
2014-03-05 17:28:08 -06:00
|
|
|
|
)
|
2014-02-03 21:14:40 -06:00
|
|
|
|
},
|
|
|
|
|
(_,_) => fail!("something is wrong with the long-form opt")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-17 20:42:23 -05:00
|
|
|
|
impl Matches {
|
2014-03-05 17:28:08 -06:00
|
|
|
|
fn opt_vals(&self, nm: &str) -> Vec<Optval> {
|
|
|
|
|
match find_opt(self.opts.as_slice(), Name::from_str(nm)) {
|
2014-07-14 18:37:25 -05:00
|
|
|
|
Some(id) => self.vals[id].clone(),
|
2013-10-21 15:08:31 -05:00
|
|
|
|
None => fail!("No option '{}' defined", nm)
|
2013-09-17 20:42:23 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
2011-04-26 10:46:54 -05:00
|
|
|
|
|
2013-11-08 18:20:25 -06:00
|
|
|
|
fn opt_val(&self, nm: &str) -> Option<Optval> {
|
2013-09-17 20:42:23 -05:00
|
|
|
|
let vals = self.opt_vals(nm);
|
2014-01-19 02:21:14 -06:00
|
|
|
|
if vals.is_empty() {
|
2013-09-17 20:42:23 -05:00
|
|
|
|
None
|
|
|
|
|
} else {
|
2014-07-14 18:37:25 -05:00
|
|
|
|
Some(vals[0].clone())
|
2013-09-17 20:42:23 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns true if an option was matched.
|
|
|
|
|
pub fn opt_present(&self, nm: &str) -> bool {
|
|
|
|
|
!self.opt_vals(nm).is_empty()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns the number of times an option was matched.
|
|
|
|
|
pub fn opt_count(&self, nm: &str) -> uint {
|
|
|
|
|
self.opt_vals(nm).len()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns true if any of several options were matched.
|
2014-05-22 18:57:53 -05:00
|
|
|
|
pub fn opts_present(&self, names: &[String]) -> bool {
|
2013-09-17 20:42:23 -05:00
|
|
|
|
for nm in names.iter() {
|
2014-05-14 23:39:11 -05:00
|
|
|
|
match find_opt(self.opts.as_slice(),
|
|
|
|
|
Name::from_str(nm.as_slice())) {
|
2014-07-14 18:37:25 -05:00
|
|
|
|
Some(id) if !self.vals[id].is_empty() => return true,
|
2013-09-17 20:42:23 -05:00
|
|
|
|
_ => (),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns the string argument supplied to one of several matching options or `None`.
|
2014-05-22 18:57:53 -05:00
|
|
|
|
pub fn opts_str(&self, names: &[String]) -> Option<String> {
|
2013-09-17 20:42:23 -05:00
|
|
|
|
for nm in names.iter() {
|
2014-05-14 23:39:11 -05:00
|
|
|
|
match self.opt_val(nm.as_slice()) {
|
2013-09-17 20:42:23 -05:00
|
|
|
|
Some(Val(ref s)) => return Some(s.clone()),
|
|
|
|
|
_ => ()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns a vector of the arguments provided to all matches of the given
|
|
|
|
|
/// option.
|
|
|
|
|
///
|
|
|
|
|
/// Used when an option accepts multiple values.
|
2014-05-22 18:57:53 -05:00
|
|
|
|
pub fn opt_strs(&self, nm: &str) -> Vec<String> {
|
|
|
|
|
let mut acc: Vec<String> = Vec::new();
|
2013-09-17 20:42:23 -05:00
|
|
|
|
let r = self.opt_vals(nm);
|
|
|
|
|
for v in r.iter() {
|
|
|
|
|
match *v {
|
|
|
|
|
Val(ref s) => acc.push((*s).clone()),
|
|
|
|
|
_ => ()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
acc
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns the string argument supplied to a matching option or `None`.
|
2014-05-22 18:57:53 -05:00
|
|
|
|
pub fn opt_str(&self, nm: &str) -> Option<String> {
|
2013-09-17 20:42:23 -05:00
|
|
|
|
let vals = self.opt_vals(nm);
|
|
|
|
|
if vals.is_empty() {
|
2014-05-22 18:57:53 -05:00
|
|
|
|
return None::<String>;
|
2013-09-17 20:42:23 -05:00
|
|
|
|
}
|
2014-07-14 18:37:25 -05:00
|
|
|
|
match vals[0] {
|
|
|
|
|
Val(ref s) => Some((*s).clone()),
|
2013-09-17 20:42:23 -05:00
|
|
|
|
_ => None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns the matching string, a default, or none.
|
|
|
|
|
///
|
|
|
|
|
/// Returns none if the option was not present, `def` if the option was
|
|
|
|
|
/// present but no argument was provided, and the argument if the option was
|
|
|
|
|
/// present and an argument was provided.
|
2014-05-22 18:57:53 -05:00
|
|
|
|
pub fn opt_default(&self, nm: &str, def: &str) -> Option<String> {
|
2013-09-17 20:42:23 -05:00
|
|
|
|
let vals = self.opt_vals(nm);
|
2014-05-14 23:39:11 -05:00
|
|
|
|
if vals.is_empty() {
|
|
|
|
|
return None;
|
|
|
|
|
}
|
2014-07-14 18:37:25 -05:00
|
|
|
|
match vals[0] {
|
|
|
|
|
Val(ref s) => Some((*s).clone()),
|
2014-05-25 05:17:19 -05:00
|
|
|
|
_ => Some(def.to_string())
|
2013-09-17 20:42:23 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
2011-04-26 10:46:54 -05:00
|
|
|
|
|
|
|
|
|
}
|
2011-06-15 13:19:50 -05:00
|
|
|
|
|
2013-09-17 20:42:23 -05:00
|
|
|
|
fn is_arg(arg: &str) -> bool {
|
2014-08-06 12:06:37 -05:00
|
|
|
|
arg.len() > 1 && arg.as_bytes()[0] == b'-'
|
2011-04-26 10:46:54 -05:00
|
|
|
|
}
|
|
|
|
|
|
2012-10-04 21:58:31 -05:00
|
|
|
|
fn find_opt(opts: &[Opt], nm: Name) -> Option<uint> {
|
2013-09-17 20:42:23 -05:00
|
|
|
|
// Search main options.
|
2013-08-05 07:37:54 -05:00
|
|
|
|
let pos = opts.iter().position(|opt| opt.name == nm);
|
|
|
|
|
if pos.is_some() {
|
|
|
|
|
return pos
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-17 20:42:23 -05:00
|
|
|
|
// Search in aliases.
|
2013-08-05 07:37:54 -05:00
|
|
|
|
for candidate in opts.iter() {
|
|
|
|
|
if candidate.aliases.iter().position(|opt| opt.name == nm).is_some() {
|
|
|
|
|
return opts.iter().position(|opt| opt.name == candidate.name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
None
|
2011-04-26 10:46:54 -05:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
/// Create a long option that is required and takes an argument.
|
|
|
|
|
pub fn reqopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
|
|
|
|
|
let len = short_name.len();
|
|
|
|
|
assert!(len == 1 || len == 0);
|
|
|
|
|
OptGroup {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
short_name: short_name.to_string(),
|
|
|
|
|
long_name: long_name.to_string(),
|
|
|
|
|
hint: hint.to_string(),
|
|
|
|
|
desc: desc.to_string(),
|
2013-09-17 20:42:23 -05:00
|
|
|
|
hasarg: Yes,
|
2014-02-03 21:14:40 -06:00
|
|
|
|
occur: Req
|
2013-09-17 20:42:23 -05:00
|
|
|
|
}
|
2011-04-26 10:46:54 -05:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
/// Create a long option that is optional and takes an argument.
|
|
|
|
|
pub fn optopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
|
|
|
|
|
let len = short_name.len();
|
|
|
|
|
assert!(len == 1 || len == 0);
|
|
|
|
|
OptGroup {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
short_name: short_name.to_string(),
|
|
|
|
|
long_name: long_name.to_string(),
|
|
|
|
|
hint: hint.to_string(),
|
|
|
|
|
desc: desc.to_string(),
|
2013-09-17 20:42:23 -05:00
|
|
|
|
hasarg: Yes,
|
2014-02-03 21:14:40 -06:00
|
|
|
|
occur: Optional
|
2013-09-17 20:42:23 -05:00
|
|
|
|
}
|
2011-04-26 10:46:54 -05:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
/// Create a long option that is optional and does not take an argument.
|
|
|
|
|
pub fn optflag(short_name: &str, long_name: &str, desc: &str) -> OptGroup {
|
|
|
|
|
let len = short_name.len();
|
|
|
|
|
assert!(len == 1 || len == 0);
|
|
|
|
|
OptGroup {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
short_name: short_name.to_string(),
|
|
|
|
|
long_name: long_name.to_string(),
|
|
|
|
|
hint: "".to_string(),
|
|
|
|
|
desc: desc.to_string(),
|
2013-09-17 20:42:23 -05:00
|
|
|
|
hasarg: No,
|
2014-02-03 21:14:40 -06:00
|
|
|
|
occur: Optional
|
2013-09-17 20:42:23 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
/// Create a long option that can occur more than once and does not
|
|
|
|
|
/// take an argument.
|
|
|
|
|
pub fn optflagmulti(short_name: &str, long_name: &str, desc: &str) -> OptGroup {
|
|
|
|
|
let len = short_name.len();
|
|
|
|
|
assert!(len == 1 || len == 0);
|
|
|
|
|
OptGroup {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
short_name: short_name.to_string(),
|
|
|
|
|
long_name: long_name.to_string(),
|
|
|
|
|
hint: "".to_string(),
|
|
|
|
|
desc: desc.to_string(),
|
2013-09-17 20:42:23 -05:00
|
|
|
|
hasarg: No,
|
2014-02-03 21:14:40 -06:00
|
|
|
|
occur: Multi
|
2013-09-17 20:42:23 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
/// Create a long option that is optional and takes an optional argument.
|
|
|
|
|
pub fn optflagopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
|
|
|
|
|
let len = short_name.len();
|
|
|
|
|
assert!(len == 1 || len == 0);
|
|
|
|
|
OptGroup {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
short_name: short_name.to_string(),
|
|
|
|
|
long_name: long_name.to_string(),
|
|
|
|
|
hint: hint.to_string(),
|
|
|
|
|
desc: desc.to_string(),
|
2013-09-17 20:42:23 -05:00
|
|
|
|
hasarg: Maybe,
|
2014-02-03 21:14:40 -06:00
|
|
|
|
occur: Optional
|
2013-09-17 20:42:23 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
/// Create a long option that is optional, takes an argument, and may occur
|
2013-09-17 20:42:23 -05:00
|
|
|
|
/// multiple times.
|
2014-02-03 21:14:40 -06:00
|
|
|
|
pub fn optmulti(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
|
|
|
|
|
let len = short_name.len();
|
|
|
|
|
assert!(len == 1 || len == 0);
|
|
|
|
|
OptGroup {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
short_name: short_name.to_string(),
|
|
|
|
|
long_name: long_name.to_string(),
|
|
|
|
|
hint: hint.to_string(),
|
|
|
|
|
desc: desc.to_string(),
|
2013-09-17 20:42:23 -05:00
|
|
|
|
hasarg: Yes,
|
2014-02-03 21:14:40 -06:00
|
|
|
|
occur: Multi
|
2013-09-17 20:42:23 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
2011-04-26 10:46:54 -05:00
|
|
|
|
|
2014-03-05 07:32:30 -06:00
|
|
|
|
/// Create a generic option group, stating all parameters explicitly
|
|
|
|
|
pub fn opt(short_name: &str,
|
|
|
|
|
long_name: &str,
|
|
|
|
|
desc: &str,
|
|
|
|
|
hint: &str,
|
|
|
|
|
hasarg: HasArg,
|
|
|
|
|
occur: Occur) -> OptGroup {
|
|
|
|
|
let len = short_name.len();
|
|
|
|
|
assert!(len == 1 || len == 0);
|
|
|
|
|
OptGroup {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
short_name: short_name.to_string(),
|
|
|
|
|
long_name: long_name.to_string(),
|
|
|
|
|
hint: hint.to_string(),
|
|
|
|
|
desc: desc.to_string(),
|
2014-03-05 07:32:30 -06:00
|
|
|
|
hasarg: hasarg,
|
|
|
|
|
occur: occur
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-17 20:42:23 -05:00
|
|
|
|
impl Fail_ {
|
|
|
|
|
/// Convert a `Fail_` enum into an error string.
|
2014-06-13 20:11:09 -05:00
|
|
|
|
#[deprecated="use `Show` (`{}` format specifier)"]
|
2014-05-22 18:57:53 -05:00
|
|
|
|
pub fn to_err_msg(self) -> String {
|
2014-06-21 05:39:03 -05:00
|
|
|
|
self.to_string()
|
2014-06-13 20:11:09 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl fmt::Show for Fail_ {
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
|
match *self {
|
2013-09-17 20:42:23 -05:00
|
|
|
|
ArgumentMissing(ref nm) => {
|
2014-06-13 20:11:09 -05:00
|
|
|
|
write!(f, "Argument to option '{}' missing.", *nm)
|
2013-09-17 20:42:23 -05:00
|
|
|
|
}
|
|
|
|
|
UnrecognizedOption(ref nm) => {
|
2014-06-13 20:11:09 -05:00
|
|
|
|
write!(f, "Unrecognized option: '{}'.", *nm)
|
2013-09-17 20:42:23 -05:00
|
|
|
|
}
|
|
|
|
|
OptionMissing(ref nm) => {
|
2014-06-13 20:11:09 -05:00
|
|
|
|
write!(f, "Required option '{}' missing.", *nm)
|
2013-09-17 20:42:23 -05:00
|
|
|
|
}
|
|
|
|
|
OptionDuplicated(ref nm) => {
|
2014-06-13 20:11:09 -05:00
|
|
|
|
write!(f, "Option '{}' given more than once.", *nm)
|
2013-09-17 20:42:23 -05:00
|
|
|
|
}
|
|
|
|
|
UnexpectedArgument(ref nm) => {
|
2014-06-13 20:11:09 -05:00
|
|
|
|
write!(f, "Option '{}' does not take an argument.", *nm)
|
2013-09-17 20:42:23 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Parse command line arguments according to the provided options.
|
|
|
|
|
///
|
2014-07-28 11:35:31 -05:00
|
|
|
|
/// On success returns `Ok(Matches)`. Use methods such as `opt_present`
|
2014-06-13 20:11:09 -05:00
|
|
|
|
/// `opt_str`, etc. to interrogate results. Returns `Err(Fail_)` on
|
|
|
|
|
/// failure: use the `Show` implementation of `Fail_` to display
|
|
|
|
|
/// information about it.
|
2014-05-22 18:57:53 -05:00
|
|
|
|
pub fn getopts(args: &[String], optgrps: &[OptGroup]) -> Result {
|
2014-03-21 07:25:16 -05:00
|
|
|
|
let opts: Vec<Opt> = optgrps.iter().map(|x| x.long_to_short()).collect();
|
2013-04-09 00:31:42 -05:00
|
|
|
|
let n_opts = opts.len();
|
2013-09-17 20:42:23 -05:00
|
|
|
|
|
2014-03-05 17:28:08 -06:00
|
|
|
|
fn f(_x: uint) -> Vec<Optval> { return Vec::new(); }
|
2013-09-17 20:42:23 -05:00
|
|
|
|
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let mut vals = Vec::from_fn(n_opts, f);
|
2014-05-22 18:57:53 -05:00
|
|
|
|
let mut free: Vec<String> = Vec::new();
|
2013-04-09 00:31:42 -05:00
|
|
|
|
let l = args.len();
|
|
|
|
|
let mut i = 0;
|
|
|
|
|
while i < l {
|
2013-07-02 14:47:32 -05:00
|
|
|
|
let cur = args[i].clone();
|
2013-04-09 00:31:42 -05:00
|
|
|
|
let curlen = cur.len();
|
2014-05-14 23:39:11 -05:00
|
|
|
|
if !is_arg(cur.as_slice()) {
|
2013-04-09 00:31:42 -05:00
|
|
|
|
free.push(cur);
|
2014-05-14 23:39:11 -05:00
|
|
|
|
} else if cur.as_slice() == "--" {
|
2013-04-09 00:31:42 -05:00
|
|
|
|
let mut j = i + 1;
|
2013-07-02 14:47:32 -05:00
|
|
|
|
while j < l { free.push(args[j].clone()); j += 1; }
|
2013-04-09 00:31:42 -05:00
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
let mut names;
|
|
|
|
|
let mut i_arg = None;
|
2014-08-06 12:06:37 -05:00
|
|
|
|
if cur.as_bytes()[1] == b'-' {
|
2014-05-14 23:39:11 -05:00
|
|
|
|
let tail = cur.as_slice().slice(2, curlen);
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let tail_eq: Vec<&str> = tail.split('=').collect();
|
2013-04-09 00:31:42 -05:00
|
|
|
|
if tail_eq.len() <= 1 {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
names = vec!(Long(tail.to_string()));
|
2013-01-23 13:43:58 -06:00
|
|
|
|
} else {
|
2013-04-09 00:31:42 -05:00
|
|
|
|
names =
|
2014-07-14 18:37:25 -05:00
|
|
|
|
vec!(Long(tail_eq[0].to_string()));
|
|
|
|
|
i_arg = Some(tail_eq[1].to_string());
|
2013-04-09 00:31:42 -05:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
let mut j = 1;
|
2014-03-05 17:28:08 -06:00
|
|
|
|
names = Vec::new();
|
2013-04-09 00:31:42 -05:00
|
|
|
|
while j < curlen {
|
2014-05-14 23:39:11 -05:00
|
|
|
|
let range = cur.as_slice().char_range_at(j);
|
2013-04-09 00:31:42 -05:00
|
|
|
|
let opt = Short(range.ch);
|
2012-07-04 10:36:31 -05:00
|
|
|
|
|
2013-04-09 00:31:42 -05:00
|
|
|
|
/* In a series of potential options (eg. -aheJ), if we
|
|
|
|
|
see one which takes an argument, we assume all
|
|
|
|
|
subsequent characters make up the argument. This
|
|
|
|
|
allows options such as -L/usr/local/lib/foo to be
|
|
|
|
|
interpreted correctly
|
|
|
|
|
*/
|
2012-07-04 17:01:24 -05:00
|
|
|
|
|
2014-08-14 23:44:55 -05:00
|
|
|
|
let opt_id = match find_opt(opts.as_slice(), opt.clone()) {
|
|
|
|
|
Some(id) => id,
|
|
|
|
|
None => return Err(UnrecognizedOption(opt.to_string()))
|
|
|
|
|
};
|
|
|
|
|
|
2013-04-09 00:31:42 -05:00
|
|
|
|
names.push(opt);
|
2014-08-14 23:44:55 -05:00
|
|
|
|
|
|
|
|
|
let arg_follows = match opts[opt_id].hasarg {
|
|
|
|
|
Yes | Maybe => true,
|
|
|
|
|
No => false
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if arg_follows && range.next < curlen {
|
|
|
|
|
i_arg = Some(cur.as_slice()
|
|
|
|
|
.slice(range.next, curlen).to_string());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-09 00:31:42 -05:00
|
|
|
|
j = range.next;
|
2011-04-26 10:46:54 -05:00
|
|
|
|
}
|
2013-04-09 00:31:42 -05:00
|
|
|
|
}
|
|
|
|
|
let mut name_pos = 0;
|
2013-08-03 11:45:23 -05:00
|
|
|
|
for nm in names.iter() {
|
2013-04-09 00:31:42 -05:00
|
|
|
|
name_pos += 1;
|
2014-03-21 07:25:16 -05:00
|
|
|
|
let optid = match find_opt(opts.as_slice(), (*nm).clone()) {
|
2013-04-09 00:31:42 -05:00
|
|
|
|
Some(id) => id,
|
2014-06-21 05:39:03 -05:00
|
|
|
|
None => return Err(UnrecognizedOption(nm.to_string()))
|
2013-04-09 00:31:42 -05:00
|
|
|
|
};
|
2014-07-14 18:37:25 -05:00
|
|
|
|
match opts[optid].hasarg {
|
2013-04-09 00:31:42 -05:00
|
|
|
|
No => {
|
2014-08-14 23:44:55 -05:00
|
|
|
|
if name_pos == names.len() && !i_arg.is_none() {
|
2014-06-21 05:39:03 -05:00
|
|
|
|
return Err(UnexpectedArgument(nm.to_string()));
|
2013-01-23 13:43:58 -06:00
|
|
|
|
}
|
2014-03-05 17:28:08 -06:00
|
|
|
|
vals.get_mut(optid).push(Given);
|
2013-04-09 00:31:42 -05:00
|
|
|
|
}
|
|
|
|
|
Maybe => {
|
|
|
|
|
if !i_arg.is_none() {
|
2014-03-05 17:28:08 -06:00
|
|
|
|
vals.get_mut(optid)
|
|
|
|
|
.push(Val((i_arg.clone())
|
|
|
|
|
.unwrap()));
|
2014-05-14 23:39:11 -05:00
|
|
|
|
} else if name_pos < names.len() || i + 1 == l ||
|
|
|
|
|
is_arg(args[i + 1].as_slice()) {
|
2014-03-05 17:28:08 -06:00
|
|
|
|
vals.get_mut(optid).push(Given);
|
|
|
|
|
} else {
|
|
|
|
|
i += 1;
|
|
|
|
|
vals.get_mut(optid).push(Val(args[i].clone()));
|
|
|
|
|
}
|
2013-04-09 00:31:42 -05:00
|
|
|
|
}
|
|
|
|
|
Yes => {
|
|
|
|
|
if !i_arg.is_none() {
|
2014-03-05 17:28:08 -06:00
|
|
|
|
vals.get_mut(optid).push(Val(i_arg.clone().unwrap()));
|
2013-04-09 00:31:42 -05:00
|
|
|
|
} else if i + 1 == l {
|
2014-06-21 05:39:03 -05:00
|
|
|
|
return Err(ArgumentMissing(nm.to_string()));
|
2014-03-05 17:28:08 -06:00
|
|
|
|
} else {
|
|
|
|
|
i += 1;
|
|
|
|
|
vals.get_mut(optid).push(Val(args[i].clone()));
|
|
|
|
|
}
|
2013-04-09 00:31:42 -05:00
|
|
|
|
}
|
2011-04-26 10:46:54 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-04-09 00:31:42 -05:00
|
|
|
|
i += 1;
|
|
|
|
|
}
|
|
|
|
|
i = 0u;
|
|
|
|
|
while i < n_opts {
|
2014-07-14 18:37:25 -05:00
|
|
|
|
let n = vals[i].len();
|
|
|
|
|
let occ = opts[i].occur;
|
2013-04-09 00:31:42 -05:00
|
|
|
|
if occ == Req {
|
|
|
|
|
if n == 0 {
|
2014-07-14 18:37:25 -05:00
|
|
|
|
return Err(OptionMissing(opts[i].name.to_string()));
|
2011-06-15 13:19:50 -05:00
|
|
|
|
}
|
2013-04-09 00:31:42 -05:00
|
|
|
|
}
|
|
|
|
|
if occ != Multi {
|
|
|
|
|
if n > 1 {
|
2014-07-14 18:37:25 -05:00
|
|
|
|
return Err(OptionDuplicated(opts[i].name.to_string()));
|
2011-06-15 13:19:50 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
2013-04-09 00:31:42 -05:00
|
|
|
|
i += 1;
|
2011-04-26 10:46:54 -05:00
|
|
|
|
}
|
2013-09-17 20:42:23 -05:00
|
|
|
|
Ok(Matches {
|
2014-03-21 07:25:16 -05:00
|
|
|
|
opts: opts,
|
2013-09-17 20:42:23 -05:00
|
|
|
|
vals: vals,
|
|
|
|
|
free: free
|
|
|
|
|
})
|
2012-05-31 19:02:03 -05:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
/// Derive a usage message from a set of long options.
|
2014-05-22 18:57:53 -05:00
|
|
|
|
pub fn usage(brief: &str, opts: &[OptGroup]) -> String {
|
2012-10-11 18:54:31 -05:00
|
|
|
|
|
2014-05-19 19:23:26 -05:00
|
|
|
|
let desc_sep = format!("\n{}", " ".repeat(24));
|
2012-10-11 18:54:31 -05:00
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
let mut rows = opts.iter().map(|optref| {
|
2014-10-05 19:36:53 -05:00
|
|
|
|
let OptGroup{short_name,
|
|
|
|
|
long_name,
|
|
|
|
|
hint,
|
|
|
|
|
desc,
|
|
|
|
|
hasarg,
|
2014-02-03 21:14:40 -06:00
|
|
|
|
..} = (*optref).clone();
|
2013-08-05 07:34:58 -05:00
|
|
|
|
|
2014-05-24 23:59:56 -05:00
|
|
|
|
let mut row = " ".repeat(4);
|
2012-10-11 18:54:31 -05:00
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
// short option
|
|
|
|
|
match short_name.len() {
|
|
|
|
|
0 => {}
|
|
|
|
|
1 => {
|
2014-09-22 10:28:35 -05:00
|
|
|
|
row.push('-');
|
2014-05-14 23:39:11 -05:00
|
|
|
|
row.push_str(short_name.as_slice());
|
2014-09-22 10:28:35 -05:00
|
|
|
|
row.push(' ');
|
2014-02-03 21:14:40 -06:00
|
|
|
|
}
|
|
|
|
|
_ => fail!("the short name should only be 1 ascii char long"),
|
2013-09-17 20:42:23 -05:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
// long option
|
|
|
|
|
match long_name.len() {
|
|
|
|
|
0 => {}
|
|
|
|
|
_ => {
|
|
|
|
|
row.push_str("--");
|
2014-05-14 23:39:11 -05:00
|
|
|
|
row.push_str(long_name.as_slice());
|
2014-09-22 10:28:35 -05:00
|
|
|
|
row.push(' ');
|
2014-02-03 21:14:40 -06:00
|
|
|
|
}
|
2013-09-17 20:42:23 -05:00
|
|
|
|
}
|
2012-10-11 18:54:31 -05:00
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
// arg
|
|
|
|
|
match hasarg {
|
|
|
|
|
No => {}
|
2014-05-14 23:39:11 -05:00
|
|
|
|
Yes => row.push_str(hint.as_slice()),
|
2014-02-03 21:14:40 -06:00
|
|
|
|
Maybe => {
|
2014-09-22 10:28:35 -05:00
|
|
|
|
row.push('[');
|
2014-05-14 23:39:11 -05:00
|
|
|
|
row.push_str(hint.as_slice());
|
2014-09-22 10:28:35 -05:00
|
|
|
|
row.push(']');
|
2014-02-03 21:14:40 -06:00
|
|
|
|
}
|
2014-02-02 14:52:51 -06:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
// FIXME: #5516 should be graphemes not codepoints
|
|
|
|
|
// here we just need to indent the start of the description
|
2014-04-02 18:54:22 -05:00
|
|
|
|
let rowlen = row.as_slice().char_len();
|
2014-02-03 21:14:40 -06:00
|
|
|
|
if rowlen < 24 {
|
|
|
|
|
for _ in range(0, 24 - rowlen) {
|
2014-09-22 10:28:35 -05:00
|
|
|
|
row.push(' ');
|
2014-02-03 21:14:40 -06:00
|
|
|
|
}
|
2014-02-02 14:52:51 -06:00
|
|
|
|
} else {
|
2014-05-19 19:23:26 -05:00
|
|
|
|
row.push_str(desc_sep.as_slice())
|
2014-02-02 14:52:51 -06:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
// Normalize desc to contain words separated by one space character
|
2014-05-22 18:57:53 -05:00
|
|
|
|
let mut desc_normalized_whitespace = String::new();
|
2014-05-14 23:39:11 -05:00
|
|
|
|
for word in desc.as_slice().words() {
|
2014-02-03 21:14:40 -06:00
|
|
|
|
desc_normalized_whitespace.push_str(word);
|
2014-09-22 10:28:35 -05:00
|
|
|
|
desc_normalized_whitespace.push(' ');
|
2014-02-02 14:52:51 -06:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
// FIXME: #5516 should be graphemes not codepoints
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let mut desc_rows = Vec::new();
|
2014-04-02 18:54:22 -05:00
|
|
|
|
each_split_within(desc_normalized_whitespace.as_slice(),
|
|
|
|
|
54,
|
|
|
|
|
|substr| {
|
2014-05-25 05:10:11 -05:00
|
|
|
|
desc_rows.push(substr.to_string());
|
2014-02-03 21:14:40 -06:00
|
|
|
|
true
|
|
|
|
|
});
|
2014-02-02 14:52:51 -06:00
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
// FIXME: #5516 should be graphemes not codepoints
|
|
|
|
|
// wrapped description
|
2014-05-19 19:23:26 -05:00
|
|
|
|
row.push_str(desc_rows.connect(desc_sep.as_slice()).as_slice());
|
2014-02-02 14:52:51 -06:00
|
|
|
|
|
2014-05-14 23:39:11 -05:00
|
|
|
|
row
|
2014-02-03 21:14:40 -06:00
|
|
|
|
});
|
2014-02-02 14:52:51 -06:00
|
|
|
|
|
2014-05-27 22:44:58 -05:00
|
|
|
|
format!("{}\n\nOptions:\n{}\n", brief,
|
|
|
|
|
rows.collect::<Vec<String>>().connect("\n"))
|
2014-02-03 21:14:40 -06:00
|
|
|
|
}
|
2014-02-02 14:52:51 -06:00
|
|
|
|
|
2014-05-22 18:57:53 -05:00
|
|
|
|
fn format_option(opt: &OptGroup) -> String {
|
|
|
|
|
let mut line = String::new();
|
2012-10-11 18:54:31 -05:00
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
if opt.occur != Req {
|
2014-09-22 10:28:35 -05:00
|
|
|
|
line.push('[');
|
2014-02-03 21:14:40 -06:00
|
|
|
|
}
|
2012-10-11 18:54:31 -05:00
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
// Use short_name is possible, but fallback to long_name.
|
|
|
|
|
if opt.short_name.len() > 0 {
|
2014-09-22 10:28:35 -05:00
|
|
|
|
line.push('-');
|
2014-05-14 23:39:11 -05:00
|
|
|
|
line.push_str(opt.short_name.as_slice());
|
2014-02-03 21:14:40 -06:00
|
|
|
|
} else {
|
|
|
|
|
line.push_str("--");
|
2014-05-14 23:39:11 -05:00
|
|
|
|
line.push_str(opt.long_name.as_slice());
|
2014-02-03 21:14:40 -06:00
|
|
|
|
}
|
2012-10-11 18:54:31 -05:00
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
if opt.hasarg != No {
|
2014-09-22 10:28:35 -05:00
|
|
|
|
line.push(' ');
|
2014-02-03 21:14:40 -06:00
|
|
|
|
if opt.hasarg == Maybe {
|
2014-09-22 10:28:35 -05:00
|
|
|
|
line.push('[');
|
2014-02-03 21:14:40 -06:00
|
|
|
|
}
|
2014-05-14 23:39:11 -05:00
|
|
|
|
line.push_str(opt.hint.as_slice());
|
2014-02-03 21:14:40 -06:00
|
|
|
|
if opt.hasarg == Maybe {
|
2014-09-22 10:28:35 -05:00
|
|
|
|
line.push(']');
|
2014-02-03 21:14:40 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
2012-10-11 18:54:31 -05:00
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
if opt.occur != Req {
|
2014-09-22 10:28:35 -05:00
|
|
|
|
line.push(']');
|
2014-02-03 21:14:40 -06:00
|
|
|
|
}
|
|
|
|
|
if opt.occur == Multi {
|
|
|
|
|
line.push_str("..");
|
|
|
|
|
}
|
2012-10-11 18:54:31 -05:00
|
|
|
|
|
2014-05-14 23:39:11 -05:00
|
|
|
|
line
|
2014-02-03 21:14:40 -06:00
|
|
|
|
}
|
2012-10-11 18:54:31 -05:00
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
/// Derive a short one-line usage summary from a set of long options.
|
2014-05-22 18:57:53 -05:00
|
|
|
|
pub fn short_usage(program_name: &str, opts: &[OptGroup]) -> String {
|
2014-05-27 22:44:58 -05:00
|
|
|
|
let mut line = format!("Usage: {} ", program_name);
|
2014-05-19 19:23:26 -05:00
|
|
|
|
line.push_str(opts.iter()
|
|
|
|
|
.map(format_option)
|
2014-05-22 18:57:53 -05:00
|
|
|
|
.collect::<Vec<String>>()
|
2014-05-19 19:23:26 -05:00
|
|
|
|
.connect(" ")
|
|
|
|
|
.as_slice());
|
2014-05-14 23:39:11 -05:00
|
|
|
|
line
|
2014-02-03 21:14:40 -06:00
|
|
|
|
}
|
2012-10-11 18:54:31 -05:00
|
|
|
|
|
2013-03-23 11:25:16 -05:00
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
/// Splits a string into substrings with possibly internal whitespace,
|
|
|
|
|
/// each of them at most `lim` bytes long. The substrings have leading and trailing
|
|
|
|
|
/// whitespace removed, and are only cut at whitespace boundaries.
|
|
|
|
|
///
|
|
|
|
|
/// Note: Function was moved here from `std::str` because this module is the only place that
|
2014-10-07 02:00:26 -05:00
|
|
|
|
/// uses it, and because it was too specific for a general string function.
|
2014-02-03 21:14:40 -06:00
|
|
|
|
///
|
|
|
|
|
/// #Failure:
|
|
|
|
|
///
|
|
|
|
|
/// Fails during iteration if the string contains a non-whitespace
|
|
|
|
|
/// sequence longer than the limit.
|
|
|
|
|
fn each_split_within<'a>(ss: &'a str, lim: uint, it: |&'a str| -> bool)
|
|
|
|
|
-> bool {
|
|
|
|
|
// Just for fun, let's write this as a state machine:
|
|
|
|
|
|
|
|
|
|
enum SplitWithinState {
|
|
|
|
|
A, // leading whitespace, initial state
|
|
|
|
|
B, // words
|
|
|
|
|
C, // internal and trailing whitespace
|
|
|
|
|
}
|
|
|
|
|
enum Whitespace {
|
|
|
|
|
Ws, // current char is whitespace
|
|
|
|
|
Cr // current char is not whitespace
|
|
|
|
|
}
|
|
|
|
|
enum LengthLimit {
|
|
|
|
|
UnderLim, // current char makes current substring still fit in limit
|
|
|
|
|
OverLim // current char makes current substring no longer fit in limit
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut slice_start = 0;
|
|
|
|
|
let mut last_start = 0;
|
|
|
|
|
let mut last_end = 0;
|
|
|
|
|
let mut state = A;
|
|
|
|
|
let mut fake_i = ss.len();
|
|
|
|
|
let mut lim = lim;
|
|
|
|
|
|
|
|
|
|
let mut cont = true;
|
|
|
|
|
|
|
|
|
|
// if the limit is larger than the string, lower it to save cycles
|
|
|
|
|
if lim >= fake_i {
|
|
|
|
|
lim = fake_i;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-09 06:37:03 -06:00
|
|
|
|
let machine: |&mut bool, (uint, char)| -> bool = |cont, (i, c)| {
|
2014-02-03 21:14:40 -06:00
|
|
|
|
let whitespace = if ::std::char::is_whitespace(c) { Ws } else { Cr };
|
|
|
|
|
let limit = if (i - slice_start + 1) <= lim { UnderLim } else { OverLim };
|
|
|
|
|
|
|
|
|
|
state = match (state, whitespace, limit) {
|
|
|
|
|
(A, Ws, _) => { A }
|
|
|
|
|
(A, Cr, _) => { slice_start = i; last_start = i; B }
|
|
|
|
|
|
|
|
|
|
(B, Cr, UnderLim) => { B }
|
|
|
|
|
(B, Cr, OverLim) if (i - last_start + 1) > lim
|
|
|
|
|
=> fail!("word starting with {} longer than limit!",
|
|
|
|
|
ss.slice(last_start, i + 1)),
|
2014-02-09 06:37:03 -06:00
|
|
|
|
(B, Cr, OverLim) => {
|
|
|
|
|
*cont = it(ss.slice(slice_start, last_end));
|
|
|
|
|
slice_start = last_start;
|
|
|
|
|
B
|
|
|
|
|
}
|
|
|
|
|
(B, Ws, UnderLim) => {
|
|
|
|
|
last_end = i;
|
|
|
|
|
C
|
|
|
|
|
}
|
|
|
|
|
(B, Ws, OverLim) => {
|
|
|
|
|
last_end = i;
|
|
|
|
|
*cont = it(ss.slice(slice_start, last_end));
|
|
|
|
|
A
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(C, Cr, UnderLim) => {
|
|
|
|
|
last_start = i;
|
|
|
|
|
B
|
|
|
|
|
}
|
|
|
|
|
(C, Cr, OverLim) => {
|
|
|
|
|
*cont = it(ss.slice(slice_start, last_end));
|
|
|
|
|
slice_start = i;
|
|
|
|
|
last_start = i;
|
|
|
|
|
last_end = i;
|
|
|
|
|
B
|
|
|
|
|
}
|
|
|
|
|
(C, Ws, OverLim) => {
|
|
|
|
|
*cont = it(ss.slice(slice_start, last_end));
|
|
|
|
|
A
|
|
|
|
|
}
|
|
|
|
|
(C, Ws, UnderLim) => {
|
|
|
|
|
C
|
|
|
|
|
}
|
2014-02-03 21:14:40 -06:00
|
|
|
|
};
|
2013-03-23 11:25:16 -05:00
|
|
|
|
|
2014-02-09 06:37:03 -06:00
|
|
|
|
*cont
|
2014-02-03 21:14:40 -06:00
|
|
|
|
};
|
2012-10-11 18:54:31 -05:00
|
|
|
|
|
2014-06-12 04:35:02 -05:00
|
|
|
|
ss.char_indices().all(|x| machine(&mut cont, x));
|
2012-10-11 18:54:31 -05:00
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
// Let the automaton 'run out' by supplying trailing whitespace
|
|
|
|
|
while cont && match state { B | C => true, A => false } {
|
2014-02-09 06:37:03 -06:00
|
|
|
|
machine(&mut cont, (fake_i, ' '));
|
2014-02-03 21:14:40 -06:00
|
|
|
|
fake_i += 1;
|
2013-09-17 20:42:23 -05:00
|
|
|
|
}
|
2014-02-03 21:14:40 -06:00
|
|
|
|
return cont;
|
|
|
|
|
}
|
2013-09-17 20:42:23 -05:00
|
|
|
|
|
2014-02-04 18:15:03 -06:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_split_within() {
|
2014-05-22 18:57:53 -05:00
|
|
|
|
fn t(s: &str, i: uint, u: &[String]) {
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let mut v = Vec::new();
|
2014-05-25 05:17:19 -05:00
|
|
|
|
each_split_within(s, i, |s| { v.push(s.to_string()); true });
|
2014-02-04 18:15:03 -06:00
|
|
|
|
assert!(v.iter().zip(u.iter()).all(|(a,b)| a == b));
|
|
|
|
|
}
|
|
|
|
|
t("", 0, []);
|
|
|
|
|
t("", 15, []);
|
2014-05-25 05:17:19 -05:00
|
|
|
|
t("hello", 15, ["hello".to_string()]);
|
2014-05-14 23:39:11 -05:00
|
|
|
|
t("\nMary had a little lamb\nLittle lamb\n", 15, [
|
2014-05-25 05:17:19 -05:00
|
|
|
|
"Mary had a".to_string(),
|
|
|
|
|
"little lamb".to_string(),
|
|
|
|
|
"Little lamb".to_string()
|
2014-05-14 23:39:11 -05:00
|
|
|
|
]);
|
2014-02-04 18:15:03 -06:00
|
|
|
|
t("\nMary had a little lamb\nLittle lamb\n", ::std::uint::MAX,
|
2014-05-25 05:17:19 -05:00
|
|
|
|
["Mary had a little lamb\nLittle lamb".to_string()]);
|
2014-02-04 18:15:03 -06:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
2013-07-27 16:38:38 -05:00
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
use std::result::{Err, Ok};
|
|
|
|
|
use std::result;
|
2013-07-27 16:38:38 -05:00
|
|
|
|
|
2014-02-03 21:14:40 -06:00
|
|
|
|
fn check_fail_type(f: Fail_, ft: FailType) {
|
|
|
|
|
match f {
|
|
|
|
|
ArgumentMissing(_) => assert!(ft == ArgumentMissing_),
|
|
|
|
|
UnrecognizedOption(_) => assert!(ft == UnrecognizedOption_),
|
|
|
|
|
OptionMissing(_) => assert!(ft == OptionMissing_),
|
|
|
|
|
OptionDuplicated(_) => assert!(ft == OptionDuplicated_),
|
|
|
|
|
UnexpectedArgument(_) => assert!(ft == UnexpectedArgument_)
|
2013-07-27 16:38:38 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-17 21:05:07 -06:00
|
|
|
|
// Tests for reqopt
|
|
|
|
|
#[test]
|
2014-02-04 18:15:03 -06:00
|
|
|
|
fn test_reqopt() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let long_args = vec!("--test=20".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(reqopt("t", "test", "testing", "TEST"));
|
|
|
|
|
let rs = getopts(long_args.as_slice(), opts.as_slice());
|
2012-08-15 13:55:17 -05:00
|
|
|
|
match rs {
|
2012-11-24 14:49:31 -06:00
|
|
|
|
Ok(ref m) => {
|
2013-09-17 20:42:23 -05:00
|
|
|
|
assert!(m.opt_present("test"));
|
2014-05-25 05:17:19 -05:00
|
|
|
|
assert_eq!(m.opt_str("test").unwrap(), "20".to_string());
|
2014-02-04 18:15:03 -06:00
|
|
|
|
assert!(m.opt_present("t"));
|
2014-05-25 05:17:19 -05:00
|
|
|
|
assert_eq!(m.opt_str("t").unwrap(), "20".to_string());
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
2014-02-04 18:15:03 -06:00
|
|
|
|
_ => { fail!("test_reqopt failed (long arg)"); }
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let short_args = vec!("-t".to_string(), "20".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
match getopts(short_args.as_slice(), opts.as_slice()) {
|
2012-11-24 14:49:31 -06:00
|
|
|
|
Ok(ref m) => {
|
2014-02-04 18:15:03 -06:00
|
|
|
|
assert!((m.opt_present("test")));
|
2014-05-25 05:17:19 -05:00
|
|
|
|
assert_eq!(m.opt_str("test").unwrap(), "20".to_string());
|
2014-02-04 18:15:03 -06:00
|
|
|
|
assert!((m.opt_present("t")));
|
2014-05-25 05:17:19 -05:00
|
|
|
|
assert_eq!(m.opt_str("t").unwrap(), "20".to_string());
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
2014-02-04 18:15:03 -06:00
|
|
|
|
_ => { fail!("test_reqopt failed (short arg)"); }
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2014-02-04 18:15:03 -06:00
|
|
|
|
fn test_reqopt_missing() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let args = vec!("blah".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(reqopt("t", "test", "testing", "TEST"));
|
|
|
|
|
let rs = getopts(args.as_slice(), opts.as_slice());
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match rs {
|
2013-05-29 18:59:33 -05:00
|
|
|
|
Err(f) => check_fail_type(f, OptionMissing_),
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2014-02-04 18:15:03 -06:00
|
|
|
|
fn test_reqopt_no_arg() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let long_args = vec!("--test".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(reqopt("t", "test", "testing", "TEST"));
|
|
|
|
|
let rs = getopts(long_args.as_slice(), opts.as_slice());
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match rs {
|
2013-05-29 18:59:33 -05:00
|
|
|
|
Err(f) => check_fail_type(f, ArgumentMissing_),
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let short_args = vec!("-t".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
match getopts(short_args.as_slice(), opts.as_slice()) {
|
2014-02-04 18:15:03 -06:00
|
|
|
|
Err(f) => check_fail_type(f, ArgumentMissing_),
|
|
|
|
|
_ => fail!()
|
|
|
|
|
}
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2014-02-04 18:15:03 -06:00
|
|
|
|
fn test_reqopt_multi() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let args = vec!("--test=20".to_string(), "-t".to_string(), "30".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(reqopt("t", "test", "testing", "TEST"));
|
|
|
|
|
let rs = getopts(args.as_slice(), opts.as_slice());
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match rs {
|
2013-05-29 18:59:33 -05:00
|
|
|
|
Err(f) => check_fail_type(f, OptionDuplicated_),
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Tests for optopt
|
|
|
|
|
#[test]
|
2014-02-04 18:15:03 -06:00
|
|
|
|
fn test_optopt() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let long_args = vec!("--test=20".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(optopt("t", "test", "testing", "TEST"));
|
|
|
|
|
let rs = getopts(long_args.as_slice(), opts.as_slice());
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match rs {
|
2012-11-24 14:49:31 -06:00
|
|
|
|
Ok(ref m) => {
|
2013-09-17 20:42:23 -05:00
|
|
|
|
assert!(m.opt_present("test"));
|
2014-05-25 05:17:19 -05:00
|
|
|
|
assert_eq!(m.opt_str("test").unwrap(), "20".to_string());
|
2014-02-04 18:15:03 -06:00
|
|
|
|
assert!((m.opt_present("t")));
|
2014-05-25 05:17:19 -05:00
|
|
|
|
assert_eq!(m.opt_str("t").unwrap(), "20".to_string());
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let short_args = vec!("-t".to_string(), "20".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
match getopts(short_args.as_slice(), opts.as_slice()) {
|
2012-11-24 14:49:31 -06:00
|
|
|
|
Ok(ref m) => {
|
2014-02-04 18:15:03 -06:00
|
|
|
|
assert!((m.opt_present("test")));
|
2014-05-25 05:17:19 -05:00
|
|
|
|
assert_eq!(m.opt_str("test").unwrap(), "20".to_string());
|
2013-09-17 20:42:23 -05:00
|
|
|
|
assert!((m.opt_present("t")));
|
2014-05-25 05:17:19 -05:00
|
|
|
|
assert_eq!(m.opt_str("t").unwrap(), "20".to_string());
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2014-02-04 18:15:03 -06:00
|
|
|
|
fn test_optopt_missing() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let args = vec!("blah".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(optopt("t", "test", "testing", "TEST"));
|
|
|
|
|
let rs = getopts(args.as_slice(), opts.as_slice());
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match rs {
|
2014-02-04 18:15:03 -06:00
|
|
|
|
Ok(ref m) => {
|
|
|
|
|
assert!(!m.opt_present("test"));
|
|
|
|
|
assert!(!m.opt_present("t"));
|
|
|
|
|
}
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2014-02-04 18:15:03 -06:00
|
|
|
|
fn test_optopt_no_arg() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let long_args = vec!("--test".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(optopt("t", "test", "testing", "TEST"));
|
|
|
|
|
let rs = getopts(long_args.as_slice(), opts.as_slice());
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match rs {
|
2013-05-29 18:59:33 -05:00
|
|
|
|
Err(f) => check_fail_type(f, ArgumentMissing_),
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let short_args = vec!("-t".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
match getopts(short_args.as_slice(), opts.as_slice()) {
|
2014-02-04 18:15:03 -06:00
|
|
|
|
Err(f) => check_fail_type(f, ArgumentMissing_),
|
|
|
|
|
_ => fail!()
|
|
|
|
|
}
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2014-02-04 18:15:03 -06:00
|
|
|
|
fn test_optopt_multi() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let args = vec!("--test=20".to_string(), "-t".to_string(), "30".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(optopt("t", "test", "testing", "TEST"));
|
|
|
|
|
let rs = getopts(args.as_slice(), opts.as_slice());
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match rs {
|
2013-05-29 18:59:33 -05:00
|
|
|
|
Err(f) => check_fail_type(f, OptionDuplicated_),
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Tests for optflag
|
|
|
|
|
#[test]
|
2014-02-04 18:15:03 -06:00
|
|
|
|
fn test_optflag() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let long_args = vec!("--test".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(optflag("t", "test", "testing"));
|
|
|
|
|
let rs = getopts(long_args.as_slice(), opts.as_slice());
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match rs {
|
2014-02-04 18:15:03 -06:00
|
|
|
|
Ok(ref m) => {
|
|
|
|
|
assert!(m.opt_present("test"));
|
|
|
|
|
assert!(m.opt_present("t"));
|
|
|
|
|
}
|
|
|
|
|
_ => fail!()
|
|
|
|
|
}
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let short_args = vec!("-t".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
match getopts(short_args.as_slice(), opts.as_slice()) {
|
2014-02-04 18:15:03 -06:00
|
|
|
|
Ok(ref m) => {
|
|
|
|
|
assert!(m.opt_present("test"));
|
|
|
|
|
assert!(m.opt_present("t"));
|
|
|
|
|
}
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2014-02-04 18:15:03 -06:00
|
|
|
|
fn test_optflag_missing() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let args = vec!("blah".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(optflag("t", "test", "testing"));
|
|
|
|
|
let rs = getopts(args.as_slice(), opts.as_slice());
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match rs {
|
2014-02-04 18:15:03 -06:00
|
|
|
|
Ok(ref m) => {
|
|
|
|
|
assert!(!m.opt_present("test"));
|
|
|
|
|
assert!(!m.opt_present("t"));
|
|
|
|
|
}
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2013-04-15 10:08:52 -05:00
|
|
|
|
fn test_optflag_long_arg() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let args = vec!("--test=20".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(optflag("t", "test", "testing"));
|
|
|
|
|
let rs = getopts(args.as_slice(), opts.as_slice());
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match rs {
|
2013-05-29 18:59:33 -05:00
|
|
|
|
Err(f) => {
|
2012-08-11 09:08:42 -05:00
|
|
|
|
check_fail_type(f, UnexpectedArgument_);
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2014-02-04 18:15:03 -06:00
|
|
|
|
fn test_optflag_multi() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let args = vec!("--test".to_string(), "-t".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(optflag("t", "test", "testing"));
|
|
|
|
|
let rs = getopts(args.as_slice(), opts.as_slice());
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match rs {
|
2013-05-29 18:59:33 -05:00
|
|
|
|
Err(f) => check_fail_type(f, OptionDuplicated_),
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2013-04-15 10:08:52 -05:00
|
|
|
|
fn test_optflag_short_arg() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let args = vec!("-t".to_string(), "20".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(optflag("t", "test", "testing"));
|
|
|
|
|
let rs = getopts(args.as_slice(), opts.as_slice());
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match rs {
|
2012-09-28 04:26:20 -05:00
|
|
|
|
Ok(ref m) => {
|
2012-01-17 21:05:07 -06:00
|
|
|
|
// The next variable after the flag is just a free argument
|
|
|
|
|
|
2014-09-22 12:30:06 -05:00
|
|
|
|
assert!(m.free[0] == "20".to_string());
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-17 21:43:39 -06:00
|
|
|
|
// Tests for optflagmulti
|
|
|
|
|
#[test]
|
2013-04-15 10:08:52 -05:00
|
|
|
|
fn test_optflagmulti_short1() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let args = vec!("-v".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(optflagmulti("v", "verbose", "verbosity"));
|
|
|
|
|
let rs = getopts(args.as_slice(), opts.as_slice());
|
2012-11-17 21:43:39 -06:00
|
|
|
|
match rs {
|
2012-11-24 14:49:31 -06:00
|
|
|
|
Ok(ref m) => {
|
2013-09-17 20:42:23 -05:00
|
|
|
|
assert_eq!(m.opt_count("v"), 1);
|
2012-11-17 21:43:39 -06:00
|
|
|
|
}
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-11-17 21:43:39 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2013-04-15 10:08:52 -05:00
|
|
|
|
fn test_optflagmulti_short2a() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let args = vec!("-v".to_string(), "-v".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(optflagmulti("v", "verbose", "verbosity"));
|
|
|
|
|
let rs = getopts(args.as_slice(), opts.as_slice());
|
2012-11-17 21:43:39 -06:00
|
|
|
|
match rs {
|
2012-11-24 14:49:31 -06:00
|
|
|
|
Ok(ref m) => {
|
2013-09-17 20:42:23 -05:00
|
|
|
|
assert_eq!(m.opt_count("v"), 2);
|
2012-11-17 21:43:39 -06:00
|
|
|
|
}
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-11-17 21:43:39 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2013-04-15 10:08:52 -05:00
|
|
|
|
fn test_optflagmulti_short2b() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let args = vec!("-vv".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(optflagmulti("v", "verbose", "verbosity"));
|
|
|
|
|
let rs = getopts(args.as_slice(), opts.as_slice());
|
2012-11-17 21:43:39 -06:00
|
|
|
|
match rs {
|
2012-11-24 14:49:31 -06:00
|
|
|
|
Ok(ref m) => {
|
2013-09-17 20:42:23 -05:00
|
|
|
|
assert_eq!(m.opt_count("v"), 2);
|
2012-11-17 21:43:39 -06:00
|
|
|
|
}
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-11-17 21:43:39 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2013-04-15 10:08:52 -05:00
|
|
|
|
fn test_optflagmulti_long1() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let args = vec!("--verbose".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(optflagmulti("v", "verbose", "verbosity"));
|
|
|
|
|
let rs = getopts(args.as_slice(), opts.as_slice());
|
2012-11-17 21:43:39 -06:00
|
|
|
|
match rs {
|
2012-11-24 14:49:31 -06:00
|
|
|
|
Ok(ref m) => {
|
2013-09-17 20:42:23 -05:00
|
|
|
|
assert_eq!(m.opt_count("verbose"), 1);
|
2012-11-17 21:43:39 -06:00
|
|
|
|
}
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-11-17 21:43:39 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2013-04-15 10:08:52 -05:00
|
|
|
|
fn test_optflagmulti_long2() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let args = vec!("--verbose".to_string(), "--verbose".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(optflagmulti("v", "verbose", "verbosity"));
|
|
|
|
|
let rs = getopts(args.as_slice(), opts.as_slice());
|
2012-11-17 21:43:39 -06:00
|
|
|
|
match rs {
|
2012-11-24 14:49:31 -06:00
|
|
|
|
Ok(ref m) => {
|
2013-09-17 20:42:23 -05:00
|
|
|
|
assert_eq!(m.opt_count("verbose"), 2);
|
2012-11-17 21:43:39 -06:00
|
|
|
|
}
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-11-17 21:43:39 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
2012-01-17 21:05:07 -06:00
|
|
|
|
|
|
|
|
|
#[test]
|
2014-02-04 18:15:03 -06:00
|
|
|
|
fn test_optflagmulti_mix() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let args = vec!("--verbose".to_string(), "-v".to_string(),
|
|
|
|
|
"-vv".to_string(), "verbose".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(optflagmulti("v", "verbose", "verbosity"));
|
|
|
|
|
let rs = getopts(args.as_slice(), opts.as_slice());
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match rs {
|
2012-11-24 14:49:31 -06:00
|
|
|
|
Ok(ref m) => {
|
2014-02-04 18:15:03 -06:00
|
|
|
|
assert_eq!(m.opt_count("verbose"), 4);
|
|
|
|
|
assert_eq!(m.opt_count("v"), 4);
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-04 18:15:03 -06:00
|
|
|
|
// Tests for optmulti
|
2012-01-17 21:05:07 -06:00
|
|
|
|
#[test]
|
2014-02-04 18:15:03 -06:00
|
|
|
|
fn test_optmulti() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let long_args = vec!("--test=20".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(optmulti("t", "test", "testing", "TEST"));
|
|
|
|
|
let rs = getopts(long_args.as_slice(), opts.as_slice());
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match rs {
|
2012-11-24 14:49:31 -06:00
|
|
|
|
Ok(ref m) => {
|
2014-02-04 18:15:03 -06:00
|
|
|
|
assert!((m.opt_present("test")));
|
2014-05-25 05:17:19 -05:00
|
|
|
|
assert_eq!(m.opt_str("test").unwrap(), "20".to_string());
|
2014-02-04 18:15:03 -06:00
|
|
|
|
assert!((m.opt_present("t")));
|
2014-05-25 05:17:19 -05:00
|
|
|
|
assert_eq!(m.opt_str("t").unwrap(), "20".to_string());
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let short_args = vec!("-t".to_string(), "20".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
match getopts(short_args.as_slice(), opts.as_slice()) {
|
2012-11-24 14:49:31 -06:00
|
|
|
|
Ok(ref m) => {
|
2014-02-04 18:15:03 -06:00
|
|
|
|
assert!((m.opt_present("test")));
|
2014-05-25 05:17:19 -05:00
|
|
|
|
assert_eq!(m.opt_str("test").unwrap(), "20".to_string());
|
2013-09-17 20:42:23 -05:00
|
|
|
|
assert!((m.opt_present("t")));
|
2014-05-25 05:17:19 -05:00
|
|
|
|
assert_eq!(m.opt_str("t").unwrap(), "20".to_string());
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2014-02-04 18:15:03 -06:00
|
|
|
|
fn test_optmulti_missing() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let args = vec!("blah".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(optmulti("t", "test", "testing", "TEST"));
|
|
|
|
|
let rs = getopts(args.as_slice(), opts.as_slice());
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match rs {
|
2014-02-04 18:15:03 -06:00
|
|
|
|
Ok(ref m) => {
|
|
|
|
|
assert!(!m.opt_present("test"));
|
|
|
|
|
assert!(!m.opt_present("t"));
|
|
|
|
|
}
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2014-02-04 18:15:03 -06:00
|
|
|
|
fn test_optmulti_no_arg() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let long_args = vec!("--test".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(optmulti("t", "test", "testing", "TEST"));
|
|
|
|
|
let rs = getopts(long_args.as_slice(), opts.as_slice());
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match rs {
|
2013-05-29 18:59:33 -05:00
|
|
|
|
Err(f) => check_fail_type(f, ArgumentMissing_),
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let short_args = vec!("-t".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
match getopts(short_args.as_slice(), opts.as_slice()) {
|
2014-02-04 18:15:03 -06:00
|
|
|
|
Err(f) => check_fail_type(f, ArgumentMissing_),
|
|
|
|
|
_ => fail!()
|
|
|
|
|
}
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2014-02-04 18:15:03 -06:00
|
|
|
|
fn test_optmulti_multi() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let args = vec!("--test=20".to_string(), "-t".to_string(), "30".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(optmulti("t", "test", "testing", "TEST"));
|
|
|
|
|
let rs = getopts(args.as_slice(), opts.as_slice());
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match rs {
|
2012-11-24 14:49:31 -06:00
|
|
|
|
Ok(ref m) => {
|
2014-02-04 18:15:03 -06:00
|
|
|
|
assert!(m.opt_present("test"));
|
2014-05-25 05:17:19 -05:00
|
|
|
|
assert_eq!(m.opt_str("test").unwrap(), "20".to_string());
|
2014-02-04 18:15:03 -06:00
|
|
|
|
assert!(m.opt_present("t"));
|
2014-05-25 05:17:19 -05:00
|
|
|
|
assert_eq!(m.opt_str("t").unwrap(), "20".to_string());
|
2014-02-04 18:15:03 -06:00
|
|
|
|
let pair = m.opt_strs("test");
|
2014-09-22 12:30:06 -05:00
|
|
|
|
assert!(pair[0] == "20".to_string());
|
|
|
|
|
assert!(pair[1] == "30".to_string());
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2014-02-04 18:15:03 -06:00
|
|
|
|
fn test_unrecognized_option() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let long_args = vec!("--untest".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(optmulti("t", "test", "testing", "TEST"));
|
|
|
|
|
let rs = getopts(long_args.as_slice(), opts.as_slice());
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match rs {
|
2013-05-29 18:59:33 -05:00
|
|
|
|
Err(f) => check_fail_type(f, UnrecognizedOption_),
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let short_args = vec!("-u".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
match getopts(short_args.as_slice(), opts.as_slice()) {
|
2013-05-29 18:59:33 -05:00
|
|
|
|
Err(f) => check_fail_type(f, UnrecognizedOption_),
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2013-04-15 10:08:52 -05:00
|
|
|
|
fn test_combined() {
|
2012-01-17 21:05:07 -06:00
|
|
|
|
let args =
|
2014-05-25 05:17:19 -05:00
|
|
|
|
vec!("prog".to_string(),
|
|
|
|
|
"free1".to_string(),
|
|
|
|
|
"-s".to_string(),
|
|
|
|
|
"20".to_string(),
|
|
|
|
|
"free2".to_string(),
|
|
|
|
|
"--flag".to_string(),
|
|
|
|
|
"--long=30".to_string(),
|
|
|
|
|
"-f".to_string(),
|
|
|
|
|
"-m".to_string(),
|
|
|
|
|
"40".to_string(),
|
|
|
|
|
"-m".to_string(),
|
|
|
|
|
"50".to_string(),
|
|
|
|
|
"-n".to_string(),
|
|
|
|
|
"-A B".to_string(),
|
|
|
|
|
"-n".to_string(),
|
|
|
|
|
"-60 70".to_string());
|
2012-01-17 21:05:07 -06:00
|
|
|
|
let opts =
|
2014-03-05 17:28:08 -06:00
|
|
|
|
vec!(optopt("s", "something", "something", "SOMETHING"),
|
2014-02-04 18:15:03 -06:00
|
|
|
|
optflag("", "flag", "a flag"),
|
2014-02-03 21:14:40 -06:00
|
|
|
|
reqopt("", "long", "hi", "LONG"),
|
2014-02-04 18:15:03 -06:00
|
|
|
|
optflag("f", "", "another flag"),
|
2014-02-03 21:14:40 -06:00
|
|
|
|
optmulti("m", "", "mmmmmm", "YUM"),
|
|
|
|
|
optmulti("n", "", "nothing", "NOTHING"),
|
2014-03-05 17:28:08 -06:00
|
|
|
|
optopt("", "notpresent", "nothing to see here", "NOPE"));
|
|
|
|
|
let rs = getopts(args.as_slice(), opts.as_slice());
|
2012-08-06 14:34:08 -05:00
|
|
|
|
match rs {
|
2012-11-24 14:49:31 -06:00
|
|
|
|
Ok(ref m) => {
|
2014-09-22 12:30:06 -05:00
|
|
|
|
assert!(m.free[0] == "prog".to_string());
|
|
|
|
|
assert!(m.free[1] == "free1".to_string());
|
2014-05-25 05:17:19 -05:00
|
|
|
|
assert_eq!(m.opt_str("s").unwrap(), "20".to_string());
|
2014-09-22 12:30:06 -05:00
|
|
|
|
assert!(m.free[2] == "free2".to_string());
|
2013-09-17 20:42:23 -05:00
|
|
|
|
assert!((m.opt_present("flag")));
|
2014-05-25 05:17:19 -05:00
|
|
|
|
assert_eq!(m.opt_str("long").unwrap(), "30".to_string());
|
2013-09-17 20:42:23 -05:00
|
|
|
|
assert!((m.opt_present("f")));
|
|
|
|
|
let pair = m.opt_strs("m");
|
2014-09-22 12:30:06 -05:00
|
|
|
|
assert!(pair[0] == "40".to_string());
|
|
|
|
|
assert!(pair[1] == "50".to_string());
|
2013-09-17 20:42:23 -05:00
|
|
|
|
let pair = m.opt_strs("n");
|
2014-09-22 12:30:06 -05:00
|
|
|
|
assert!(pair[0] == "-A B".to_string());
|
|
|
|
|
assert!(pair[1] == "-60 70".to_string());
|
2013-09-17 20:42:23 -05:00
|
|
|
|
assert!((!m.opt_present("notpresent")));
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
2013-10-21 15:08:31 -05:00
|
|
|
|
_ => fail!()
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-31 19:02:03 -05:00
|
|
|
|
#[test]
|
2013-04-15 10:08:52 -05:00
|
|
|
|
fn test_multi() {
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(optopt("e", "", "encrypt", "ENCRYPT"),
|
2014-02-03 21:14:40 -06:00
|
|
|
|
optopt("", "encrypt", "encrypt", "ENCRYPT"),
|
2014-03-05 17:28:08 -06:00
|
|
|
|
optopt("f", "", "flag", "FLAG"));
|
2013-07-30 14:23:19 -05:00
|
|
|
|
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let args_single = vec!("-e".to_string(), "foo".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let matches_single = &match getopts(args_single.as_slice(),
|
|
|
|
|
opts.as_slice()) {
|
2013-07-30 14:23:19 -05:00
|
|
|
|
result::Ok(m) => m,
|
2013-10-21 15:08:31 -05:00
|
|
|
|
result::Err(_) => fail!()
|
2013-07-30 14:23:19 -05:00
|
|
|
|
};
|
2014-05-25 05:17:19 -05:00
|
|
|
|
assert!(matches_single.opts_present(["e".to_string()]));
|
|
|
|
|
assert!(matches_single.opts_present(["encrypt".to_string(), "e".to_string()]));
|
|
|
|
|
assert!(matches_single.opts_present(["e".to_string(), "encrypt".to_string()]));
|
|
|
|
|
assert!(!matches_single.opts_present(["encrypt".to_string()]));
|
|
|
|
|
assert!(!matches_single.opts_present(["thing".to_string()]));
|
2013-09-17 20:42:23 -05:00
|
|
|
|
assert!(!matches_single.opts_present([]));
|
2013-07-30 14:23:19 -05:00
|
|
|
|
|
2014-05-25 05:17:19 -05:00
|
|
|
|
assert_eq!(matches_single.opts_str(["e".to_string()]).unwrap(), "foo".to_string());
|
|
|
|
|
assert_eq!(matches_single.opts_str(["e".to_string(), "encrypt".to_string()]).unwrap(),
|
|
|
|
|
"foo".to_string());
|
|
|
|
|
assert_eq!(matches_single.opts_str(["encrypt".to_string(), "e".to_string()]).unwrap(),
|
|
|
|
|
"foo".to_string());
|
2013-07-30 14:23:19 -05:00
|
|
|
|
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let args_both = vec!("-e".to_string(), "foo".to_string(), "--encrypt".to_string(),
|
|
|
|
|
"foo".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let matches_both = &match getopts(args_both.as_slice(),
|
|
|
|
|
opts.as_slice()) {
|
2013-02-15 01:30:30 -06:00
|
|
|
|
result::Ok(m) => m,
|
2013-10-21 15:08:31 -05:00
|
|
|
|
result::Err(_) => fail!()
|
2012-05-31 19:02:03 -05:00
|
|
|
|
};
|
2014-05-25 05:17:19 -05:00
|
|
|
|
assert!(matches_both.opts_present(["e".to_string()]));
|
|
|
|
|
assert!(matches_both.opts_present(["encrypt".to_string()]));
|
|
|
|
|
assert!(matches_both.opts_present(["encrypt".to_string(), "e".to_string()]));
|
|
|
|
|
assert!(matches_both.opts_present(["e".to_string(), "encrypt".to_string()]));
|
|
|
|
|
assert!(!matches_both.opts_present(["f".to_string()]));
|
|
|
|
|
assert!(!matches_both.opts_present(["thing".to_string()]));
|
2013-09-17 20:42:23 -05:00
|
|
|
|
assert!(!matches_both.opts_present([]));
|
2013-07-30 14:23:19 -05:00
|
|
|
|
|
2014-05-25 05:17:19 -05:00
|
|
|
|
assert_eq!(matches_both.opts_str(["e".to_string()]).unwrap(), "foo".to_string());
|
|
|
|
|
assert_eq!(matches_both.opts_str(["encrypt".to_string()]).unwrap(), "foo".to_string());
|
|
|
|
|
assert_eq!(matches_both.opts_str(["e".to_string(), "encrypt".to_string()]).unwrap(),
|
|
|
|
|
"foo".to_string());
|
|
|
|
|
assert_eq!(matches_both.opts_str(["encrypt".to_string(), "e".to_string()]).unwrap(),
|
|
|
|
|
"foo".to_string());
|
2012-05-31 19:02:03 -05:00
|
|
|
|
}
|
2012-07-04 10:36:31 -05:00
|
|
|
|
|
|
|
|
|
#[test]
|
2013-04-15 10:08:52 -05:00
|
|
|
|
fn test_nospace() {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let args = vec!("-Lfoo".to_string(), "-M.".to_string());
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(optmulti("L", "", "library directory", "LIB"),
|
|
|
|
|
optmulti("M", "", "something", "MMMM"));
|
|
|
|
|
let matches = &match getopts(args.as_slice(), opts.as_slice()) {
|
2013-02-15 01:30:30 -06:00
|
|
|
|
result::Ok(m) => m,
|
2013-10-21 15:08:31 -05:00
|
|
|
|
result::Err(_) => fail!()
|
2012-07-04 10:36:31 -05:00
|
|
|
|
};
|
2014-05-25 05:17:19 -05:00
|
|
|
|
assert!(matches.opts_present(["L".to_string()]));
|
|
|
|
|
assert_eq!(matches.opts_str(["L".to_string()]).unwrap(), "foo".to_string());
|
|
|
|
|
assert!(matches.opts_present(["M".to_string()]));
|
|
|
|
|
assert_eq!(matches.opts_str(["M".to_string()]).unwrap(), ".".to_string());
|
2012-12-07 21:53:45 -06:00
|
|
|
|
|
2012-07-04 10:36:31 -05:00
|
|
|
|
}
|
2012-10-11 18:54:31 -05:00
|
|
|
|
|
2014-08-14 23:44:55 -05:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_nospace_conflict() {
|
|
|
|
|
let args = vec!("-vvLverbose".to_string(), "-v".to_string() );
|
|
|
|
|
let opts = vec!(optmulti("L", "", "library directory", "LIB"),
|
|
|
|
|
optflagmulti("v", "verbose", "Verbose"));
|
|
|
|
|
let matches = &match getopts(args.as_slice(), opts.as_slice()) {
|
|
|
|
|
result::Ok(m) => m,
|
|
|
|
|
result::Err(e) => fail!( "{}", e )
|
|
|
|
|
};
|
|
|
|
|
assert!(matches.opts_present(["L".to_string()]));
|
|
|
|
|
assert_eq!(matches.opts_str(["L".to_string()]).unwrap(), "verbose".to_string());
|
|
|
|
|
assert!(matches.opts_present(["v".to_string()]));
|
|
|
|
|
assert_eq!(3, matches.opt_count("v"));
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-11 18:54:31 -05:00
|
|
|
|
#[test]
|
2014-02-04 18:15:03 -06:00
|
|
|
|
fn test_long_to_short() {
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let mut short = Opt {
|
2014-05-25 05:17:19 -05:00
|
|
|
|
name: Long("banana".to_string()),
|
2014-03-05 17:28:08 -06:00
|
|
|
|
hasarg: Yes,
|
|
|
|
|
occur: Req,
|
|
|
|
|
aliases: Vec::new(),
|
|
|
|
|
};
|
|
|
|
|
short.aliases = vec!(Opt { name: Short('b'),
|
2014-02-03 21:14:40 -06:00
|
|
|
|
hasarg: Yes,
|
|
|
|
|
occur: Req,
|
2014-03-05 17:28:08 -06:00
|
|
|
|
aliases: Vec::new() });
|
2014-02-03 21:14:40 -06:00
|
|
|
|
let verbose = reqopt("b", "banana", "some bananas", "VAL");
|
2012-10-11 18:54:31 -05:00
|
|
|
|
|
2014-02-28 03:23:06 -06:00
|
|
|
|
assert!(verbose.long_to_short() == short);
|
2012-10-11 18:54:31 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2014-02-04 18:15:03 -06:00
|
|
|
|
fn test_aliases_long_and_short() {
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let opts = vec!(
|
|
|
|
|
optflagmulti("a", "apple", "Desc"));
|
2013-08-05 07:37:54 -05:00
|
|
|
|
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let args = vec!("-a".to_string(), "--apple".to_string(), "-a".to_string());
|
2013-08-05 07:37:54 -05:00
|
|
|
|
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let matches = getopts(args.as_slice(), opts.as_slice()).unwrap();
|
2013-09-17 20:42:23 -05:00
|
|
|
|
assert_eq!(3, matches.opt_count("a"));
|
|
|
|
|
assert_eq!(3, matches.opt_count("apple"));
|
2013-08-05 07:37:54 -05:00
|
|
|
|
}
|
|
|
|
|
|
2012-10-11 18:54:31 -05:00
|
|
|
|
#[test]
|
2014-02-04 18:15:03 -06:00
|
|
|
|
fn test_usage() {
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let optgroups = vec!(
|
2014-02-03 21:14:40 -06:00
|
|
|
|
reqopt("b", "banana", "Desc", "VAL"),
|
|
|
|
|
optopt("a", "012345678901234567890123456789",
|
2013-05-23 11:39:00 -05:00
|
|
|
|
"Desc", "VAL"),
|
2014-02-03 21:14:40 -06:00
|
|
|
|
optflag("k", "kiwi", "Desc"),
|
|
|
|
|
optflagopt("p", "", "Desc", "VAL"),
|
2014-03-05 17:28:08 -06:00
|
|
|
|
optmulti("l", "", "Desc", "VAL"));
|
2012-10-11 18:54:31 -05:00
|
|
|
|
|
|
|
|
|
let expected =
|
2014-05-01 00:32:13 -05:00
|
|
|
|
"Usage: fruits
|
2012-10-11 18:54:31 -05:00
|
|
|
|
|
|
|
|
|
Options:
|
|
|
|
|
-b --banana VAL Desc
|
|
|
|
|
-a --012345678901234567890123456789 VAL
|
|
|
|
|
Desc
|
|
|
|
|
-k --kiwi Desc
|
|
|
|
|
-p [VAL] Desc
|
|
|
|
|
-l VAL Desc
|
2014-05-25 05:17:19 -05:00
|
|
|
|
".to_string();
|
2012-10-11 18:54:31 -05:00
|
|
|
|
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let generated_usage = usage("Usage: fruits", optgroups.as_slice());
|
2012-10-11 18:54:31 -05:00
|
|
|
|
|
2013-10-21 15:08:31 -05:00
|
|
|
|
debug!("expected: <<{}>>", expected);
|
|
|
|
|
debug!("generated: <<{}>>", generated_usage);
|
2013-05-18 21:02:45 -05:00
|
|
|
|
assert_eq!(generated_usage, expected);
|
2012-10-11 18:54:31 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2014-02-04 18:15:03 -06:00
|
|
|
|
fn test_usage_description_wrapping() {
|
2012-10-11 18:54:31 -05:00
|
|
|
|
// indentation should be 24 spaces
|
|
|
|
|
// lines wrap after 78: or rather descriptions wrap after 54
|
|
|
|
|
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let optgroups = vec!(
|
2014-02-03 21:14:40 -06:00
|
|
|
|
optflag("k", "kiwi",
|
2013-05-23 11:39:00 -05:00
|
|
|
|
"This is a long description which won't be wrapped..+.."), // 54
|
2014-02-03 21:14:40 -06:00
|
|
|
|
optflag("a", "apple",
|
2014-03-05 17:28:08 -06:00
|
|
|
|
"This is a long description which _will_ be wrapped..+.."));
|
2012-10-11 18:54:31 -05:00
|
|
|
|
|
|
|
|
|
let expected =
|
2014-05-01 00:32:13 -05:00
|
|
|
|
"Usage: fruits
|
2012-10-11 18:54:31 -05:00
|
|
|
|
|
|
|
|
|
Options:
|
|
|
|
|
-k --kiwi This is a long description which won't be wrapped..+..
|
|
|
|
|
-a --apple This is a long description which _will_ be
|
|
|
|
|
wrapped..+..
|
2014-05-25 05:17:19 -05:00
|
|
|
|
".to_string();
|
2012-10-11 18:54:31 -05:00
|
|
|
|
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let usage = usage("Usage: fruits", optgroups.as_slice());
|
2012-10-11 18:54:31 -05:00
|
|
|
|
|
2013-10-21 15:08:31 -05:00
|
|
|
|
debug!("expected: <<{}>>", expected);
|
|
|
|
|
debug!("generated: <<{}>>", usage);
|
2013-03-28 20:39:09 -05:00
|
|
|
|
assert!(usage == expected)
|
2012-10-11 18:54:31 -05:00
|
|
|
|
}
|
2013-08-24 05:09:18 -05:00
|
|
|
|
|
|
|
|
|
#[test]
|
2014-02-04 18:15:03 -06:00
|
|
|
|
fn test_usage_description_multibyte_handling() {
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let optgroups = vec!(
|
2014-02-03 21:14:40 -06:00
|
|
|
|
optflag("k", "k\u2013w\u2013",
|
2013-08-24 05:09:18 -05:00
|
|
|
|
"The word kiwi is normally spelled with two i's"),
|
2014-02-03 21:14:40 -06:00
|
|
|
|
optflag("a", "apple",
|
2013-08-24 05:09:18 -05:00
|
|
|
|
"This \u201Cdescription\u201D has some characters that could \
|
2014-03-05 17:28:08 -06:00
|
|
|
|
confuse the line wrapping; an apple costs 0.51€ in some parts of Europe."));
|
2013-08-24 05:09:18 -05:00
|
|
|
|
|
|
|
|
|
let expected =
|
2014-05-01 00:32:13 -05:00
|
|
|
|
"Usage: fruits
|
2013-08-24 05:09:18 -05:00
|
|
|
|
|
|
|
|
|
Options:
|
|
|
|
|
-k --k–w– The word kiwi is normally spelled with two i's
|
|
|
|
|
-a --apple This “description” has some characters that could
|
|
|
|
|
confuse the line wrapping; an apple costs 0.51€ in
|
|
|
|
|
some parts of Europe.
|
2014-05-25 05:17:19 -05:00
|
|
|
|
".to_string();
|
2013-08-24 05:09:18 -05:00
|
|
|
|
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let usage = usage("Usage: fruits", optgroups.as_slice());
|
2013-08-24 05:09:18 -05:00
|
|
|
|
|
2013-10-21 15:08:31 -05:00
|
|
|
|
debug!("expected: <<{}>>", expected);
|
|
|
|
|
debug!("generated: <<{}>>", usage);
|
2013-08-24 05:09:18 -05:00
|
|
|
|
assert!(usage == expected)
|
|
|
|
|
}
|
2014-02-02 14:52:51 -06:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_short_usage() {
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let optgroups = vec!(
|
2014-02-03 21:14:40 -06:00
|
|
|
|
reqopt("b", "banana", "Desc", "VAL"),
|
|
|
|
|
optopt("a", "012345678901234567890123456789",
|
|
|
|
|
"Desc", "VAL"),
|
|
|
|
|
optflag("k", "kiwi", "Desc"),
|
|
|
|
|
optflagopt("p", "", "Desc", "VAL"),
|
2014-03-05 17:28:08 -06:00
|
|
|
|
optmulti("l", "", "Desc", "VAL"));
|
2014-02-02 14:52:51 -06:00
|
|
|
|
|
2014-05-25 05:17:19 -05:00
|
|
|
|
let expected = "Usage: fruits -b VAL [-a VAL] [-k] [-p [VAL]] [-l VAL]..".to_string();
|
2014-03-05 17:28:08 -06:00
|
|
|
|
let generated_usage = short_usage("fruits", optgroups.as_slice());
|
2014-02-02 14:52:51 -06:00
|
|
|
|
|
|
|
|
|
debug!("expected: <<{}>>", expected);
|
|
|
|
|
debug!("generated: <<{}>>", generated_usage);
|
|
|
|
|
assert_eq!(generated_usage, expected);
|
|
|
|
|
}
|
2012-01-17 21:05:07 -06:00
|
|
|
|
}
|