aboutsummaryrefslogtreecommitdiffstats
path: root/src/config.rs
blob: 5d37fabe1d45cf253efd3a52aaa2b6d0c1def6e3 (plain)
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
125
126
use std::ffi::CString;
use std::fs;
use std::ptr;

use exitcode;
use libc::c_char;
use getopts::Options;
use toml;
use xdg;

use errors::*;

type Milliseconds = u16;

#[repr(C)]
pub struct Args {
    pub reload: bool,
    pub daemon: bool,
    pub audio: bool,
    pub version: bool,
    pub license: *mut c_char,
}

impl Default for Args {
    fn default() -> Self {
        Args {
            reload: false,
            daemon: false,
            audio: false,
            version: false,
            license: ptr::null_mut(),
        }
    }
}

#[repr(C)]
#[derive(Deserialize)]
#[serde(default)]
pub struct Config {
    #[serde(skip)]
    pub args: Args,
    pub timeout: Milliseconds,
}

impl Default for Config {
    fn default() -> Self {
        Config {
            args: Args::default(),
            timeout: 500,
        }
    }
}

fn print_usage(opts: Options) {
    let brief = "Usage: dome-key [options]";
    print!("{}", opts.usage(&brief));

    ::std::process::exit(exitcode::OK);
}

pub fn parse_args<'a>(args: &[String], config: &'a mut Config) -> &'a mut Config {
    let mut opts = Options::new();

    opts.optflag("d", "daemon", "run the daemon in the current shell");
    opts.optflag("r", "reload-mappings", "reload the mappings file");
    opts.optflag("", "audio", "play interface audio");
    opts.optopt(
        "",
        "license",
        "register the software using a license plist file",
        "FILE"
    );
    opts.optflag("v", "version", "print the program version");
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(e) => panic!(e),
    };

    if matches.opt_present("h") {
        print_usage(opts);
        return config;
    }

    if matches.opt_present("audio") {
        config.args.audio = true;
    }

    if matches.opt_present("r") {
        config.args.reload = true;
    } else if matches.opt_present("d") {
        config.args.daemon = true;
    } else if let Some(license_path) = matches.opt_str("license") {
        match CString::new(license_path) {
            Ok(str) => config.args.license = str.into_raw(),
            Err(e) => dkeprintln!("{}", e),
        }
    } else if matches.opt_present("v") {
        config.args.version = true;
    } else {
        print_usage(opts);
    }

    config
}

pub fn get_config() -> Result<Config> {
    let config = match xdg::BaseDirectories::with_prefix("dome-key") {
        Ok(xdg_dirs) => {
            match xdg_dirs.find_config_file("config.toml") {
                Some(config_file) => {
                    let config_str = fs::read_to_string(config_file)
                        .chain_err(|| "failed to read config file")?;

                    toml::from_str(&config_str)
                        .chain_err(|| "failed to parse config file")?
                },
                None => Config::default(),
            }
        },
        Err(_) => Config::default(),
    };

    Ok(config)
}