1#![cfg_attr(not(feature = "std"), no_std)]
2#![doc = include_str!("../README.md")]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4
5pub use getopts;
6use getopts::{HasArg, Occur};
7
8pub trait GetOptsExt {
10 fn optflagreqopt(
11 &mut self,
12 short_name: &str,
13 long_name: &str,
14 desc: &str,
15 hint: &str,
16 ) -> &mut Self;
17 fn optflagmultiopt(
18 &mut self,
19 short_name: &str,
20 long_name: &str,
21 desc: &str,
22 hint: &str,
23 ) -> &mut Self;
24}
25impl GetOptsExt for getopts::Options {
26 fn optflagreqopt(
27 &mut self,
28 short_name: &str,
29 long_name: &str,
30 desc: &str,
31 hint: &str,
32 ) -> &mut Self {
33 self.opt(short_name, long_name, desc, hint, HasArg::Maybe, Occur::Req)
34 }
35
36 fn optflagmultiopt(
37 &mut self,
38 short_name: &str,
39 long_name: &str,
40 desc: &str,
41 hint: &str,
42 ) -> &mut Self {
43 self.opt(short_name, long_name, desc, hint, HasArg::Maybe, Occur::Multi)
44 }
45}
46
47#[macro_export]
92macro_rules! getopts_options {
93 (-$($t:tt)*) => {{
94 let mut options = $crate::getopts::Options::new();
95 $crate::getopts_options!(@with(options) -$($t)*);
96 options
97 }};
98 (@long $first:ident $($rest:ident)*) => {
99 ::core::concat!(
100 ::core::stringify!($first),
101 $(
102 "-",
103 ::core::stringify!($rest),
104 )*
105 )
106 };
107
108 (@with($o:ident)) => {};
109 (@with($o:ident) . $($t:tt)+) => {
110 $o.$($t)+;
111 };
112 (@with($o:ident) $t1:tt $t2:tt $desc:tt; $($rest:tt)*) => {
113 $crate::getopts_options!(@impl($o, $desc) $t1 $t2);
114 $crate::getopts_options!(@with($o) $($rest)*);
115 };
116 (@with($o:ident) $t1:tt $t2:tt $t3:tt $desc:tt; $($rest:tt)*) => {
117 $crate::getopts_options!(@impl($o, $desc) $t1 $t2 $t3);
118 $crate::getopts_options!(@with($o) $($rest)*);
119 };
120 (@with($o:ident) $t1:tt $t2:tt $t3:tt $t4:tt $desc:tt; $($rest:tt)*) => {
121 $crate::getopts_options!(@impl($o, $desc) $t1 $t2 $t3 $t4);
122 $crate::getopts_options!(@with($o) $($rest)*);
123 };
124 (@with($o:ident) $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $desc:tt; $($rest:tt)*) => {
125 $crate::getopts_options!(@impl($o, $desc) $t1 $t2 $t3 $t4 $t5);
126 $crate::getopts_options!(@with($o) $($rest)*);
127 };
128 (@with($o:ident) $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $desc:tt; $($rest:tt)*) => {
129 $crate::getopts_options!(@impl($o, $desc) $t1 $t2 $t3 $t4 $t5 $t6);
130 $crate::getopts_options!(@with($o) $($rest)*);
131 };
132 (@with($o:ident) $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $desc:tt; $($rest:tt)*) => {
133 $crate::getopts_options!(@impl($o, $desc) $t1 $t2 $t3 $t4 $t5 $t6 $t7);
134 $crate::getopts_options!(@with($o) $($rest)*);
135 };
136 (@with($o:ident) $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $desc:tt; $($rest:tt)*) => {
137 $crate::getopts_options!(@impl($o, $desc) $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8);
138 $crate::getopts_options!(@with($o) $($rest)*);
139 };
140 (@with($o:ident) $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $desc:tt; $($rest:tt)*) => {
141 $crate::getopts_options!(@impl($o, $desc) $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9);
142 $crate::getopts_options!(@with($o) $($rest)*);
143 };
144 (@with($o:ident) $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $desc:tt; $($rest:tt)*) => {
145 $crate::getopts_options!(@impl($o, $desc) $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10);
146 $crate::getopts_options!(@with($o) $($rest)*);
147 };
148 (@with($o:ident) $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $desc:tt; $($rest:tt)*) => {
149 $crate::getopts_options!(@impl($o, $desc) $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11);
150 $crate::getopts_options!(@with($o) $($rest)*);
151 };
152 (@with($o:ident) $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $desc:tt; $($rest:tt)*) => {
153 $crate::getopts_options!(@impl($o, $desc) $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12);
154 $crate::getopts_options!(@with($o) $($rest)*);
155 };
156 (@with($o:ident) $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $desc:tt; $($rest:tt)*) => {
157 $crate::getopts_options!(@impl($o, $desc) $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13);
158 $crate::getopts_options!(@with($o) $($rest)*);
159 };
160 (@with($o:ident) $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $desc:tt; $($rest:tt)*) => {
161 $crate::getopts_options!(@impl($o, $desc) $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14);
162 $crate::getopts_options!(@with($o) $($rest)*);
163 };
164 (@with($o:ident) $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $desc:tt; $($rest:tt)*) => {
165 $crate::getopts_options!(@impl($o, $desc) $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15);
166 $crate::getopts_options!(@with($o) $($rest)*);
167 };
168 (@with($o:ident) $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $desc:tt; $($rest:tt)*) => {
169 $crate::getopts_options!(@impl($o, $desc) $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16);
170 $crate::getopts_options!(@with($o) $($rest)*);
171 };
172 (@with($o:ident) $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $desc:tt; $($rest:tt)*) => {
173 $crate::getopts_options!(@impl($o, $desc) $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17);
174 $crate::getopts_options!(@with($o) $($rest)*);
175 };
176 (@with($o:ident) $t1:tt $t2:tt $t3:tt $t4:tt $t5:tt $t6:tt $t7:tt $t8:tt $t9:tt $t10:tt $t11:tt $t12:tt $t13:tt $t14:tt $t15:tt $t16:tt $t17:tt $t18:tt $desc:tt; $($rest:tt)*) => {
177 $crate::getopts_options!(@impl($o, $desc) $t1 $t2 $t3 $t4 $t5 $t6 $t7 $t8 $t9 $t10 $t11 $t12 $t13 $t14 $t15 $t16 $t17 $t18);
178 $crate::getopts_options!(@with($o) $($rest)*);
179 };
180
181 (@impl($o:ident, $desc:tt) -$short:ident $(,)? --$($long:ident)-+) => {
182 $o.optflag(
183 ::core::stringify!($short),
184 $crate::getopts_options!(@long $($long)+),
185 $desc,
186 );
187 };
188 (@impl($o:ident, $desc:tt) -$short:ident $(,)? --$($long:ident)-+ *) => {
189 $o.optflagmulti(
190 ::core::stringify!($short),
191 $crate::getopts_options!(@long $($long)+),
192 $desc,
193 );
194 };
195 (@impl($o:ident, $desc:tt) -$short:ident $(,)? --$($long:ident)-+ = $hint:ident) => {
196 $o.optopt(
197 ::core::stringify!($short),
198 $crate::getopts_options!(@long $($long)+),
199 $desc,
200 ::core::stringify!($hint),
201 );
202 };
203 (@impl($o:ident, $desc:tt) -$short:ident $(,)? --$($long:ident)-+ * = $hint:ident) => {
204 $o.optmulti(
205 ::core::stringify!($short),
206 $crate::getopts_options!(@long $($long)+),
207 $desc,
208 ::core::stringify!($hint),
209 );
210 };
211 (@impl($o:ident, $desc:tt) -$short:ident $(,)? --$($long:ident)-+ *= $hint:ident) => {
212 $o.optmulti(
213 ::core::stringify!($short),
214 $crate::getopts_options!(@long $($long)+),
215 $desc,
216 ::core::stringify!($hint),
217 );
218 };
219 (@impl($o:ident, $desc:tt) -$short:ident $(,)? --$($long:ident)-+ + = $hint:ident) => {
220 $o.reqopt(
221 ::core::stringify!($short),
222 $crate::getopts_options!(@long $($long)+),
223 $desc,
224 ::core::stringify!($hint),
225 );
226 };
227 (@impl($o:ident, $desc:tt) -$short:ident $(,)? --$($long:ident)-+ += $hint:ident) => {
228 $o.reqopt(
229 ::core::stringify!($short),
230 $crate::getopts_options!(@long $($long)+),
231 $desc,
232 ::core::stringify!($hint),
233 );
234 };
235 (@impl($o:ident, $desc:tt) -$short:ident $(,)? --$($long:ident)-+ ?= $hint:ident) => {
236 $o.optflagopt(
237 ::core::stringify!($short),
238 $crate::getopts_options!(@long $($long)+),
239 $desc,
240 ::core::stringify!($hint),
241 );
242 };
243 (@impl($o:ident, $desc:tt) -$short:ident $(,)? --$($long:ident)-+ *?= $hint:ident) => {
244 $crate::GetOptsExt::optflagmultiopt(
245 &mut $o,
246 ::core::stringify!($short),
247 $crate::getopts_options!(@long $($long)+),
248 $desc,
249 ::core::stringify!($hint),
250 )
251 };
252 (@impl($o:ident, $desc:tt) -$short:ident $(,)? --$($long:ident)-+ +?= $hint:ident) => {
253 $crate::GetOptsExt::optflagreqopt(
254 &mut $o,
255 ::core::stringify!($short),
256 $crate::getopts_options!(@long $($long)+),
257 $desc,
258 ::core::stringify!($hint),
259 )
260 };
261
262
263 (@impl($o:ident, $desc:tt) -$short:ident) => {
264 $o.optflag(
265 ::core::stringify!($short),
266 "",
267 $desc,
268 );
269 };
270 (@impl($o:ident, $desc:tt) -$short:ident *) => {
271 $o.optflagmulti(
272 ::core::stringify!($short),
273 "",
274 $desc,
275 );
276 };
277 (@impl($o:ident, $desc:tt) -$short:ident = $hint:ident) => {
278 $o.optopt(
279 ::core::stringify!($short),
280 "",
281 $desc,
282 ::core::stringify!($hint),
283 );
284 };
285 (@impl($o:ident, $desc:tt) -$short:ident * = $hint:ident) => {
286 $o.optmulti(
287 ::core::stringify!($short),
288 "",
289 $desc,
290 ::core::stringify!($hint),
291 );
292 };
293 (@impl($o:ident, $desc:tt) -$short:ident *= $hint:ident) => {
294 $o.optmulti(
295 ::core::stringify!($short),
296 "",
297 $desc,
298 ::core::stringify!($hint),
299 );
300 };
301 (@impl($o:ident, $desc:tt) -$short:ident + = $hint:ident) => {
302 $o.reqopt(
303 ::core::stringify!($short),
304 "",
305 $desc,
306 ::core::stringify!($hint),
307 );
308 };
309 (@impl($o:ident, $desc:tt) -$short:ident += $hint:ident) => {
310 $o.reqopt(
311 ::core::stringify!($short),
312 "",
313 $desc,
314 ::core::stringify!($hint),
315 );
316 };
317 (@impl($o:ident, $desc:tt) -$short:ident ?= $hint:ident) => {
318 $o.optflagopt(
319 ::core::stringify!($short),
320 "",
321 $desc,
322 ::core::stringify!($hint),
323 );
324 };
325 (@impl($o:ident, $desc:tt) -$short:ident *?= $hint:ident) => {
326 $crate::GetOptsExt::optflagmultiopt(
327 &mut $o,
328 ::core::stringify!($short),
329 "",
330 $desc,
331 ::core::stringify!($hint),
332 )
333 };
334 (@impl($o:ident, $desc:tt) -$short:ident +?= $hint:ident) => {
335 $crate::GetOptsExt::optflagreqopt(
336 &mut $o,
337 ::core::stringify!($short),
338 "",
339 $desc,
340 ::core::stringify!($hint),
341 )
342 };
343
344
345 (@impl($o:ident, $desc:tt) --$($long:ident)-+) => {
346 $o.optflag(
347 "",
348 $crate::getopts_options!(@long $($long)+),
349 $desc,
350 );
351 };
352 (@impl($o:ident, $desc:tt) --$($long:ident)-+ *) => {
353 $o.optflagmulti(
354 "",
355 $crate::getopts_options!(@long $($long)+),
356 $desc,
357 );
358 };
359 (@impl($o:ident, $desc:tt) --$($long:ident)-+ = $hint:ident) => {
360 $o.optopt(
361 "",
362 $crate::getopts_options!(@long $($long)+),
363 $desc,
364 ::core::stringify!($hint),
365 );
366 };
367 (@impl($o:ident, $desc:tt) --$($long:ident)-+ * = $hint:ident) => {
368 $o.optmulti(
369 "",
370 $crate::getopts_options!(@long $($long)+),
371 $desc,
372 ::core::stringify!($hint),
373 );
374 };
375 (@impl($o:ident, $desc:tt) --$($long:ident)-+ *= $hint:ident) => {
376 $o.optmulti(
377 "",
378 $crate::getopts_options!(@long $($long)+),
379 $desc,
380 ::core::stringify!($hint),
381 );
382 };
383 (@impl($o:ident, $desc:tt) --$($long:ident)-+ + = $hint:ident) => {
384 $o.reqopt(
385 "",
386 $crate::getopts_options!(@long $($long)+),
387 $desc,
388 ::core::stringify!($hint),
389 );
390 };
391 (@impl($o:ident, $desc:tt) --$($long:ident)-+ += $hint:ident) => {
392 $o.reqopt(
393 "",
394 $crate::getopts_options!(@long $($long)+),
395 $desc,
396 ::core::stringify!($hint),
397 );
398 };
399 (@impl($o:ident, $desc:tt) --$($long:ident)-+ ?= $hint:ident) => {
400 $o.optflagopt(
401 "",
402 $crate::getopts_options!(@long $($long)+),
403 $desc,
404 ::core::stringify!($hint),
405 );
406 };
407 (@impl($o:ident, $desc:tt) --$($long:ident)-+ *?= $hint:ident) => {
408 $crate::GetOptsExt::optflagmultiopt(
409 &mut $o,
410 "",
411 $crate::getopts_options!(@long $($long)+),
412 $desc,
413 ::core::stringify!($hint),
414 )
415 };
416 (@impl($o:ident, $desc:tt) --$($long:ident)-+ +?= $hint:ident) => {
417 $crate::GetOptsExt::optflagreqopt(
418 &mut $o,
419 "",
420 $crate::getopts_options!(@long $($long)+),
421 $desc,
422 ::core::stringify!($hint),
423 )
424 };
425}
426
427
428#[cfg(feature = "std")]
446#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
447#[track_caller]
448pub fn simple_parse(
449 options: &getopts::Options,
450 prog_desc: &str,
451 min_free: usize,
452 free_desc: &str,
453) -> getopts::Matches {
454 let mut args = std::env::args_os();
455 let prog_name = args.next().unwrap_or_else(|| "<unknown>".into());
456 let prog_name = prog_name.display();
457 let matches = match options.parse(args) {
458 Ok(it) => it,
459 Err(e) => {
460 eprintln!("{prog_name}: {e}");
461 std::process::exit(2);
462 },
463 };
464
465 debug_assert!(matches.opt_defined("help"));
466 if matches.opt_present("help") {
467 let desc = if prog_desc.is_empty() { "" } else { &format!("\n{prog_desc}") };
468 let free_desc = if free_desc.is_empty() { "" } else { &format!(" {free_desc}") };
469
470 let brief = format!("Usage: {prog_name} [Options]{free_desc}{desc}");
471 let usage = options.usage(&brief);
472 println!("{}", usage.trim_end());
473 std::process::exit(0);
474 }
475
476 let found = matches.free.len();
477 if found < min_free {
478 eprintln!("{prog_name}: missing argument, requires {min_free} arguments, provide {found}");
479 std::process::exit(2);
480 }
481
482 matches
483}
484
485#[test]
486fn test() {
487 let usage = getopts_options! {
488 -c --center-rule "...";
489 -i --ignore*=NAME "...";
490 -I --ignore-partial*=NAME "...";
491 -S --fake-source-from=SRC "...";
492 -s --sep?=PATTERN "...";
493 -k --keep*?=PATTERN "...";
494 -h,--help* "...";
495 -m* "...";
496 --long "...";
497 --long-arg=A "...";
498 -j+=J "...";
499 .parsing_style(getopts::ParsingStyle::StopAtFirstFree)
500 }.short_usage("prog");
501 assert_eq!(usage, "Usage: prog [-c] [-i NAME].. [-I NAME].. [-S SRC] [-s [PATTERN]] [-k [PATTERN]].. [-h].. [-m].. [--long] [--long-arg A] -j J");
502}