1use std::env;
24use std::iter;
25
26
27#[derive(Debug)]
34#[derive(PartialEq)]
35pub enum Opt {
36 Flag(String),
37 Named(String, String),
38 Ordinal(String),
39 Raw(String),
40}
41
42
43pub struct Opts<I> where I : Iterator<Item = String> {
50 iter : I,
51 flags : Vec<char>,
52 name : String,
53 drain : bool,
54 done : bool,
55}
56
57impl<I> Opts<I> where I : Iterator<Item = String> {
58 fn next_opt (&mut self) -> Option<Opt> {
59 if self.done {
61 return None;
62 }
63
64 if let Some(c) = self.flags.pop() {
66 return Some(Opt::Flag(c.to_string()));
67 }
68
69 let value;
71 match self.iter.next() {
72 Some(a) => value = a,
73 None => {
74 self.done = true;
76
77 if !self.name.is_empty() {
78 let temp = self.name.clone();
80 self.name.clear();
81 return Some(Opt::Flag(temp));
82 }
83 else {
84 return None;
86 }
87 }
88 }
89
90 if self.drain {
92 return Some(Opt::Raw(value));
93 }
94
95 if value == "--" {
97 self.drain = true;
98 return self.next_opt();
99 }
100
101 let mut name = String::new();
103 if value.starts_with("--") {
104 name.push_str(&value[2..]);
105 }
106 else if value.starts_with("-") {
107 if value.chars().count() > 2 {
108 for c in value.chars().skip(1) {
110 self.flags.push(c);
111 }
112 self.flags.reverse();
113 }
114 else {
115 name.push_str(&value[1..]);
117 }
118 }
119
120 if !self.name.is_empty() {
122 if !name.is_empty() {
124 let temp = name;
126 name = self.name.clone();
127 self.name = temp;
128 return Some(Opt::Flag(name));
129 }
130 else if !self.flags.is_empty() {
131 name = self.name.clone();
133 self.name.clear();
134 return Some(Opt::Flag(name));
135 }
136 else {
137 name = self.name.clone();
139 self.name.clear();
140 return Some(Opt::Named(name, value));
141 }
142 }
143 else if !name.is_empty() {
144 self.name = name;
146 return self.next_opt();
147 }
148 else if !self.flags.is_empty() {
149 return self.next_opt();
151 }
152
153 return Some(Opt::Ordinal(value));
155 }
156}
157
158impl<I> Iterator for Opts<I> where I : Iterator<Item = String> {
159 type Item = Opt;
160
161 fn next (&mut self) -> Option<Opt> {
162 return self.next_opt();
163 }
164}
165
166
167pub fn parse<I, II> (values : II) -> Opts<II::IntoIter> where
174 I : Iterator<Item = String>,
175 II : IntoIterator<Item = String, IntoIter = I>
176{
177 return Opts {
178 iter : values.into_iter(),
179 flags : Vec::new(),
180 name : String::new(),
181 drain : false,
182 done : false,
183 };
184}
185
186pub fn parse_env () -> Opts<iter::Skip<env::Args>> {
187 return parse(env::args().skip(1));
188}
189
190
191
192#[cfg(test)]
199mod tests {
200 use super::Opt;
201
202 fn args_from_str (s : &str) -> Vec<String> {
203 return s.split(" ").map(|s| s.to_string()).collect();
204 }
205
206 fn options_from_str (s : &str) -> Vec<Opt> {
207 return super::parse(args_from_str(s)).collect();
208 }
209
210 fn flag_from_str (name : &str) -> Opt {
211 return Opt::Flag(name.to_string());
212 }
213
214 fn named_from_str (name : &str, value : &str) -> Opt {
215 return Opt::Named(name.to_string(), value.to_string());
216 }
217
218 fn ordinal_from_str (value : &str) -> Opt {
219 return Opt::Ordinal(value.to_string());
220 }
221
222 fn raw_from_str (value : &str) -> Opt {
223 return Opt::Raw(value.to_string());
224 }
225
226 #[test]
227 fn full () {
228 let actual = options_from_str("a -bc -d e --f g - h -- i -j --k");
229 let spec = vec![
230 ordinal_from_str("a"),
231 flag_from_str("b"),
232 flag_from_str("c"),
233 named_from_str("d", "e"),
234 named_from_str("f", "g"),
235 ordinal_from_str("-"),
236 ordinal_from_str("h"),
237 raw_from_str("i"),
238 raw_from_str("-j"),
239 raw_from_str("--k"),
240 ];
241
242 assert_eq!(actual, spec);
243 }
244
245 #[test]
246 fn trailing_flag () {
247 let actual = options_from_str("a b -c");
248 let spec = vec![
249 ordinal_from_str("a"),
250 ordinal_from_str("b"),
251 flag_from_str("c"),
252 ];
253
254 assert_eq!(actual, spec);
255 }
256}