1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use std::env;
use std::process::exit;

/// Configuration struct, all program behavior is defined in those fields.
pub struct Config {
    /// Year to use.
    pub year: Option<i32>,
    /// Print a newline "\n" char at the end.
    pub newline: bool,
    /// Force the date to be last week-end.
    pub week_end: bool,
}

/// Version of the program, eg: 0.1.2-deadbeef
pub const VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION");
const MIN_YEAR: i32 = -1_000;
const MAX_YEAR: i32 = 10_000;

impl Config {
    /// Parses the command line arguments.
    pub fn parse() -> Config {
        let mut c = Config::default();
        let mut first: bool = true;

        for arg in env::args() {
            if first {
                first = false;
                continue;
            }
            match arg.as_str() {
                "-n" | "--no-newline" => {
                    c.newline = false;
                    continue;
                }
                "-w" | "--week-end" => {
                    c.week_end = true;
                    continue;
                }
                "-h" | "--help" => {
                    help();
                    exit(0);
                }
                "-v" | "--version" => {
                    version();
                    exit(0);
                }
                _ => (),
            }
            if arg.len() > 1 && arg[0..1] == *"-" {
                match arg[1..].parse::<i32>() {
                    Ok(n) => {
                        if n >= MIN_YEAR && n <= MAX_YEAR {
                            c.year = Some(n);
                        } else {
                            println!("invalid year: {}", n);
                            println!();
                            usage();
                            exit(1);
                        }
                        continue;
                    }
                    Err(e) => {
                        println!("error parsing year \"{}\": {}", arg, e);
                        println!();
                        usage();
                        exit(1);
                    }
                }
            }
            println!("invalid arg: \"{}\"", arg);
            println!();
            usage();
            exit(1);
        }

        return c;
    }
}

impl std::default::Default for Config {
    /// Return a default config.
    ///
    /// ```
    /// use fakedate::options;
    ///
    /// let c = options::Config::default();
    /// assert!(c.newline);
    /// ```
    fn default() -> Self {
        Config {
            newline: true,
            week_end: false,
            year: None,
        }
    }
}

fn help() {
    copyright();
    println!();
    usage();
}

fn version() {
    println!("fakedate-{}", VERSION.unwrap_or("unknown"));
}

fn copyright() {
    println!("fakedate is licensed under the MIT license");
    println!("Copyright (C) 2021 Christian Mauduit <ufoot@ufoot.org>");
    println!();
    println!("https://gitlab.com/ufoot/fakedate");
}

fn usage() {
    println!("usage: fakedate [-w] [-n] [-<year>]");
    println!("example: fakedate -1975");
    println!();
    println!("options:");
    println!("-n,--no-newline: no newline char at the end of the date");
    println!("-w,--week-end: force the date to be last week-end");
    println!("-h,--help: display help");
    println!("-v,--version: show version");
}