summaryrefslogtreecommitdiff
path: root/src/config.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/config.rs')
-rw-r--r--src/config.rs168
1 files changed, 168 insertions, 0 deletions
diff --git a/src/config.rs b/src/config.rs
new file mode 100644
index 0000000..6ab2118
--- /dev/null
+++ b/src/config.rs
@@ -0,0 +1,168 @@
+use std::collections::HashMap;
+use std::fs::{File,metadata};
+use std::io::{stderr,Write,BufReader,BufRead};
+use std::env::{home_dir,args};
+use std::process::exit;
+
+use super::filter::Filter;
+use getopts::{Matches,Options};
+
+#[derive(Clone,Debug)]
+pub struct Config {
+ pub quiet: bool,
+ pub vhost2ident: bool,
+ pub aliases: HashMap<String, Filter>,
+}
+
+
+impl Config {
+ pub fn new() -> Config {
+ Config {
+ quiet: false,
+ vhost2ident: false,
+ aliases: HashMap::new()
+ }
+ }
+
+ fn add_alias(&mut self, file: &str, i: usize, l: &str) {
+ let mut a = l.splitn(2, ' ');
+ if a.clone().count() != 2 {
+ writeln!(&mut stderr(), "{}:{}: alias needs two arguments", file, i+1).unwrap();
+ return;
+ }
+ let n = a.next().unwrap();
+ // TODO: Verify that the alias only consists of allowed chars
+
+ let f = match Filter::new(a.next().unwrap()) {
+ Err(()) => {
+ writeln!(&mut stderr(), "{}:{}: invalid filter string", file, i+1).unwrap();
+ return
+ },
+ Ok(x) => x
+ };
+
+ self.aliases.insert(String::from_str(n), f);
+ }
+
+ /// Dumps any errors/warnings to stderr, returns false on fatal error.
+ fn load_file(&mut self, file: &str) -> bool {
+ let f = match File::open(file) {
+ Err(x) => {
+ writeln!(&mut stderr(), "Unable to open '{}': {}", file, x).unwrap();
+ return false;
+ },
+ Ok(x) => x
+ };
+ let b = BufReader::new(f);
+ for (i, l) in b.lines().enumerate() {
+ let l = match l {
+ Err(x) => {
+ writeln!(&mut stderr(), "Unable to read from '{}': {}", file, x).unwrap();
+ return false;
+ },
+ Ok(x) => x
+ };
+ if l == "quiet" {
+ self.quiet = true;
+ } else if l == "no-quiet" {
+ self.quiet = false;
+ } else if l == "vhost2ident" {
+ self.vhost2ident = true;
+ } else if l == "no-vhost2ident" {
+ self.vhost2ident = false;
+ } else if l.starts_with("alias ") {
+ self.add_alias(file, i, &l[6..]);
+ } else if !(l.starts_with("#") || l.len() == 0) {
+ writeln!(&mut stderr(), "{}:{}: Unrecognized line: {}", file, i+1, l).unwrap();
+ }
+ }
+ true
+ }
+
+ fn load_config(&mut self, m: &Matches) {
+ if m.opt_present("config") {
+ if !self.load_file(&m.opt_str("config").unwrap()) {
+ exit(1);
+ }
+ } else if !m.opt_present("no-config") {
+ if metadata("/etc/ncsautil").is_ok() {
+ self.load_file("/etc/ncsautil");
+ }
+ let h = home_dir();
+ match h {
+ None => (),
+ Some(mut x) => {
+ x.push(".ncsautil");
+ if metadata(&x).is_ok() {
+ self.load_file(x.to_str().unwrap());
+ }
+ }
+ };
+ }
+ }
+
+ fn parse_opts(&mut self, m: &Matches) {
+ if m.opt_present("vhost2ident") {
+ self.vhost2ident = true;
+ }
+ if m.opt_present("no-vhost2ident") {
+ self.vhost2ident = false;
+ }
+
+ if m.opt_present("quiet") {
+ self.quiet = true;
+ }
+ if m.opt_present("no-quiet") {
+ self.quiet = false;
+ }
+ }
+
+ /// Parses the filter string from the command line
+ fn parse_filter(&self, m: &Matches) -> Filter {
+ if m.free.is_empty() {
+ println!("No filter string given. See --help for options.");
+ exit(1);
+ }
+
+ let filter = &m.free[0];
+ let f = Filter::new(filter);
+ if f.is_err() {
+ println!("Invalid filter '{}'", filter);
+ exit(1);
+ }
+ let mut f = f.unwrap();
+ match f.expand(&self.aliases) {
+ Ok(_) => (),
+ Err(x) => {
+ println!("Invalid filter '{}': {}", filter, x);
+ exit(1);
+ }
+ }
+ f
+ }
+
+ /// Parses command-line arguments and loads any config files. Exits the program on error.
+ pub fn parse_args(&mut self) -> Filter {
+ let mut opts = Options::new();
+ opts.optflag("h", "help", "print this help");
+ opts.optopt( "c", "config", "load alternative config file", "FILE");
+ opts.optflag("", "no-config", "don't load any config file at all");
+ opts.optflag("", "vhost2ident", "normalize hostname into ident field");
+ opts.optflag("", "no-vhost2ident", "");
+ opts.optflag("q", "quiet", "suppress warnings about unrecognized lines");
+ opts.optflag("", "no-quiet", "");
+
+ let mut args = args();
+ let prog = args.next().unwrap();
+ let m = opts.parse(args).unwrap();
+
+ if m.opt_present("h") {
+ print!("{}", opts.usage(format!("Usage: {} [options] <filter>", prog).as_ref()));
+ exit(1);
+ }
+
+ self.load_config(&m);
+ self.parse_opts(&m);
+ self.parse_filter(&m)
+ }
+}