arg.rs (2881B) - raw
1 // This file is licensed under the terms of 0BSD: 2 // 3 // Permission to use, copy, modify, and/or distribute this software for any purpose with or without 4 // fee is hereby granted. 5 // 6 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 7 // SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 8 // AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 9 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 10 // NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 11 // OF THIS SOFTWARE. 12 // 13 14 use std::env; 15 use std::ffi::OsString; 16 17 use std::path::PathBuf; 18 use std::process::exit; 19 use std::str::FromStr; 20 21 fn usage() -> ! { 22 let name = env::args().next().unwrap(); 23 eprintln!( 24 "usage: {} [-rR] [-c CONFIG] [-d OUT_DIR] MAIDLIR 25 26 MAILDIR A directory containing the maildirs of lists you want to parse 27 28 FLAGS (default -gh if none set) 29 -g include gemini output 30 -h include HTML output 31 32 ARGS: 33 -c config file (crabmail.conf) 34 -d output directory (site)", 35 name 36 ); 37 exit(1) 38 } 39 40 #[derive(Default)] 41 pub struct Args { 42 pub config: PathBuf, 43 pub out_dir: PathBuf, 44 pub positional: Vec<OsString>, 45 pub a: i32, // placeholder 46 pub include_gemini: bool, 47 pub include_html: bool, 48 pub no_index: bool, 49 } 50 51 impl Args { 52 pub fn default() -> Self { 53 Args { 54 out_dir: "site".into(), 55 config: "crabmail.conf".into(), 56 ..Default::default() 57 } 58 } 59 60 pub fn from_env() -> Self { 61 let mut out = Self::default(); 62 let mut args = env::args_os().skip(1); 63 while let Some(arg) = args.next() { 64 let s = arg.to_string_lossy(); 65 let mut ch_iter = s.chars(); 66 if ch_iter.next() != Some('-') { 67 out.positional.push(arg); 68 continue; 69 } 70 ch_iter.for_each(|m| match m { 71 // Edit these lines // 72 'c' => out.config = parse_os_arg(args.next()), 73 'd' => out.out_dir = parse_os_arg(args.next()), 74 'g' => out.include_gemini = true, 75 'h' => out.include_html = true, 76 // Stop editing // 77 _ => { 78 usage(); 79 } 80 }) 81 } 82 // other validation 83 if out.positional.len() < 1 { 84 usage() 85 } 86 out 87 } 88 } 89 90 #[allow(dead_code)] 91 fn parse_arg<T: FromStr>(a: Option<OsString>) -> T { 92 a.and_then(|a| a.into_string().ok()) 93 .and_then(|a| a.parse().ok()) 94 .unwrap_or_else(|| usage()) 95 } 96 97 fn parse_os_arg<T: From<OsString>>(a: Option<OsString>) -> T { 98 match a { 99 Some(s) => T::from(s), 100 None => usage(), 101 } 102 }