Mike Gerwitz

Activist for User Freedom

aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'tamer/src/bin/tameld.rs')
-rw-r--r--tamer/src/bin/tameld.rs213
1 files changed, 212 insertions, 1 deletions
diff --git a/tamer/src/bin/tameld.rs b/tamer/src/bin/tameld.rs
index 40f51bc..c06aa1c 100644
--- a/tamer/src/bin/tameld.rs
+++ b/tamer/src/bin/tameld.rs
@@ -24,9 +24,220 @@
extern crate tamer;
+use getopts::{Fail, Options};
+use std::env;
use std::error::Error;
use tamer::ld::poc;
+/// Types of commands
+enum Command {
+ Link(String, String),
+ Usage,
+}
+
+/// Entrypoint for the linker
pub fn main() -> Result<(), Box<dyn Error>> {
- poc::main()
+ let args: Vec<String> = env::args().collect();
+ let program = &args[0];
+ let opts = get_opts();
+ let usage = opts.usage(&format!("Usage: {} -o OUTPUT FILE", program));
+
+ match parse_options(opts, args) {
+ Ok(Command::Link(input, output)) => poc::main(&input, &output),
+ Ok(Command::Usage) => {
+ println!("{}", usage);
+ std::process::exit(exitcode::OK);
+ }
+ Err(e) => {
+ eprintln!("{}", e);
+ println!("{}", usage);
+ std::process::exit(exitcode::USAGE);
+ }
+ }
+}
+
+/// Get 'Options'
+///
+/// ```
+/// use getopts::Options;
+///
+/// let opts = get_opts();
+/// ```
+fn get_opts() -> Options {
+ let mut opts = Options::new();
+ opts.optopt("o", "output", "set output file name", "NAME");
+ opts.optflag("h", "help", "print this help menu");
+
+ opts
+}
+
+/// Option parser
+fn parse_options(opts: Options, args: Vec<String>) -> Result<Command, Fail> {
+ let matches = match opts.parse(&args[1..]) {
+ Ok(m) => m,
+ Err(f) => {
+ return Err(f);
+ }
+ };
+
+ if matches.opt_present("h") {
+ return Ok(Command::Usage);
+ }
+
+ let input = match matches.free.len() {
+ 0 => return Err(Fail::OptionMissing(String::from("FILE"))),
+ 1 => matches.free[0].clone(),
+ _ => return Err(Fail::UnrecognizedOption(matches.free[1].clone())),
+ };
+
+ let output = match matches.opt_str("o") {
+ Some(m) => m,
+ None => {
+ return Err(Fail::OptionMissing(String::from("-o OUTPUT")));
+ }
+ };
+
+ Ok(Command::Link(input, output))
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn parse_options_help() {
+ let opts = get_opts();
+ let result = parse_options(
+ opts,
+ vec![String::from("program"), String::from("-h")],
+ );
+
+ match result {
+ Ok(Command::Usage) => {}
+ _ => panic!("Long help option did not parse"),
+ }
+ }
+
+ #[test]
+ fn parse_options_help_long() {
+ let opts = get_opts();
+ let result = parse_options(
+ opts,
+ vec![String::from("program"), String::from("--help")],
+ );
+
+ match result {
+ Ok(Command::Usage) => {}
+ _ => panic!("Help option did not parse"),
+ }
+ }
+
+ #[test]
+ fn parse_options_invalid() {
+ let opts = get_opts();
+ let result = parse_options(
+ opts,
+ vec![String::from("program"), String::from("-q")],
+ );
+
+ match result {
+ Err(Fail::UnrecognizedOption(_)) => {}
+ _ => panic!("Invalid option not caught"),
+ }
+ }
+
+ #[test]
+ fn parse_options_missing_input() {
+ let opts = get_opts();
+ let result = parse_options(opts, vec![String::from("program")]);
+
+ match result {
+ Err(Fail::OptionMissing(message)) => {
+ assert_eq!("FILE", message);
+ }
+ _ => panic!("Missing input not caught"),
+ }
+ }
+
+ #[test]
+ fn parse_options_missing_output() {
+ let opts = get_opts();
+ let result = parse_options(
+ opts,
+ vec![String::from("program"), String::from("foo")],
+ );
+
+ match result {
+ Err(Fail::OptionMissing(message)) => {
+ assert_eq!("-o OUTPUT", message);
+ }
+ _ => panic!("Missing output not caught"),
+ }
+ }
+
+ #[test]
+ fn parse_options_too_many_args() {
+ let opts = get_opts();
+ let result = parse_options(
+ opts,
+ vec![
+ String::from("program"),
+ String::from("foo"),
+ String::from("-o"),
+ String::from("bar"),
+ String::from("baz"),
+ ],
+ );
+
+ match result {
+ Err(Fail::UnrecognizedOption(message)) => {
+ assert_eq!("baz", message);
+ }
+ _ => panic!("Extra option not caught"),
+ }
+ }
+
+ #[test]
+ fn parse_options_valid() {
+ let opts = get_opts();
+ let result = parse_options(
+ opts,
+ vec![
+ String::from("program"),
+ String::from("foo"),
+ String::from("-o"),
+ String::from("bar"),
+ ],
+ );
+
+ match result {
+ Ok(Command::Link(infile, outfile)) => {
+ assert_eq!("foo", infile);
+ assert_eq!("bar", outfile);
+ }
+ _ => panic!("Unexpected result"),
+ }
+ }
+
+ #[test]
+ fn parse_options_valid_long() {
+ let opts = get_opts();
+ let result = parse_options(
+ opts,
+ vec![
+ String::from("program"),
+ String::from("foo"),
+ String::from("--output"),
+ String::from("bar"),
+ ],
+ );
+
+ match result {
+ Ok(Command::Link(infile, outfile)) => {
+ assert_eq!("foo", infile);
+ assert_eq!("bar", outfile);
+ }
+ _ => panic!("Unexpected result"),
+ }
+ }
}