(index<- ) ./libextra/getopts.rs
1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Simple getopt alternative.
12 //!
13 //! Construct a vector of options, either by using reqopt, optopt, and optflag
14 //! or by building them from components yourself, and pass them to getopts,
15 //! along with a vector of actual arguments (not including argv[0]). You'll
16 //! either get a failure code back, or a match. You'll have to verify whether
17 //! the amount of 'free' arguments in the match is what you expect. Use opt_*
18 //! accessors to get argument values out of the matches object.
19 //!
20 //! Single-character options are expected to appear on the command line with a
21 //! single preceding dash; multiple-character options are expected to be
22 //! proceeded by two dashes. Options that expect an argument accept their
23 //! argument following either a space or an equals sign. Single-character
24 //! options don't require the space.
25 //!
26 //! # Example
27 //!
28 //! The following example shows simple command line parsing for an application
29 //! that requires an input file to be specified, accepts an optional output
30 //! file name following -o, and accepts both -h and --help as optional flags.
31 //!
32 //! ```
33 //! exter mod extra;
34 //! use extra::getopts::*;
35 //! use std::os;
36 //!
37 //! fn do_work(inp: &str, out: Option<~str>) {
38 //! println(inp);
39 //! println(match out {
40 //! Some(x) => x,
41 //! None => ~"No Output"
42 //! });
43 //! }
44 //!
45 //! fn print_usage(program: &str, _opts: &[Opt]) {
46 //! printfln!("Usage: %s [options]", program);
47 //! println("-o\t\tOutput");
48 //! println("-h --help\tUsage");
49 //! }
50 //!
51 //! fn main() {
52 //! let args = os::args();
53 //!
54 //! let program = args[0].clone();
55 //!
56 //! let opts = ~[
57 //! optopt("o"),
58 //! optflag("h"),
59 //! optflag("help")
60 //! ];
61 //! let matches = match getopts(args.tail(), opts) {
62 //! Ok(m) => { m }
63 //! Err(f) => { fail!(f.to_err_msg()) }
64 //! };
65 //! if matches.opt_present("h") || matches.opt_present("help") {
66 //! print_usage(program, opts);
67 //! return;
68 //! }
69 //! let output = matches.opt_str("o");
70 //! let input: &str = if !matches.free.is_empty() {
71 //! matches.free[0].clone()
72 //! } else {
73 //! print_usage(program, opts);
74 //! return;
75 //! };
76 //! do_work(input, output);
77 //! }
78 //! ```
79
80 use std::cmp::Eq;
81 use std::result::{Err, Ok};
82 use std::result;
83 use std::option::{Some, None};
84 use std::vec;
85
86 /// Name of an option. Either a string or a single char.
87 #[deriving(Clone, Eq)]
88 pub enum Name {
89 Long(~str),
90 Short(char),
91 }
92
93 /// Describes whether an option has an argument.
94 #[deriving(Clone, Eq)]
95 pub enum HasArg {
96 Yes,
97 No,
98 Maybe,
99 }
100
101 /// Describes how often an option may occur.
102 #[deriving(Clone, Eq)]
103 pub enum Occur {
104 Req,
105 Optional,
106 Multi,
107 }
108
109 /// A description of a possible option.
110 #[deriving(Clone, Eq)]
111 pub struct Opt {
112 /// Name of the option
113 name: Name,
114 /// Wheter it has an argument
115 hasarg: HasArg,
116 /// How often it can occur
117 occur: Occur,
118 /// Which options it aliases
119 aliases: ~[Opt],
120 }
121
122 /// Describes wether an option is given at all or has a value.
123 #[deriving(Clone, Eq)]
124 enum Optval {
125 Val(~str),
126 Given,
127 }
128
129 /// The result of checking command line arguments. Contains a vector
130 /// of matches and a vector of free strings.
131 #[deriving(Clone, Eq)]
132 pub struct Matches {
133 /// Options that matched
134 opts: ~[Opt],
135 /// Values of the Options that matched
136 vals: ~[~[Optval]],
137 /// Free string fragments
138 free: ~[~str]
139 }
140
141 /// The type returned when the command line does not conform to the
142 /// expected format. Pass this value to <fail_str> to get an error message.
143 #[deriving(Clone, Eq, ToStr)]
144 pub enum Fail_ {
145 ArgumentMissing(~str),
146 UnrecognizedOption(~str),
147 OptionMissing(~str),
148 OptionDuplicated(~str),
149 UnexpectedArgument(~str),
150 }
151
152 /// The type of failure that occured.
153 #[deriving(Eq)]
154 pub enum FailType {
155 ArgumentMissing_,
156 UnrecognizedOption_,
157 OptionMissing_,
158 OptionDuplicated_,
159 UnexpectedArgument_,
160 }
161
162 /// The result of parsing a command line with a set of options.
163 pub type Result = result::Result<Matches, Fail_>;
164
165 impl Name {
166 fn from_str(nm: &str) -> Name {
167 if nm.len() == 1u {
168 Short(nm.char_at(0u))
169 } else {
170 Long(nm.to_owned())
171 }
172 }
173
174 fn to_str(&self) -> ~str {
175 match *self {
176 Short(ch) => ch.to_str(),
177 Long(ref s) => s.to_owned()
178 }
179 }
180 }
181
182 impl Matches {
183 /// FIXME: #9311 This used to be private, but rustpkg somehow managed to depend on it.
184 /// No idea what this does.
185 pub fn opt_vals(&self, nm: &str) -> ~[Optval] {
186 match find_opt(self.opts, Name::from_str(nm)) {
187 Some(id) => self.vals[id].clone(),
188 None => fail!("No option '%s' defined", nm)
189 }
190 }
191
192 /// FIXME: #9311 This used to be private, but rustpkg somehow managed to depend on it.
193 /// No idea what this does.
194 pub fn opt_val(&self, nm: &str) -> Option<Optval> {
195 let vals = self.opt_vals(nm);
196 if (vals.is_empty()) {
197 None
198 } else {
199 Some(vals[0].clone())
200 }
201 }
202
203 /// Returns true if an option was matched.
204 pub fn opt_present(&self, nm: &str) -> bool {
205 !self.opt_vals(nm).is_empty()
206 }
207
208 /// Returns the number of times an option was matched.
209 pub fn opt_count(&self, nm: &str) -> uint {
210 self.opt_vals(nm).len()
211 }
212
213 /// Returns true if any of several options were matched.
214 pub fn opts_present(&self, names: &[~str]) -> bool {
215 for nm in names.iter() {
216 match find_opt(self.opts, Name::from_str(*nm)) {
217 Some(id) if !self.vals[id].is_empty() => return true,
218 _ => (),
219 };
220 }
221 false
222 }
223
224 /// Returns the string argument supplied to one of several matching options or `None`.
225 pub fn opts_str(&self, names: &[~str]) -> Option<~str> {
226 for nm in names.iter() {
227 match self.opt_val(*nm) {
228 Some(Val(ref s)) => return Some(s.clone()),
229 _ => ()
230 }
231 }
232 None
233 }
234
235 /// Returns a vector of the arguments provided to all matches of the given
236 /// option.
237 ///
238 /// Used when an option accepts multiple values.
239 pub fn opt_strs(&self, nm: &str) -> ~[~str] {
240 let mut acc: ~[~str] = ~[];
241 let r = self.opt_vals(nm);
242 for v in r.iter() {
243 match *v {
244 Val(ref s) => acc.push((*s).clone()),
245 _ => ()
246 }
247 }
248 acc
249 }
250
251 /// Returns the string argument supplied to a matching option or `None`.
252 pub fn opt_str(&self, nm: &str) -> Option<~str> {
253 let vals = self.opt_vals(nm);
254 if vals.is_empty() {
255 return None::<~str>;
256 }
257 match vals[0] {
258 Val(ref s) => Some((*s).clone()),
259 _ => None
260 }
261 }
262
263
264 /// Returns the matching string, a default, or none.
265 ///
266 /// Returns none if the option was not present, `def` if the option was
267 /// present but no argument was provided, and the argument if the option was
268 /// present and an argument was provided.
269 pub fn opt_default(&self, nm: &str, def: &str) -> Option<~str> {
270 let vals = self.opt_vals(nm);
271 if vals.is_empty() { return None; }
272 match vals[0] {
273 Val(ref s) => Some((*s).clone()),
274 _ => Some(def.to_owned())
275 }
276 }
277
278 }
279
280 fn is_arg(arg: &str) -> bool {
281 arg.len() > 1 && arg[0] == '-' as u8
282 }
283
284 fn find_opt(opts: &[Opt], nm: Name) -> Option<uint> {
285 // Search main options.
286 let pos = opts.iter().position(|opt| opt.name == nm);
287 if pos.is_some() {
288 return pos
289 }
290
291 // Search in aliases.
292 for candidate in opts.iter() {
293 if candidate.aliases.iter().position(|opt| opt.name == nm).is_some() {
294 return opts.iter().position(|opt| opt.name == candidate.name);
295 }
296 }
297
298 None
299 }
300
301 /// Create an option that is required and takes an argument.
302 pub fn reqopt(name: &str) -> Opt {
303 Opt {
304 name: Name::from_str(name),
305 hasarg: Yes,
306 occur: Req,
307 aliases: ~[]
308 }
309 }
310
311 /// Create an option that is optional and takes an argument.
312 pub fn optopt(name: &str) -> Opt {
313 Opt {
314 name: Name::from_str(name),
315 hasarg: Yes,
316 occur: Optional,
317 aliases: ~[]
318 }
319 }
320
321 /// Create an option that is optional and does not take an argument.
322 pub fn optflag(name: &str) -> Opt {
323 Opt {
324 name: Name::from_str(name),
325 hasarg: No,
326 occur: Optional,
327 aliases: ~[]
328 }
329 }
330
331 /// Create an option that is optional, does not take an argument,
332 /// and may occur multiple times.
333 pub fn optflagmulti(name: &str) -> Opt {
334 Opt {
335 name: Name::from_str(name),
336 hasarg: No,
337 occur: Multi,
338 aliases: ~[]
339 }
340 }
341
342 /// Create an option that is optional and takes an optional argument.
343 pub fn optflagopt(name: &str) -> Opt {
344 Opt {
345 name: Name::from_str(name),
346 hasarg: Maybe,
347 occur: Optional,
348 aliases: ~[]
349 }
350 }
351
352 /// Create an option that is optional, takes an argument, and may occur
353 /// multiple times.
354 pub fn optmulti(name: &str) -> Opt {
355 Opt {
356 name: Name::from_str(name),
357 hasarg: Yes,
358 occur: Multi,
359 aliases: ~[]
360 }
361 }
362
363 impl Fail_ {
364 /// Convert a `Fail_` enum into an error string.
365 pub fn to_err_msg(self) -> ~str {
366 match self {
367 ArgumentMissing(ref nm) => {
368 fmt!("Argument to option '%s' missing.", *nm)
369 }
370 UnrecognizedOption(ref nm) => {
371 fmt!("Unrecognized option: '%s'.", *nm)
372 }
373 OptionMissing(ref nm) => {
374 fmt!("Required option '%s' missing.", *nm)
375 }
376 OptionDuplicated(ref nm) => {
377 fmt!("Option '%s' given more than once.", *nm)
378 }
379 UnexpectedArgument(ref nm) => {
380 fmt!("Option '%s' does not take an argument.", *nm)
381 }
382 }
383 }
384 }
385
386 /// Parse command line arguments according to the provided options.
387 ///
388 /// On success returns `Ok(Opt)`. Use methods such as `opt_present`
389 /// `opt_str`, etc. to interrogate results. Returns `Err(Fail_)` on failure.
390 /// Use `to_err_msg` to get an error message.
391 pub fn getopts(args: &[~str], opts: &[Opt]) -> Result {
392 let n_opts = opts.len();
393
394 fn f(_x: uint) -> ~[Optval] { return ~[]; }
395
396 let mut vals = vec::from_fn(n_opts, f);
397 let mut free: ~[~str] = ~[];
398 let l = args.len();
399 let mut i = 0;
400 while i < l {
401 let cur = args[i].clone();
402 let curlen = cur.len();
403 if !is_arg(cur) {
404 free.push(cur);
405 } else if cur == ~"--" {
406 let mut j = i + 1;
407 while j < l { free.push(args[j].clone()); j += 1; }
408 break;
409 } else {
410 let mut names;
411 let mut i_arg = None;
412 if cur[1] == '-' as u8 {
413 let tail = cur.slice(2, curlen);
414 let tail_eq: ~[&str] = tail.split_iter('=').collect();
415 if tail_eq.len() <= 1 {
416 names = ~[Long(tail.to_owned())];
417 } else {
418 names =
419 ~[Long(tail_eq[0].to_owned())];
420 i_arg = Some(tail_eq[1].to_owned());
421 }
422 } else {
423 let mut j = 1;
424 let mut last_valid_opt_id = None;
425 names = ~[];
426 while j < curlen {
427 let range = cur.char_range_at(j);
428 let opt = Short(range.ch);
429
430 /* In a series of potential options (eg. -aheJ), if we
431 see one which takes an argument, we assume all
432 subsequent characters make up the argument. This
433 allows options such as -L/usr/local/lib/foo to be
434 interpreted correctly
435 */
436
437 match find_opt(opts, opt.clone()) {
438 Some(id) => last_valid_opt_id = Some(id),
439 None => {
440 let arg_follows =
441 last_valid_opt_id.is_some() &&
442 match opts[last_valid_opt_id.unwrap()]
443 .hasarg {
444
445 Yes | Maybe => true,
446 No => false
447 };
448 if arg_follows && j < curlen {
449 i_arg = Some(cur.slice(j, curlen).to_owned());
450 break;
451 } else {
452 last_valid_opt_id = None;
453 }
454 }
455 }
456 names.push(opt);
457 j = range.next;
458 }
459 }
460 let mut name_pos = 0;
461 for nm in names.iter() {
462 name_pos += 1;
463 let optid = match find_opt(opts, (*nm).clone()) {
464 Some(id) => id,
465 None => return Err(UnrecognizedOption(nm.to_str()))
466 };
467 match opts[optid].hasarg {
468 No => {
469 if !i_arg.is_none() {
470 return Err(UnexpectedArgument(nm.to_str()));
471 }
472 vals[optid].push(Given);
473 }
474 Maybe => {
475 if !i_arg.is_none() {
476 vals[optid].push(Val((i_arg.clone()).unwrap()));
477 } else if name_pos < names.len() ||
478 i + 1 == l || is_arg(args[i + 1]) {
479 vals[optid].push(Given);
480 } else { i += 1; vals[optid].push(Val(args[i].clone())); }
481 }
482 Yes => {
483 if !i_arg.is_none() {
484 vals[optid].push(Val(i_arg.clone().unwrap()));
485 } else if i + 1 == l {
486 return Err(ArgumentMissing(nm.to_str()));
487 } else { i += 1; vals[optid].push(Val(args[i].clone())); }
488 }
489 }
490 }
491 }
492 i += 1;
493 }
494 i = 0u;
495 while i < n_opts {
496 let n = vals[i].len();
497 let occ = opts[i].occur;
498 if occ == Req {
499 if n == 0 {
500 return Err(OptionMissing(opts[i].name.to_str()));
501 }
502 }
503 if occ != Multi {
504 if n > 1 {
505 return Err(OptionDuplicated(opts[i].name.to_str()));
506 }
507 }
508 i += 1;
509 }
510 Ok(Matches {
511 opts: opts.to_owned(),
512 vals: vals,
513 free: free
514 })
515 }
516
517 /// A module which provides a way to specify descriptions and
518 /// groups of short and long option names, together.
519 pub mod groups {
520 use getopts::{HasArg, Long, Maybe, Multi, No, Occur, Opt, Optional, Req};
521 use getopts::{Short, Yes};
522
523 /// One group of options, e.g., both -h and --help, along with
524 /// their shared description and properties.
525 #[deriving(Clone, Eq)]
526 pub struct OptGroup {
527 /// Short Name of the `OptGroup`
528 short_name: ~str,
529 /// Long Name of the `OptGroup`
530 long_name: ~str,
531 /// Hint
532 hint: ~str,
533 /// Description
534 desc: ~str,
535 /// Whether it has an argument
536 hasarg: HasArg,
537 /// How often it can occur
538 occur: Occur
539 }
540
541 impl OptGroup {
542 /// Translate OptGroup into Opt.
543 /// (Both short and long names correspond to different Opts).
544 pub fn long_to_short(&self) -> Opt {
545 let OptGroup {
546 short_name: short_name,
547 long_name: long_name,
548 hasarg: hasarg,
549 occur: occur,
550 _
551 } = (*self).clone();
552
553 match (short_name.len(), long_name.len()) {
554 (0,0) => fail!("this long-format option was given no name"),
555 (0,_) => Opt {
556 name: Long((long_name)),
557 hasarg: hasarg,
558 occur: occur,
559 aliases: ~[]
560 },
561 (1,0) => Opt {
562 name: Short(short_name.char_at(0)),
563 hasarg: hasarg,
564 occur: occur,
565 aliases: ~[]
566 },
567 (1,_) => Opt {
568 name: Long((long_name)),
569 hasarg: hasarg,
570 occur: occur,
571 aliases: ~[
572 Opt {
573 name: Short(short_name.char_at(0)),
574 hasarg: hasarg,
575 occur: occur,
576 aliases: ~[]
577 }
578 ]
579 },
580 (_,_) => fail!("something is wrong with the long-form opt")
581 }
582 }
583 }
584
585 /// Create a long option that is required and takes an argument.
586 pub fn reqopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
587 let len = short_name.len();
588 assert!(len == 1 || len == 0);
589 OptGroup {
590 short_name: short_name.to_owned(),
591 long_name: long_name.to_owned(),
592 hint: hint.to_owned(),
593 desc: desc.to_owned(),
594 hasarg: Yes,
595 occur: Req
596 }
597 }
598
599 /// Create a long option that is optional and takes an argument.
600 pub fn optopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
601 let len = short_name.len();
602 assert!(len == 1 || len == 0);
603 OptGroup {
604 short_name: short_name.to_owned(),
605 long_name: long_name.to_owned(),
606 hint: hint.to_owned(),
607 desc: desc.to_owned(),
608 hasarg: Yes,
609 occur: Optional
610 }
611 }
612
613 /// Create a long option that is optional and does not take an argument.
614 pub fn optflag(short_name: &str, long_name: &str, desc: &str) -> OptGroup {
615 let len = short_name.len();
616 assert!(len == 1 || len == 0);
617 OptGroup {
618 short_name: short_name.to_owned(),
619 long_name: long_name.to_owned(),
620 hint: ~"",
621 desc: desc.to_owned(),
622 hasarg: No,
623 occur: Optional
624 }
625 }
626
627 /// Create a long option that can occur more than once and does not
628 /// take an argument.
629 pub fn optflagmulti(short_name: &str, long_name: &str, desc: &str) -> OptGroup {
630 let len = short_name.len();
631 assert!(len == 1 || len == 0);
632 OptGroup {
633 short_name: short_name.to_owned(),
634 long_name: long_name.to_owned(),
635 hint: ~"",
636 desc: desc.to_owned(),
637 hasarg: No,
638 occur: Multi
639 }
640 }
641
642 /// Create a long option that is optional and takes an optional argument.
643 pub fn optflagopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
644 let len = short_name.len();
645 assert!(len == 1 || len == 0);
646 OptGroup {
647 short_name: short_name.to_owned(),
648 long_name: long_name.to_owned(),
649 hint: hint.to_owned(),
650 desc: desc.to_owned(),
651 hasarg: Maybe,
652 occur: Optional
653 }
654 }
655
656 /// Create a long option that is optional, takes an argument, and may occur
657 /// multiple times.
658 pub fn optmulti(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
659 let len = short_name.len();
660 assert!(len == 1 || len == 0);
661 OptGroup {
662 short_name: short_name.to_owned(),
663 long_name: long_name.to_owned(),
664 hint: hint.to_owned(),
665 desc: desc.to_owned(),
666 hasarg: Yes,
667 occur: Multi
668 }
669 }
670
671 /// Parse command line args with the provided long format options.
672 pub fn getopts(args: &[~str], opts: &[OptGroup]) -> ::getopts::Result {
673 ::getopts::getopts(args, opts.map(|x| x.long_to_short()))
674 }
675
676 /// Derive a usage message from a set of long options.
677 pub fn usage(brief: &str, opts: &[OptGroup]) -> ~str {
678
679 let desc_sep = "\n" + " ".repeat(24);
680
681 let mut rows = opts.iter().map(|optref| {
682 let OptGroup{short_name: short_name,
683 long_name: long_name,
684 hint: hint,
685 desc: desc,
686 hasarg: hasarg,
687 _} = (*optref).clone();
688
689 let mut row = " ".repeat(4);
690
691 // short option
692 match short_name.len() {
693 0 => {}
694 1 => {
695 row.push_char('-');
696 row.push_str(short_name);
697 row.push_char(' ');
698 }
699 _ => fail!("the short name should only be 1 ascii char long"),
700 }
701
702 // long option
703 match long_name.len() {
704 0 => {}
705 _ => {
706 row.push_str("--");
707 row.push_str(long_name);
708 row.push_char(' ');
709 }
710 }
711
712 // arg
713 match hasarg {
714 No => {}
715 Yes => row.push_str(hint),
716 Maybe => {
717 row.push_char('[');
718 row.push_str(hint);
719 row.push_char(']');
720 }
721 }
722
723 // FIXME: #5516 should be graphemes not codepoints
724 // here we just need to indent the start of the description
725 let rowlen = row.char_len();
726 if rowlen < 24 {
727 do (24 - rowlen).times {
728 row.push_char(' ')
729 }
730 } else {
731 row.push_str(desc_sep)
732 }
733
734 // Normalize desc to contain words separated by one space character
735 let mut desc_normalized_whitespace = ~"";
736 for word in desc.word_iter() {
737 desc_normalized_whitespace.push_str(word);
738 desc_normalized_whitespace.push_char(' ');
739 }
740
741 // FIXME: #5516 should be graphemes not codepoints
742 let mut desc_rows = ~[];
743 do each_split_within(desc_normalized_whitespace, 54) |substr| {
744 desc_rows.push(substr.to_owned());
745 true
746 };
747
748 // FIXME: #5516 should be graphemes not codepoints
749 // wrapped description
750 row.push_str(desc_rows.connect(desc_sep));
751
752 row
753 });
754
755 fmt!("%s\n\nOptions:\n%s\n", brief, rows.collect::<~[~str]>().connect("\n"))
756 }
757
758 /// Splits a string into substrings with possibly internal whitespace,
759 /// each of them at most `lim` bytes long. The substrings have leading and trailing
760 /// whitespace removed, and are only cut at whitespace boundaries.
761 ///
762 /// Note: Function was moved here from `std::str` because this module is the only place that
763 /// uses it, and because it was to specific for a general string function.
764 ///
765 /// #Failure:
766 ///
767 /// Fails during iteration if the string contains a non-whitespace
768 /// sequence longer than the limit.
769 fn each_split_within<'a>(ss: &'a str,
770 lim: uint,
771 it: &fn(&'a str) -> bool) -> bool {
772 // Just for fun, let's write this as a state machine:
773
774 enum SplitWithinState {
775 A, // leading whitespace, initial state
776 B, // words
777 C, // internal and trailing whitespace
778 }
779 enum Whitespace {
780 Ws, // current char is whitespace
781 Cr // current char is not whitespace
782 }
783 enum LengthLimit {
784 UnderLim, // current char makes current substring still fit in limit
785 OverLim // current char makes current substring no longer fit in limit
786 }
787
788 let mut slice_start = 0;
789 let mut last_start = 0;
790 let mut last_end = 0;
791 let mut state = A;
792 let mut fake_i = ss.len();
793 let mut lim = lim;
794
795 let mut cont = true;
796 let slice: &fn() = || { cont = it(ss.slice(slice_start, last_end)) };
797
798 // if the limit is larger than the string, lower it to save cycles
799 if (lim >= fake_i) {
800 lim = fake_i;
801 }
802
803 let machine: &fn((uint, char)) -> bool = |(i, c)| {
804 let whitespace = if ::std::char::is_whitespace(c) { Ws } else { Cr };
805 let limit = if (i - slice_start + 1) <= lim { UnderLim } else { OverLim };
806
807 state = match (state, whitespace, limit) {
808 (A, Ws, _) => { A }
809 (A, Cr, _) => { slice_start = i; last_start = i; B }
810
811 (B, Cr, UnderLim) => { B }
812 (B, Cr, OverLim) if (i - last_start + 1) > lim
813 => fail!("word starting with %? longer than limit!",
814 ss.slice(last_start, i + 1)),
815 (B, Cr, OverLim) => { slice(); slice_start = last_start; B }
816 (B, Ws, UnderLim) => { last_end = i; C }
817 (B, Ws, OverLim) => { last_end = i; slice(); A }
818
819 (C, Cr, UnderLim) => { last_start = i; B }
820 (C, Cr, OverLim) => { slice(); slice_start = i; last_start = i; last_end = i; B }
821 (C, Ws, OverLim) => { slice(); A }
822 (C, Ws, UnderLim) => { C }
823 };
824
825 cont
826 };
827
828 ss.char_offset_iter().advance(|x| machine(x));
829
830 // Let the automaton 'run out' by supplying trailing whitespace
831 while cont && match state { B | C => true, A => false } {
832 machine((fake_i, ' '));
833 fake_i += 1;
834 }
835 return cont;
836 }
837
838 #[test]
839 fn test_split_within() {
840 fn t(s: &str, i: uint, u: &[~str]) {
841 let mut v = ~[];
842 do each_split_within(s, i) |s| { v.push(s.to_owned()); true };
843 assert!(v.iter().zip(u.iter()).all(|(a,b)| a == b));
844 }
845 t("", 0, []);
846 t("", 15, []);
847 t("hello", 15, [~"hello"]);
848 t("\nMary had a little lamb\nLittle lamb\n", 15,
849 [~"Mary had a", ~"little lamb", ~"Little lamb"]);
850 t("\nMary had a little lamb\nLittle lamb\n", ::std::uint::max_value,
851 [~"Mary had a little lamb\nLittle lamb"]);
852 }
853 } // end groups module
854
855 #[cfg(test)]
856 mod tests {
857
858 use getopts::groups::OptGroup;
859 use getopts::*;
860
861 use std::result::{Err, Ok};
862 use std::result;
863
864 fn check_fail_type(f: Fail_, ft: FailType) {
865 match f {
866 ArgumentMissing(_) => assert!(ft == ArgumentMissing_),
867 UnrecognizedOption(_) => assert!(ft == UnrecognizedOption_),
868 OptionMissing(_) => assert!(ft == OptionMissing_),
869 OptionDuplicated(_) => assert!(ft == OptionDuplicated_),
870 UnexpectedArgument(_) => assert!(ft == UnexpectedArgument_)
871 }
872 }
873
874
875 // Tests for reqopt
876 #[test]
877 fn test_reqopt_long() {
878 let args = ~[~"--test=20"];
879 let opts = ~[reqopt("test")];
880 let rs = getopts(args, opts);
881 match rs {
882 Ok(ref m) => {
883 assert!(m.opt_present("test"));
884 assert_eq!(m.opt_str("test").unwrap(), ~"20");
885 }
886 _ => { fail!("test_reqopt_long failed"); }
887 }
888 }
889
890 #[test]
891 fn test_reqopt_long_missing() {
892 let args = ~[~"blah"];
893 let opts = ~[reqopt("test")];
894 let rs = getopts(args, opts);
895 match rs {
896 Err(f) => check_fail_type(f, OptionMissing_),
897 _ => fail!()
898 }
899 }
900
901 #[test]
902 fn test_reqopt_long_no_arg() {
903 let args = ~[~"--test"];
904 let opts = ~[reqopt("test")];
905 let rs = getopts(args, opts);
906 match rs {
907 Err(f) => check_fail_type(f, ArgumentMissing_),
908 _ => fail!()
909 }
910 }
911
912 #[test]
913 fn test_reqopt_long_multi() {
914 let args = ~[~"--test=20", ~"--test=30"];
915 let opts = ~[reqopt("test")];
916 let rs = getopts(args, opts);
917 match rs {
918 Err(f) => check_fail_type(f, OptionDuplicated_),
919 _ => fail!()
920 }
921 }
922
923 #[test]
924 fn test_reqopt_short() {
925 let args = ~[~"-t", ~"20"];
926 let opts = ~[reqopt("t")];
927 let rs = getopts(args, opts);
928 match rs {
929 Ok(ref m) => {
930 assert!(m.opt_present("t"));
931 assert_eq!(m.opt_str("t").unwrap(), ~"20");
932 }
933 _ => fail!()
934 }
935 }
936
937 #[test]
938 fn test_reqopt_short_missing() {
939 let args = ~[~"blah"];
940 let opts = ~[reqopt("t")];
941 let rs = getopts(args, opts);
942 match rs {
943 Err(f) => check_fail_type(f, OptionMissing_),
944 _ => fail!()
945 }
946 }
947
948 #[test]
949 fn test_reqopt_short_no_arg() {
950 let args = ~[~"-t"];
951 let opts = ~[reqopt("t")];
952 let rs = getopts(args, opts);
953 match rs {
954 Err(f) => check_fail_type(f, ArgumentMissing_),
955 _ => fail!()
956 }
957 }
958
959 #[test]
960 fn test_reqopt_short_multi() {
961 let args = ~[~"-t", ~"20", ~"-t", ~"30"];
962 let opts = ~[reqopt("t")];
963 let rs = getopts(args, opts);
964 match rs {
965 Err(f) => check_fail_type(f, OptionDuplicated_),
966 _ => fail!()
967 }
968 }
969
970
971 // Tests for optopt
972 #[test]
973 fn test_optopt_long() {
974 let args = ~[~"--test=20"];
975 let opts = ~[optopt("test")];
976 let rs = getopts(args, opts);
977 match rs {
978 Ok(ref m) => {
979 assert!(m.opt_present("test"));
980 assert_eq!(m.opt_str("test").unwrap(), ~"20");
981 }
982 _ => fail!()
983 }
984 }
985
986 #[test]
987 fn test_optopt_long_missing() {
988 let args = ~[~"blah"];
989 let opts = ~[optopt("test")];
990 let rs = getopts(args, opts);
991 match rs {
992 Ok(ref m) => assert!(!m.opt_present("test")),
993 _ => fail!()
994 }
995 }
996
997 #[test]
998 fn test_optopt_long_no_arg() {
999 let args = ~[~"--test"];
1000 let opts = ~[optopt("test")];
1001 let rs = getopts(args, opts);
1002 match rs {
1003 Err(f) => check_fail_type(f, ArgumentMissing_),
1004 _ => fail!()
1005 }
1006 }
1007
1008 #[test]
1009 fn test_optopt_long_multi() {
1010 let args = ~[~"--test=20", ~"--test=30"];
1011 let opts = ~[optopt("test")];
1012 let rs = getopts(args, opts);
1013 match rs {
1014 Err(f) => check_fail_type(f, OptionDuplicated_),
1015 _ => fail!()
1016 }
1017 }
1018
1019 #[test]
1020 fn test_optopt_short() {
1021 let args = ~[~"-t", ~"20"];
1022 let opts = ~[optopt("t")];
1023 let rs = getopts(args, opts);
1024 match rs {
1025 Ok(ref m) => {
1026 assert!((m.opt_present("t")));
1027 assert_eq!(m.opt_str("t").unwrap(), ~"20");
1028 }
1029 _ => fail!()
1030 }
1031 }
1032
1033 #[test]
1034 fn test_optopt_short_missing() {
1035 let args = ~[~"blah"];
1036 let opts = ~[optopt("t")];
1037 let rs = getopts(args, opts);
1038 match rs {
1039 Ok(ref m) => assert!(!m.opt_present("t")),
1040 _ => fail!()
1041 }
1042 }
1043
1044 #[test]
1045 fn test_optopt_short_no_arg() {
1046 let args = ~[~"-t"];
1047 let opts = ~[optopt("t")];
1048 let rs = getopts(args, opts);
1049 match rs {
1050 Err(f) => check_fail_type(f, ArgumentMissing_),
1051 _ => fail!()
1052 }
1053 }
1054
1055 #[test]
1056 fn test_optopt_short_multi() {
1057 let args = ~[~"-t", ~"20", ~"-t", ~"30"];
1058 let opts = ~[optopt("t")];
1059 let rs = getopts(args, opts);
1060 match rs {
1061 Err(f) => check_fail_type(f, OptionDuplicated_),
1062 _ => fail!()
1063 }
1064 }
1065
1066
1067 // Tests for optflag
1068 #[test]
1069 fn test_optflag_long() {
1070 let args = ~[~"--test"];
1071 let opts = ~[optflag("test")];
1072 let rs = getopts(args, opts);
1073 match rs {
1074 Ok(ref m) => assert!(m.opt_present("test")),
1075 _ => fail!()
1076 }
1077 }
1078
1079 #[test]
1080 fn test_optflag_long_missing() {
1081 let args = ~[~"blah"];
1082 let opts = ~[optflag("test")];
1083 let rs = getopts(args, opts);
1084 match rs {
1085 Ok(ref m) => assert!(!m.opt_present("test")),
1086 _ => fail!()
1087 }
1088 }
1089
1090 #[test]
1091 fn test_optflag_long_arg() {
1092 let args = ~[~"--test=20"];
1093 let opts = ~[optflag("test")];
1094 let rs = getopts(args, opts);
1095 match rs {
1096 Err(f) => {
1097 error!(f.clone().to_err_msg());
1098 check_fail_type(f, UnexpectedArgument_);
1099 }
1100 _ => fail!()
1101 }
1102 }
1103
1104 #[test]
1105 fn test_optflag_long_multi() {
1106 let args = ~[~"--test", ~"--test"];
1107 let opts = ~[optflag("test")];
1108 let rs = getopts(args, opts);
1109 match rs {
1110 Err(f) => check_fail_type(f, OptionDuplicated_),
1111 _ => fail!()
1112 }
1113 }
1114
1115 #[test]
1116 fn test_optflag_short() {
1117 let args = ~[~"-t"];
1118 let opts = ~[optflag("t")];
1119 let rs = getopts(args, opts);
1120 match rs {
1121 Ok(ref m) => assert!(m.opt_present("t")),
1122 _ => fail!()
1123 }
1124 }
1125
1126 #[test]
1127 fn test_optflag_short_missing() {
1128 let args = ~[~"blah"];
1129 let opts = ~[optflag("t")];
1130 let rs = getopts(args, opts);
1131 match rs {
1132 Ok(ref m) => assert!(!m.opt_present("t")),
1133 _ => fail!()
1134 }
1135 }
1136
1137 #[test]
1138 fn test_optflag_short_arg() {
1139 let args = ~[~"-t", ~"20"];
1140 let opts = ~[optflag("t")];
1141 let rs = getopts(args, opts);
1142 match rs {
1143 Ok(ref m) => {
1144 // The next variable after the flag is just a free argument
1145
1146 assert!(m.free[0] == ~"20");
1147 }
1148 _ => fail!()
1149 }
1150 }
1151
1152 #[test]
1153 fn test_optflag_short_multi() {
1154 let args = ~[~"-t", ~"-t"];
1155 let opts = ~[optflag("t")];
1156 let rs = getopts(args, opts);
1157 match rs {
1158 Err(f) => check_fail_type(f, OptionDuplicated_),
1159 _ => fail!()
1160 }
1161 }
1162
1163 // Tests for optflagmulti
1164 #[test]
1165 fn test_optflagmulti_short1() {
1166 let args = ~[~"-v"];
1167 let opts = ~[optflagmulti("v")];
1168 let rs = getopts(args, opts);
1169 match rs {
1170 Ok(ref m) => {
1171 assert_eq!(m.opt_count("v"), 1);
1172 }
1173 _ => fail!()
1174 }
1175 }
1176
1177 #[test]
1178 fn test_optflagmulti_short2a() {
1179 let args = ~[~"-v", ~"-v"];
1180 let opts = ~[optflagmulti("v")];
1181 let rs = getopts(args, opts);
1182 match rs {
1183 Ok(ref m) => {
1184 assert_eq!(m.opt_count("v"), 2);
1185 }
1186 _ => fail!()
1187 }
1188 }
1189
1190 #[test]
1191 fn test_optflagmulti_short2b() {
1192 let args = ~[~"-vv"];
1193 let opts = ~[optflagmulti("v")];
1194 let rs = getopts(args, opts);
1195 match rs {
1196 Ok(ref m) => {
1197 assert_eq!(m.opt_count("v"), 2);
1198 }
1199 _ => fail!()
1200 }
1201 }
1202
1203 #[test]
1204 fn test_optflagmulti_long1() {
1205 let args = ~[~"--verbose"];
1206 let opts = ~[optflagmulti("verbose")];
1207 let rs = getopts(args, opts);
1208 match rs {
1209 Ok(ref m) => {
1210 assert_eq!(m.opt_count("verbose"), 1);
1211 }
1212 _ => fail!()
1213 }
1214 }
1215
1216 #[test]
1217 fn test_optflagmulti_long2() {
1218 let args = ~[~"--verbose", ~"--verbose"];
1219 let opts = ~[optflagmulti("verbose")];
1220 let rs = getopts(args, opts);
1221 match rs {
1222 Ok(ref m) => {
1223 assert_eq!(m.opt_count("verbose"), 2);
1224 }
1225 _ => fail!()
1226 }
1227 }
1228
1229 // Tests for optmulti
1230 #[test]
1231 fn test_optmulti_long() {
1232 let args = ~[~"--test=20"];
1233 let opts = ~[optmulti("test")];
1234 let rs = getopts(args, opts);
1235 match rs {
1236 Ok(ref m) => {
1237 assert!((m.opt_present("test")));
1238 assert_eq!(m.opt_str("test").unwrap(), ~"20");
1239 }
1240 _ => fail!()
1241 }
1242 }
1243
1244 #[test]
1245 fn test_optmulti_long_missing() {
1246 let args = ~[~"blah"];
1247 let opts = ~[optmulti("test")];
1248 let rs = getopts(args, opts);
1249 match rs {
1250 Ok(ref m) => assert!(!m.opt_present("test")),
1251 _ => fail!()
1252 }
1253 }
1254
1255 #[test]
1256 fn test_optmulti_long_no_arg() {
1257 let args = ~[~"--test"];
1258 let opts = ~[optmulti("test")];
1259 let rs = getopts(args, opts);
1260 match rs {
1261 Err(f) => check_fail_type(f, ArgumentMissing_),
1262 _ => fail!()
1263 }
1264 }
1265
1266 #[test]
1267 fn test_optmulti_long_multi() {
1268 let args = ~[~"--test=20", ~"--test=30"];
1269 let opts = ~[optmulti("test")];
1270 let rs = getopts(args, opts);
1271 match rs {
1272 Ok(ref m) => {
1273 assert!(m.opt_present("test"));
1274 assert_eq!(m.opt_str("test").unwrap(), ~"20");
1275 let pair = m.opt_strs("test");
1276 assert!(pair[0] == ~"20");
1277 assert!(pair[1] == ~"30");
1278 }
1279 _ => fail!()
1280 }
1281 }
1282
1283 #[test]
1284 fn test_optmulti_short() {
1285 let args = ~[~"-t", ~"20"];
1286 let opts = ~[optmulti("t")];
1287 let rs = getopts(args, opts);
1288 match rs {
1289 Ok(ref m) => {
1290 assert!((m.opt_present("t")));
1291 assert_eq!(m.opt_str("t").unwrap(), ~"20");
1292 }
1293 _ => fail!()
1294 }
1295 }
1296
1297 #[test]
1298 fn test_optmulti_short_missing() {
1299 let args = ~[~"blah"];
1300 let opts = ~[optmulti("t")];
1301 let rs = getopts(args, opts);
1302 match rs {
1303 Ok(ref m) => assert!(!m.opt_present("t")),
1304 _ => fail!()
1305 }
1306 }
1307
1308 #[test]
1309 fn test_optmulti_short_no_arg() {
1310 let args = ~[~"-t"];
1311 let opts = ~[optmulti("t")];
1312 let rs = getopts(args, opts);
1313 match rs {
1314 Err(f) => check_fail_type(f, ArgumentMissing_),
1315 _ => fail!()
1316 }
1317 }
1318
1319 #[test]
1320 fn test_optmulti_short_multi() {
1321 let args = ~[~"-t", ~"20", ~"-t", ~"30"];
1322 let opts = ~[optmulti("t")];
1323 let rs = getopts(args, opts);
1324 match rs {
1325 Ok(ref m) => {
1326 assert!((m.opt_present("t")));
1327 assert_eq!(m.opt_str("t").unwrap(), ~"20");
1328 let pair = m.opt_strs("t");
1329 assert!(pair[0] == ~"20");
1330 assert!(pair[1] == ~"30");
1331 }
1332 _ => fail!()
1333 }
1334 }
1335
1336 #[test]
1337 fn test_unrecognized_option_long() {
1338 let args = ~[~"--untest"];
1339 let opts = ~[optmulti("t")];
1340 let rs = getopts(args, opts);
1341 match rs {
1342 Err(f) => check_fail_type(f, UnrecognizedOption_),
1343 _ => fail!()
1344 }
1345 }
1346
1347 #[test]
1348 fn test_unrecognized_option_short() {
1349 let args = ~[~"-t"];
1350 let opts = ~[optmulti("test")];
1351 let rs = getopts(args, opts);
1352 match rs {
1353 Err(f) => check_fail_type(f, UnrecognizedOption_),
1354 _ => fail!()
1355 }
1356 }
1357
1358 #[test]
1359 fn test_combined() {
1360 let args =
1361 ~[~"prog", ~"free1", ~"-s", ~"20", ~"free2",
1362 ~"--flag", ~"--long=30", ~"-f", ~"-m", ~"40",
1363 ~"-m", ~"50", ~"-n", ~"-A B", ~"-n", ~"-60 70"];
1364 let opts =
1365 ~[optopt("s"), optflag("flag"), reqopt("long"),
1366 optflag("f"), optmulti("m"), optmulti("n"),
1367 optopt("notpresent")];
1368 let rs = getopts(args, opts);
1369 match rs {
1370 Ok(ref m) => {
1371 assert!(m.free[0] == ~"prog");
1372 assert!(m.free[1] == ~"free1");
1373 assert_eq!(m.opt_str("s").unwrap(), ~"20");
1374 assert!(m.free[2] == ~"free2");
1375 assert!((m.opt_present("flag")));
1376 assert_eq!(m.opt_str("long").unwrap(), ~"30");
1377 assert!((m.opt_present("f")));
1378 let pair = m.opt_strs("m");
1379 assert!(pair[0] == ~"40");
1380 assert!(pair[1] == ~"50");
1381 let pair = m.opt_strs("n");
1382 assert!(pair[0] == ~"-A B");
1383 assert!(pair[1] == ~"-60 70");
1384 assert!((!m.opt_present("notpresent")));
1385 }
1386 _ => fail!()
1387 }
1388 }
1389
1390 #[test]
1391 fn test_multi() {
1392 let opts = ~[optopt("e"), optopt("encrypt"), optopt("f")];
1393
1394 let args_single = ~[~"-e", ~"foo"];
1395 let matches_single = &match getopts(args_single, opts) {
1396 result::Ok(m) => m,
1397 result::Err(_) => fail!()
1398 };
1399 assert!(matches_single.opts_present([~"e"]));
1400 assert!(matches_single.opts_present([~"encrypt", ~"e"]));
1401 assert!(matches_single.opts_present([~"e", ~"encrypt"]));
1402 assert!(!matches_single.opts_present([~"encrypt"]));
1403 assert!(!matches_single.opts_present([~"thing"]));
1404 assert!(!matches_single.opts_present([]));
1405
1406 assert_eq!(matches_single.opts_str([~"e"]).unwrap(), ~"foo");
1407 assert_eq!(matches_single.opts_str([~"e", ~"encrypt"]).unwrap(), ~"foo");
1408 assert_eq!(matches_single.opts_str([~"encrypt", ~"e"]).unwrap(), ~"foo");
1409
1410 let args_both = ~[~"-e", ~"foo", ~"--encrypt", ~"foo"];
1411 let matches_both = &match getopts(args_both, opts) {
1412 result::Ok(m) => m,
1413 result::Err(_) => fail!()
1414 };
1415 assert!(matches_both.opts_present([~"e"]));
1416 assert!(matches_both.opts_present([~"encrypt"]));
1417 assert!(matches_both.opts_present([~"encrypt", ~"e"]));
1418 assert!(matches_both.opts_present([~"e", ~"encrypt"]));
1419 assert!(!matches_both.opts_present([~"f"]));
1420 assert!(!matches_both.opts_present([~"thing"]));
1421 assert!(!matches_both.opts_present([]));
1422
1423 assert_eq!(matches_both.opts_str([~"e"]).unwrap(), ~"foo");
1424 assert_eq!(matches_both.opts_str([~"encrypt"]).unwrap(), ~"foo");
1425 assert_eq!(matches_both.opts_str([~"e", ~"encrypt"]).unwrap(), ~"foo");
1426 assert_eq!(matches_both.opts_str([~"encrypt", ~"e"]).unwrap(), ~"foo");
1427 }
1428
1429 #[test]
1430 fn test_nospace() {
1431 let args = ~[~"-Lfoo", ~"-M."];
1432 let opts = ~[optmulti("L"), optmulti("M")];
1433 let matches = &match getopts(args, opts) {
1434 result::Ok(m) => m,
1435 result::Err(_) => fail!()
1436 };
1437 assert!(matches.opts_present([~"L"]));
1438 assert_eq!(matches.opts_str([~"L"]).unwrap(), ~"foo");
1439 assert!(matches.opts_present([~"M"]));
1440 assert_eq!(matches.opts_str([~"M"]).unwrap(), ~".");
1441
1442 }
1443
1444 #[test]
1445 fn test_groups_reqopt() {
1446 let opt = groups::reqopt("b", "banana", "some bananas", "VAL");
1447 assert!(opt == OptGroup { short_name: ~"b",
1448 long_name: ~"banana",
1449 hint: ~"VAL",
1450 desc: ~"some bananas",
1451 hasarg: Yes,
1452 occur: Req })
1453 }
1454
1455 #[test]
1456 fn test_groups_optopt() {
1457 let opt = groups::optopt("a", "apple", "some apples", "VAL");
1458 assert!(opt == OptGroup { short_name: ~"a",
1459 long_name: ~"apple",
1460 hint: ~"VAL",
1461 desc: ~"some apples",
1462 hasarg: Yes,
1463 occur: Optional })
1464 }
1465
1466 #[test]
1467 fn test_groups_optflag() {
1468 let opt = groups::optflag("k", "kiwi", "some kiwis");
1469 assert!(opt == OptGroup { short_name: ~"k",
1470 long_name: ~"kiwi",
1471 hint: ~"",
1472 desc: ~"some kiwis",
1473 hasarg: No,
1474 occur: Optional })
1475 }
1476
1477 #[test]
1478 fn test_groups_optflagopt() {
1479 let opt = groups::optflagopt("p", "pineapple", "some pineapples", "VAL");
1480 assert!(opt == OptGroup { short_name: ~"p",
1481 long_name: ~"pineapple",
1482 hint: ~"VAL",
1483 desc: ~"some pineapples",
1484 hasarg: Maybe,
1485 occur: Optional })
1486 }
1487
1488 #[test]
1489 fn test_groups_optmulti() {
1490 let opt = groups::optmulti("l", "lime", "some limes", "VAL");
1491 assert!(opt == OptGroup { short_name: ~"l",
1492 long_name: ~"lime",
1493 hint: ~"VAL",
1494 desc: ~"some limes",
1495 hasarg: Yes,
1496 occur: Multi })
1497 }
1498
1499 #[test]
1500 fn test_groups_long_to_short() {
1501 let mut short = reqopt("banana");
1502 short.aliases = ~[reqopt("b")];
1503 let verbose = groups::reqopt("b", "banana", "some bananas", "VAL");
1504
1505 assert_eq!(verbose.long_to_short(), short);
1506 }
1507
1508 #[test]
1509 fn test_groups_getopts() {
1510 let mut banana = reqopt("banana");
1511 banana.aliases = ~[reqopt("b")];
1512 let mut apple = optopt("apple");
1513 apple.aliases = ~[optopt("a")];
1514 let mut kiwi = optflag("kiwi");
1515 kiwi.aliases = ~[optflag("k")];
1516 let short = ~[
1517 banana,
1518 apple,
1519 kiwi,
1520 optflagopt("p"),
1521 optmulti("l")
1522 ];
1523
1524 let verbose = ~[
1525 groups::reqopt("b", "banana", "Desc", "VAL"),
1526 groups::optopt("a", "apple", "Desc", "VAL"),
1527 groups::optflag("k", "kiwi", "Desc"),
1528 groups::optflagopt("p", "", "Desc", "VAL"),
1529 groups::optmulti("l", "", "Desc", "VAL"),
1530 ];
1531
1532 let sample_args = ~[~"--kiwi", ~"15", ~"--apple", ~"1", ~"k",
1533 ~"-p", ~"16", ~"l", ~"35"];
1534
1535 // FIXME #4681: sort options here?
1536 assert!(getopts(sample_args, short)
1537 == groups::getopts(sample_args, verbose));
1538 }
1539
1540 #[test]
1541 fn test_groups_aliases_long_and_short() {
1542 let opts = ~[
1543 groups::optflagmulti("a", "apple", "Desc"),
1544 ];
1545
1546 let args = ~[~"-a", ~"--apple", ~"-a"];
1547
1548 let matches = groups::getopts(args, opts).unwrap();
1549 assert_eq!(3, matches.opt_count("a"));
1550 assert_eq!(3, matches.opt_count("apple"));
1551 }
1552
1553 #[test]
1554 fn test_groups_usage() {
1555 let optgroups = ~[
1556 groups::reqopt("b", "banana", "Desc", "VAL"),
1557 groups::optopt("a", "012345678901234567890123456789",
1558 "Desc", "VAL"),
1559 groups::optflag("k", "kiwi", "Desc"),
1560 groups::optflagopt("p", "", "Desc", "VAL"),
1561 groups::optmulti("l", "", "Desc", "VAL"),
1562 ];
1563
1564 let expected =
1565 ~"Usage: fruits
1566
1567 Options:
1568 -b --banana VAL Desc
1569 -a --012345678901234567890123456789 VAL
1570 Desc
1571 -k --kiwi Desc
1572 -p [VAL] Desc
1573 -l VAL Desc
1574 ";
1575
1576 let generated_usage = groups::usage("Usage: fruits", optgroups);
1577
1578 debug!("expected: <<%s>>", expected);
1579 debug!("generated: <<%s>>", generated_usage);
1580 assert_eq!(generated_usage, expected);
1581 }
1582
1583 #[test]
1584 fn test_groups_usage_description_wrapping() {
1585 // indentation should be 24 spaces
1586 // lines wrap after 78: or rather descriptions wrap after 54
1587
1588 let optgroups = ~[
1589 groups::optflag("k", "kiwi",
1590 "This is a long description which won't be wrapped..+.."), // 54
1591 groups::optflag("a", "apple",
1592 "This is a long description which _will_ be wrapped..+.."), // 55
1593 ];
1594
1595 let expected =
1596 ~"Usage: fruits
1597
1598 Options:
1599 -k --kiwi This is a long description which won't be wrapped..+..
1600 -a --apple This is a long description which _will_ be
1601 wrapped..+..
1602 ";
1603
1604 let usage = groups::usage("Usage: fruits", optgroups);
1605
1606 debug!("expected: <<%s>>", expected);
1607 debug!("generated: <<%s>>", usage);
1608 assert!(usage == expected)
1609 }
1610
1611 #[test]
1612 fn test_groups_usage_description_multibyte_handling() {
1613 let optgroups = ~[
1614 groups::optflag("k", "k\u2013w\u2013",
1615 "The word kiwi is normally spelled with two i's"),
1616 groups::optflag("a", "apple",
1617 "This \u201Cdescription\u201D has some characters that could \
1618 confuse the line wrapping; an apple costs 0.51⬠in some parts of Europe."),
1619 ];
1620
1621 let expected =
1622 ~"Usage: fruits
1623
1624 Options:
1625 -k --kâwâ The word kiwi is normally spelled with two i's
1626 -a --apple This âdescriptionâ has some characters that could
1627 confuse the line wrapping; an apple costs 0.51⬠in
1628 some parts of Europe.
1629 ";
1630
1631 let usage = groups::usage("Usage: fruits", optgroups);
1632
1633 debug!("expected: <<%s>>", expected);
1634 debug!("generated: <<%s>>", usage);
1635 assert!(usage == expected)
1636 }
1637 }
libextra/getopts.rs:153:16-153:16 -enum- definition:
#[deriving(Eq)]
pub enum FailType {
references:-153: #[deriving(Eq)]
153: #[deriving(Eq)]
153: #[deriving(Eq)]
libextra/getopts.rs:131:23-131:23 -struct- definition:
#[deriving(Clone, Eq)]
pub struct Matches {
references:-131: #[deriving(Clone, Eq)]
131: #[deriving(Clone, Eq)]
510: Ok(Matches {
131: #[deriving(Clone, Eq)]
131: #[deriving(Clone, Eq)]
131: #[deriving(Clone, Eq)]
131: #[deriving(Clone, Eq)]
131: #[deriving(Clone, Eq)]
131: #[deriving(Clone, Eq)]
163: pub type Result = result::Result<Matches, Fail_>;
131: #[deriving(Clone, Eq)]
182: impl Matches {
131: #[deriving(Clone, Eq)]
131: #[deriving(Clone, Eq)]
libextra/getopts.rs:672:4-672:4 -fn- definition:
pub fn getopts(args: &[~str], opts: &[OptGroup]) -> ::getopts::Result {
::getopts::getopts(args, opts.map(|x| x.long_to_short()))
references:-libextra/test.rs:
227: match groups::getopts(args_, optgroups()) {
libextra/getopts.rs:143:30-143:30 -enum- definition:
#[deriving(Clone, Eq, ToStr)]
pub enum Fail_ {
references:-163: pub type Result = result::Result<Matches, Fail_>;
143: #[deriving(Clone, Eq, ToStr)]
363: impl Fail_ {
143: #[deriving(Clone, Eq, ToStr)]
143: #[deriving(Clone, Eq, ToStr)]
143: #[deriving(Clone, Eq, ToStr)]
143: #[deriving(Clone, Eq, ToStr)]
143: #[deriving(Clone, Eq, ToStr)]
libextra/getopts.rs:283:1-283:1 -fn- definition:
fn find_opt(opts: &[Opt], nm: Name) -> Option<uint> {
references:-463: let optid = match find_opt(opts, (*nm).clone()) {
216: match find_opt(self.opts, Name::from_str(*nm)) {
186: match find_opt(self.opts, Name::from_str(nm)) {
437: match find_opt(opts, opt.clone()) {
libextra/getopts.rs:279:1-279:1 -fn- definition:
fn is_arg(arg: &str) -> bool {
references:-478: i + 1 == l || is_arg(args[i + 1]) {
403: if !is_arg(cur) {
libextra/getopts.rs:102:23-102:23 -enum- definition:
#[deriving(Clone, Eq)]
pub enum Occur {
references:-102: #[deriving(Clone, Eq)]
102: #[deriving(Clone, Eq)]
538: occur: Occur
102: #[deriving(Clone, Eq)]
102: #[deriving(Clone, Eq)]
117: occur: Occur,
102: #[deriving(Clone, Eq)]
libextra/getopts.rs:390:46-390:46 -fn- definition:
/// Use `to_err_msg` to get an error message.
pub fn getopts(args: &[~str], opts: &[Opt]) -> Result {
references:-673: ::getopts::getopts(args, opts.map(|x| x.long_to_short()))
libextra/getopts.rs:677:4-677:4 -fn- definition:
pub fn usage(brief: &str, opts: &[OptGroup]) -> ~str {
references:-libextra/test.rs:
196: println(groups::usage(message, optgroups()));
libextra/getopts.rs:94:23-94:23 -enum- definition:
#[deriving(Clone, Eq)]
pub enum HasArg {
references:-94: #[deriving(Clone, Eq)]
94: #[deriving(Clone, Eq)]
115: hasarg: HasArg,
94: #[deriving(Clone, Eq)]
94: #[deriving(Clone, Eq)]
94: #[deriving(Clone, Eq)]
536: hasarg: HasArg,
libextra/getopts.rs:394:4-394:4 -fn- definition:
fn f(_x: uint) -> ~[Optval] { return ~[]; }
references:-396: let mut vals = vec::from_fn(n_opts, f);
libextra/getopts.rs:526:4-526:4 -struct- definition:
pub struct OptGroup {
/// Short Name of the `OptGroup`
references:-646: OptGroup {
682: let OptGroup{short_name: short_name,
525: #[deriving(Clone, Eq)]
658: pub fn optmulti(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
661: OptGroup {
525: #[deriving(Clone, Eq)]
525: #[deriving(Clone, Eq)]
614: pub fn optflag(short_name: &str, long_name: &str, desc: &str) -> OptGroup {
545: let OptGroup {
525: #[deriving(Clone, Eq)]
525: #[deriving(Clone, Eq)]
672: pub fn getopts(args: &[~str], opts: &[OptGroup]) -> ::getopts::Result {
617: OptGroup {
525: #[deriving(Clone, Eq)]
525: #[deriving(Clone, Eq)]
586: pub fn reqopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
600: pub fn optopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
643: pub fn optflagopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
525: #[deriving(Clone, Eq)]
525: #[deriving(Clone, Eq)]
603: OptGroup {
629: pub fn optflagmulti(short_name: &str, long_name: &str, desc: &str) -> OptGroup {
677: pub fn usage(brief: &str, opts: &[OptGroup]) -> ~str {
541: impl OptGroup {
589: OptGroup {
525: #[deriving(Clone, Eq)]
632: OptGroup {
525: #[deriving(Clone, Eq)]
libextra/test.rs:
172: fn optgroups() -> ~[getopts::groups::OptGroup] {
libextra/getopts.rs:162:64-162:64 -ty- definition:
/// The result of parsing a command line with a set of options.
pub type Result = result::Result<Matches, Fail_>;
references:-391: pub fn getopts(args: &[~str], opts: &[Opt]) -> Result {
672: pub fn getopts(args: &[~str], opts: &[OptGroup]) -> ::getopts::Result {
libextra/getopts.rs:110:23-110:23 -struct- definition:
#[deriving(Clone, Eq)]
pub struct Opt {
references:-323: Opt {
110: #[deriving(Clone, Eq)]
355: Opt {
110: #[deriving(Clone, Eq)]
312: pub fn optopt(name: &str) -> Opt {
313: Opt {
344: Opt {
119: aliases: ~[Opt],
110: #[deriving(Clone, Eq)]
561: (1,0) => Opt {
110: #[deriving(Clone, Eq)]
322: pub fn optflag(name: &str) -> Opt {
391: pub fn getopts(args: &[~str], opts: &[Opt]) -> Result {
110: #[deriving(Clone, Eq)]
343: pub fn optflagopt(name: &str) -> Opt {
354: pub fn optmulti(name: &str) -> Opt {
333: pub fn optflagmulti(name: &str) -> Opt {
110: #[deriving(Clone, Eq)]
134: opts: ~[Opt],
110: #[deriving(Clone, Eq)]
544: pub fn long_to_short(&self) -> Opt {
110: #[deriving(Clone, Eq)]
572: Opt {
302: pub fn reqopt(name: &str) -> Opt {
284: fn find_opt(opts: &[Opt], nm: Name) -> Option<uint> {
334: Opt {
110: #[deriving(Clone, Eq)]
555: (0,_) => Opt {
110: #[deriving(Clone, Eq)]
303: Opt {
(567)(110)libextra/getopts.rs:600:4-600:4 -fn- definition:
pub fn optopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
let len = short_name.len();
references:-libextra/test.rs:
183: groups::optopt("", "ratchet-noise-percent",
188: groups::optopt("", "test-shard", "run shard A, of B shards, worth of the testsuite",
186: groups::optopt("", "logfile", "Write logs to the specified file instead \
177: groups::optopt("", "save-metrics", "Location to save bench metrics",
179: groups::optopt("", "ratchet-metrics",
libextra/getopts.rs:614:4-614:4 -fn- definition:
pub fn optflag(short_name: &str, long_name: &str, desc: &str) -> OptGroup {
let len = short_name.len();
references:-libextra/test.rs:
173: ~[groups::optflag("", "ignored", "Run ignored tests"),
175: groups::optflag("", "bench", "Run benchmarks instead of tests"),
174: groups::optflag("", "test", "Run tests and not benchmarks"),
176: groups::optflag("h", "help", "Display this message (longer with --help)"),
libextra/getopts.rs:769:4-769:4 -fn- definition:
fn each_split_within<'a>(ss: &'a str,
lim: uint,
references:-743: do each_split_within(desc_normalized_whitespace, 54) |substr| {
libextra/getopts.rs:123:23-123:23 -enum- definition:
#[deriving(Clone, Eq)]
enum Optval {
references:-123: #[deriving(Clone, Eq)]
136: vals: ~[~[Optval]],
123: #[deriving(Clone, Eq)]
394: fn f(_x: uint) -> ~[Optval] { return ~[]; }
123: #[deriving(Clone, Eq)]
185: pub fn opt_vals(&self, nm: &str) -> ~[Optval] {
123: #[deriving(Clone, Eq)]
123: #[deriving(Clone, Eq)]
194: pub fn opt_val(&self, nm: &str) -> Option<Optval> {
libextra/getopts.rs:87:23-87:23 -enum- definition:
#[deriving(Clone, Eq)]
pub enum Name {
references:-113: name: Name,
87: #[deriving(Clone, Eq)]
87: #[deriving(Clone, Eq)]
87: #[deriving(Clone, Eq)]
87: #[deriving(Clone, Eq)]
166: fn from_str(nm: &str) -> Name {
165: impl Name {
87: #[deriving(Clone, Eq)]
284: fn find_opt(opts: &[Opt], nm: Name) -> Option<uint> {