<commit_before>extern crate env_logger;
extern crate log;

extern crate afterparty;
#[macro_use]
extern crate clap;
extern crate git2;
extern crate github_rs;
extern crate hyper;
extern crate lettre;
extern crate regex;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate slack_hook;
extern crate toml;

mod auth;
mod config;
mod email;
mod repo;
mod slack;
mod taste;
mod github;

use afterparty::{Delivery, Event, Hub};
use hyper::Server;
use std::collections::HashMap;
use std::error::Error;
use std::path::Path;
use std::sync::{Arc, Mutex};

use config::Config;

#[cfg_attr(rustfmt, rustfmt_skip)]
const TASTER_USAGE: &'static str = "\
EXAMPLES:
  taster -w /path/to/workdir -s my_secret
  taster -l 0.0.0.0:1234 -w /path/to/workdir -s my_secret";

#[derive(Clone, Debug)]
pub struct Commit {
    pub id: git2::Oid,
    pub msg: String,
    pub url: String,
}

#[derive(Clone, Debug)]
pub struct Push {
    pub head_commit: Commit,
    pub push_ref: Option<String>,
    pub pusher: Option<String>,
    pub owner_name: Option<String>,
    pub repo_name: Option<String>,
}

pub fn main() {
    use clap::{App, Arg, ErrorKind};

    env_logger::init().unwrap();

    let args = App::new("taster")
        .version("0.0.1")
        .about("Tastes GitHub commits.")
        .arg(
            Arg::with_name("listen_addr")
                .short("l")
                .long("listen_addr")
                .takes_value(true)
                .value_name("IP:PORT")
                .default_value("0.0.0.0:4567")
                .help("Listen address and port for webhook delivery"),
        )
        .arg(
            Arg::with_name("github_repo")
                .short("r")
                .long("github_repo")
                .takes_value(true)
                .required(true)
                .value_name("GH_REPO")
                .default_value("https://github.com/ms705/taster")
                .help("GitHub repository to taste"),
        )
        .arg(
            Arg::with_name("email_addr")
                .long("email_addr")
                .takes_value(true)
                .required(false)
                .help("Email address to send notifications to"),
        )
        .arg(
            Arg::with_name("default_regression_reporting_threshold")
                .long("default_regression_reporting_threshold")
                .takes_value(true)
                .default_value("0.1")
                .help(
                    "Relative performance threshold below which a result is considered a \
                     regression that needs reporting (0.1 = +/-10%).",
                ),
        )
        .arg(
            Arg::with_name("default_improvement_reporting_threshold")
                .long("default_improvement_reporting_threshold")
                .takes_value(true)
                .default_value("0.1")
                .help(
                    "Relative performance threshold above which a result is considered an \
                     improvement that needs reporting (0.1 = +/-10%).",
                ),
        )
        .arg(
            Arg::with_name("secret")
                .short("s")
                .long("secret")
                .takes_value(true)
                .required(false)
                .help("GitHub webhook secret"),
        )
        .arg(
            Arg::with_name("slack_hook_url")
                .long("slack_hook_url")
                .takes_value(true)
                .required(false)
                .help("Slack webhook URL to push notifications to"),
        )
        .arg(
            Arg::with_name("slack_channel")
                .long("slack_channel")
                .takes_value(true)
                .required(false)
                .default_value("#soup-test")
                .help("Slack channel for notifications"),
        )
        .arg(
            Arg::with_name("github_api_key")
                .long("github_api_key")
                .takes_value(true)
                .required(false)
                .help("GitHub API key to provide status notifications"),
        )
        .arg(
            Arg::with_name("taste_commit")
                .long("taste_commit")
                .short("t")
                .takes_value(true)
                .required(false)
                .help("Do a one-off taste of a specific commit"),
        )
        .arg(
            Arg::with_name("taste_head_only")
                .long("taste_head_only")
                .required(false)
                .help("When multiple commits are pushed, taste the head commit only"),
        )
        .arg(
            Arg::with_name("timeout")
                .long("timeout")
                .required(false)
                .takes_value(true)
                .help("Timeout (in seconds) after which benchmarks should be killed"),
        )
        .arg(
            Arg::with_name("verbose_notifications")
                .long("verbose_notifications")
                .required(false)
                .help(
                    "List all benchmarks in notifications even if the results have not changed \
                     significantly",
                ),
        )
        .arg(
            Arg::with_name("workdir")
                .short("w")
                .long("workdir")
                .takes_value(true)
                .required(true)
                .value_name("REPO_DIR")
                .help("Directory holding the workspace repo"),
        )
        .after_help(TASTER_USAGE)
        .get_matches();

    let addr = args.value_of("listen_addr").unwrap();
    let email_notification_addr = args.value_of("email_addr");
    let repo = args.value_of("github_repo").unwrap();
    let secret = args.value_of("secret");
    let slack_hook_url = args.value_of("slack_hook_url");
    let slack_channel = args.value_of("slack_channel");
    let taste_commit = args.value_of("taste_commit");
    let github_api_key = args.value_of("github_api_key");
    let taste_head_only = args.is_present("taste_head_only");
    let workdir = Path::new(args.value_of("workdir").unwrap());
    let verbose_notify = args.is_present("verbose_notifications");
    let improvement_threshold =
        value_t_or_exit!(args, "default_improvement_reporting_threshold", f64);
    let regression_threshold =
        value_t_or_exit!(args, "default_regression_reporting_threshold", f64);
    let timeout = match value_t!(args, "timeout", u64) {
        Ok(timeout) => Some(timeout),
        Err(e) => match e.kind {
            ErrorKind::ArgumentNotFound => None,
            _ => panic!("failed to parse timeout: {:?}", e),
        },
    };

    let mut history = HashMap::new();
    let ws = repo::Workspace::new(repo, workdir);
    let en = if let Some(addr) = email_notification_addr {
        Some(email::EmailNotifier::new(addr, repo))
    } else {
        None
    };
    let sn = if let Some(url) = slack_hook_url {
        Some(slack::SlackNotifier::new(
            url,
            slack_channel.unwrap(),
            repo,
            verbose_notify,
        ))
    } else {
        None
    };
    let gn = if let Some(key) = github_api_key {
        Some(github::GithubNotifier::new(key))
    } else {
        None
    };

    if taste_commit.is_some() {
        let cid = if let Some("HEAD") = taste_commit {
            ws.repo.head().unwrap().target().unwrap().clone()
        } else {
            git2::Oid::from_str(taste_commit.unwrap()).unwrap()
        };
        match ws.repo.find_object(cid, None) {
            Err(e) => panic!(format!("{}", e.description())),
            Ok(o) => {
                let cobj = o.as_commit().unwrap();
                let hc = Commit {
                    id: cobj.id(),
                    msg: String::from(cobj.message().unwrap()),
                    url: format!("{}/commit/{}", repo, cobj.id()),
                };
                // fake a push
                let push = Push {
                    head_commit: hc,
                    push_ref: None,
                    pusher: None,
                    owner_name: None,
                    repo_name: None,
                };
                let res = taste::taste_commit(
                    &ws,
                    &mut history,
                    &push,
                    &push.head_commit,
                    improvement_threshold,
                    regression_threshold,
                    timeout,
                );
                match res {
                    Err(e) => println!("ERROR: failed to taste{}: {}", cid, e),
                    Ok((cfg, tr)) => {
                        // email notification
                        if en.is_some() {
                            en.as_ref()
                                .unwrap()
                                .notify(cfg.as_ref(), &tr, &push)
                                .unwrap();
                        }
                        // slack notification
                        if sn.is_some() {
                            sn.as_ref()
                                .unwrap()
                                .notify(cfg.as_ref(), &tr, &push)
                                .unwrap();
                        }
                        // We're done
                        return;
                    }
                }
            }
        };
    }

    // If we get here, we must be running in continuous mode
    if let None = secret {
        panic!("--secret must be set when in continuous webhook handler mode");
    }

    // Initialize history by tasting the HEAD commit of each branch
    {
        let branches = ws.branch_heads();
        for (b, c) in branches.iter() {
            println!(
                "tasting HEAD of {}: {} / {}",
                b,
                c.id(),
                c.message().unwrap()
            );
            let hc = Commit {
                id: c.id(),
                msg: String::from(c.message().unwrap()),
                url: format!("{}/commit/{}", repo, c.id()),
            };
            // fake a push
            let push = Push {
                head_commit: hc,
                push_ref: Some(b.clone()),
                pusher: None,
                owner_name: None,
                repo_name: None,
            };
            let res = taste::taste_commit(
                &ws,
                &mut history,
                &push,
                &push.head_commit,
                improvement_threshold,
                regression_threshold,
                timeout,
            );
            assert!(res.is_ok());
        }
    }

    let hl = Arc::new(Mutex::new(history));
    let wsl = Mutex::new(ws);

    let mut hub = Hub::new();
    hub.handle_authenticated("push", secret.unwrap(), move |delivery: &Delivery| {
        match delivery.payload {
            Event::Push {
                ref _ref,
                ref commits,
                ref head_commit,
                ref pusher,
                ref repository,
                ..
            } => {
                println!(
                    "Handling {} commits pushed by {}",
                    commits.len(),
                    pusher.name
                );

                // Data structures to represent info from webhook
                let hc = Commit {
                    id: git2::Oid::from_str(&head_commit.id).unwrap(),
                    msg: head_commit.message.clone(),
                    url: head_commit.url.clone(),
                };
                let push = Push {
                    head_commit: hc,
                    push_ref: Some(_ref.clone()),
                    pusher: Some(pusher.name.clone()),
                    owner_name: Some(repository.owner.name.clone()),
                    repo_name: Some(repository.name.clone()),
                };

                let notify_pending = |push: &Push, commit: &Commit| {
                    // github status notification
                    if gn.is_some() {
                        gn.as_ref().unwrap().notify_pending(&push, &commit).unwrap();
                    }
                };

                let notify = |cfg: Option<&Config>,
                              res: &taste::TastingResult,
                              push: &Push,
                              commit: &Commit| {
                    // email notification
                    if en.is_some() {
                        en.as_ref().unwrap().notify(cfg, &res, &push).unwrap();
                    }
                    // slack notification
                    if sn.is_some() {
                        sn.as_ref().unwrap().notify(cfg, &res, &push).unwrap();
                    }
                    // github status notification
                    if gn.is_some() {
                        gn.as_ref()
                            .unwrap()
                            .notify(cfg, &res, &push, &commit)
                            .unwrap();
                    }
                };

                {
                    notify_pending(&push, &push.head_commit);
                    let ws = wsl.lock().unwrap();
                    let mut history = hl.lock().unwrap();
                    // First taste the head commit
                    ws.fetch().unwrap();
                    let head_res = taste::taste_commit(
                        &ws,
                        &mut history,
                        &push,
                        &push.head_commit,
                        improvement_threshold,
                        regression_threshold,
                        timeout,
                    );
                    match head_res {
                        Err(e) => println!(
                            "ERROR: failed to taste HEAD commit {}: {}",
                            head_commit.id,
                            e
                        ),
                        Ok((cfg, tr)) => {
                            notify(cfg.as_ref(), &tr, &push, &push.head_commit);
                            // Taste others if needed
                            if !taste_head_only {
                                for c in commits.iter() {
                                    if c.id == head_commit.id {
                                        // skip HEAD as we've already tested it
                                        continue;
                                    }
                                    let cur_c = Commit {
                                        id: git2::Oid::from_str(&c.id).unwrap(),
                                        msg: c.message.clone(),
                                        url: c.url.clone(),
                                    };
                                    notify_pending(&push, &cur_c);
                                    // taste
                                    let res = taste::taste_commit(
                                        &ws,
                                        &mut history,
                                        &push,
                                        &cur_c,
                                        improvement_threshold,
                                        regression_threshold,
                                        timeout,
                                    );
                                    match res {
                                        Err(e) => println!(
                                            "ERROR: failed to taste commit {}: {}",
                                            c.id,
                                            e
                                        ),
                                        Ok((cfg, tr)) => notify(cfg.as_ref(), &tr, &push, &cur_c),
                                    }
                                }
                            } else if !commits.is_empty() {
                                println!(
                                    "Skipping {} remaining commits in push!",
                                    commits.len() - 1
                                );
                            }
                        }
                    }
                }
            }
            _ => (),
        }
    });

    let srvc = Server::http(&addr[..]).unwrap().handle(hub);

    println!("Taster listening on {}", addr);
    srvc.unwrap();
}
<commit_msg>Error if GH notify fails<commit_after>extern crate env_logger;
extern crate log;

extern crate afterparty;
#[macro_use]
extern crate clap;
extern crate git2;
extern crate github_rs;
extern crate hyper;
extern crate lettre;
extern crate regex;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate slack_hook;
extern crate toml;

mod auth;
mod config;
mod email;
mod repo;
mod slack;
mod taste;
mod github;

use afterparty::{Delivery, Event, Hub};
use hyper::Server;
use std::collections::HashMap;
use std::error::Error;
use std::path::Path;
use std::sync::{Arc, Mutex};

use config::Config;

#[cfg_attr(rustfmt, rustfmt_skip)]
const TASTER_USAGE: &'static str = "\
EXAMPLES:
  taster -w /path/to/workdir -s my_secret
  taster -l 0.0.0.0:1234 -w /path/to/workdir -s my_secret";

#[derive(Clone, Debug)]
pub struct Commit {
    pub id: git2::Oid,
    pub msg: String,
    pub url: String,
}

#[derive(Clone, Debug)]
pub struct Push {
    pub head_commit: Commit,
    pub push_ref: Option<String>,
    pub pusher: Option<String>,
    pub owner_name: Option<String>,
    pub repo_name: Option<String>,
}

pub fn main() {
    use clap::{App, Arg, ErrorKind};

    env_logger::init().unwrap();

    let args = App::new("taster")
        .version("0.0.1")
        .about("Tastes GitHub commits.")
        .arg(
            Arg::with_name("listen_addr")
                .short("l")
                .long("listen_addr")
                .takes_value(true)
                .value_name("IP:PORT")
                .default_value("0.0.0.0:4567")
                .help("Listen address and port for webhook delivery"),
        )
        .arg(
            Arg::with_name("github_repo")
                .short("r")
                .long("github_repo")
                .takes_value(true)
                .required(true)
                .value_name("GH_REPO")
                .default_value("https://github.com/ms705/taster")
                .help("GitHub repository to taste"),
        )
        .arg(
            Arg::with_name("email_addr")
                .long("email_addr")
                .takes_value(true)
                .required(false)
                .help("Email address to send notifications to"),
        )
        .arg(
            Arg::with_name("default_regression_reporting_threshold")
                .long("default_regression_reporting_threshold")
                .takes_value(true)
                .default_value("0.1")
                .help(
                    "Relative performance threshold below which a result is considered a \
                     regression that needs reporting (0.1 = +/-10%).",
                ),
        )
        .arg(
            Arg::with_name("default_improvement_reporting_threshold")
                .long("default_improvement_reporting_threshold")
                .takes_value(true)
                .default_value("0.1")
                .help(
                    "Relative performance threshold above which a result is considered an \
                     improvement that needs reporting (0.1 = +/-10%).",
                ),
        )
        .arg(
            Arg::with_name("secret")
                .short("s")
                .long("secret")
                .takes_value(true)
                .required(false)
                .help("GitHub webhook secret"),
        )
        .arg(
            Arg::with_name("slack_hook_url")
                .long("slack_hook_url")
                .takes_value(true)
                .required(false)
                .help("Slack webhook URL to push notifications to"),
        )
        .arg(
            Arg::with_name("slack_channel")
                .long("slack_channel")
                .takes_value(true)
                .required(false)
                .default_value("#soup-test")
                .help("Slack channel for notifications"),
        )
        .arg(
            Arg::with_name("github_api_key")
                .long("github_api_key")
                .takes_value(true)
                .required(false)
                .help("GitHub API key to provide status notifications"),
        )
        .arg(
            Arg::with_name("taste_commit")
                .long("taste_commit")
                .short("t")
                .takes_value(true)
                .required(false)
                .help("Do a one-off taste of a specific commit"),
        )
        .arg(
            Arg::with_name("taste_head_only")
                .long("taste_head_only")
                .required(false)
                .help("When multiple commits are pushed, taste the head commit only"),
        )
        .arg(
            Arg::with_name("timeout")
                .long("timeout")
                .required(false)
                .takes_value(true)
                .help("Timeout (in seconds) after which benchmarks should be killed"),
        )
        .arg(
            Arg::with_name("verbose_notifications")
                .long("verbose_notifications")
                .required(false)
                .help(
                    "List all benchmarks in notifications even if the results have not changed \
                     significantly",
                ),
        )
        .arg(
            Arg::with_name("workdir")
                .short("w")
                .long("workdir")
                .takes_value(true)
                .required(true)
                .value_name("REPO_DIR")
                .help("Directory holding the workspace repo"),
        )
        .after_help(TASTER_USAGE)
        .get_matches();

    let addr = args.value_of("listen_addr").unwrap();
    let email_notification_addr = args.value_of("email_addr");
    let repo = args.value_of("github_repo").unwrap();
    let secret = args.value_of("secret");
    let slack_hook_url = args.value_of("slack_hook_url");
    let slack_channel = args.value_of("slack_channel");
    let taste_commit = args.value_of("taste_commit");
    let github_api_key = args.value_of("github_api_key");
    let taste_head_only = args.is_present("taste_head_only");
    let workdir = Path::new(args.value_of("workdir").unwrap());
    let verbose_notify = args.is_present("verbose_notifications");
    let improvement_threshold =
        value_t_or_exit!(args, "default_improvement_reporting_threshold", f64);
    let regression_threshold =
        value_t_or_exit!(args, "default_regression_reporting_threshold", f64);
    let timeout = match value_t!(args, "timeout", u64) {
        Ok(timeout) => Some(timeout),
        Err(e) => match e.kind {
            ErrorKind::ArgumentNotFound => None,
            _ => panic!("failed to parse timeout: {:?}", e),
        },
    };

    let mut history = HashMap::new();
    let ws = repo::Workspace::new(repo, workdir);
    let en = if let Some(addr) = email_notification_addr {
        Some(email::EmailNotifier::new(addr, repo))
    } else {
        None
    };
    let sn = if let Some(url) = slack_hook_url {
        Some(slack::SlackNotifier::new(
            url,
            slack_channel.unwrap(),
            repo,
            verbose_notify,
        ))
    } else {
        None
    };
    let gn = if let Some(key) = github_api_key {
        Some(github::GithubNotifier::new(key))
    } else {
        None
    };

    if taste_commit.is_some() {
        let cid = if let Some("HEAD") = taste_commit {
            ws.repo.head().unwrap().target().unwrap().clone()
        } else {
            git2::Oid::from_str(taste_commit.unwrap()).unwrap()
        };
        match ws.repo.find_object(cid, None) {
            Err(e) => panic!(format!("{}", e.description())),
            Ok(o) => {
                let cobj = o.as_commit().unwrap();
                let hc = Commit {
                    id: cobj.id(),
                    msg: String::from(cobj.message().unwrap()),
                    url: format!("{}/commit/{}", repo, cobj.id()),
                };
                // fake a push
                let push = Push {
                    head_commit: hc,
                    push_ref: None,
                    pusher: None,
                    owner_name: None,
                    repo_name: None,
                };
                let res = taste::taste_commit(
                    &ws,
                    &mut history,
                    &push,
                    &push.head_commit,
                    improvement_threshold,
                    regression_threshold,
                    timeout,
                );
                match res {
                    Err(e) => println!("ERROR: failed to taste{}: {}", cid, e),
                    Ok((cfg, tr)) => {
                        // email notification
                        if en.is_some() {
                            en.as_ref()
                                .unwrap()
                                .notify(cfg.as_ref(), &tr, &push)
                                .unwrap();
                        }
                        // slack notification
                        if sn.is_some() {
                            sn.as_ref()
                                .unwrap()
                                .notify(cfg.as_ref(), &tr, &push)
                                .unwrap();
                        }
                        // We're done
                        return;
                    }
                }
            }
        };
    }

    // If we get here, we must be running in continuous mode
    if let None = secret {
        panic!("--secret must be set when in continuous webhook handler mode");
    }

    // Initialize history by tasting the HEAD commit of each branch
    {
        let branches = ws.branch_heads();
        for (b, c) in branches.iter() {
            println!(
                "tasting HEAD of {}: {} / {}",
                b,
                c.id(),
                c.message().unwrap()
            );
            let hc = Commit {
                id: c.id(),
                msg: String::from(c.message().unwrap()),
                url: format!("{}/commit/{}", repo, c.id()),
            };
            // fake a push
            let push = Push {
                head_commit: hc,
                push_ref: Some(b.clone()),
                pusher: None,
                owner_name: None,
                repo_name: None,
            };
            let res = taste::taste_commit(
                &ws,
                &mut history,
                &push,
                &push.head_commit,
                improvement_threshold,
                regression_threshold,
                timeout,
            );
            assert!(res.is_ok());
        }
    }

    let hl = Arc::new(Mutex::new(history));
    let wsl = Mutex::new(ws);

    let mut hub = Hub::new();
    hub.handle_authenticated("push", secret.unwrap(), move |delivery: &Delivery| {
        match delivery.payload {
            Event::Push {
                ref _ref,
                ref commits,
                ref head_commit,
                ref pusher,
                ref repository,
                ..
            } => {
                println!(
                    "Handling {} commits pushed by {}",
                    commits.len(),
                    pusher.name
                );

                // Data structures to represent info from webhook
                let hc = Commit {
                    id: git2::Oid::from_str(&head_commit.id).unwrap(),
                    msg: head_commit.message.clone(),
                    url: head_commit.url.clone(),
                };
                let push = Push {
                    head_commit: hc,
                    push_ref: Some(_ref.clone()),
                    pusher: Some(pusher.name.clone()),
                    owner_name: Some(repository.owner.name.clone()),
                    repo_name: Some(repository.name.clone()),
                };

                let notify_pending = |push: &Push, commit: &Commit| {
                    // github status notification
                    if gn.is_some() {
                        match gn.as_ref().unwrap().notify_pending(&push, &commit) {
                            Ok(_) => (),
                            Err(e) => {
                                println!("failed to deliver GitHub status notification: {:?}", e)
                            }
                        }
                    }
                };

                let notify = |cfg: Option<&Config>,
                              res: &taste::TastingResult,
                              push: &Push,
                              commit: &Commit| {
                    // email notification
                    if en.is_some() {
                        en.as_ref().unwrap().notify(cfg, &res, &push).unwrap();
                    }
                    // slack notification
                    if sn.is_some() {
                        sn.as_ref().unwrap().notify(cfg, &res, &push).unwrap();
                    }
                    // github status notification
                    if gn.is_some() {
                        gn.as_ref()
                            .unwrap()
                            .notify(cfg, &res, &push, &commit)
                            .unwrap();
                    }
                };

                {
                    notify_pending(&push, &push.head_commit);
                    let ws = wsl.lock().unwrap();
                    let mut history = hl.lock().unwrap();
                    // First taste the head commit
                    ws.fetch().unwrap();
                    let head_res = taste::taste_commit(
                        &ws,
                        &mut history,
                        &push,
                        &push.head_commit,
                        improvement_threshold,
                        regression_threshold,
                        timeout,
                    );
                    match head_res {
                        Err(e) => println!(
                            "ERROR: failed to taste HEAD commit {}: {}",
                            head_commit.id,
                            e
                        ),
                        Ok((cfg, tr)) => {
                            notify(cfg.as_ref(), &tr, &push, &push.head_commit);
                            // Taste others if needed
                            if !taste_head_only {
                                for c in commits.iter() {
                                    if c.id == head_commit.id {
                                        // skip HEAD as we've already tested it
                                        continue;
                                    }
                                    let cur_c = Commit {
                                        id: git2::Oid::from_str(&c.id).unwrap(),
                                        msg: c.message.clone(),
                                        url: c.url.clone(),
                                    };
                                    notify_pending(&push, &cur_c);
                                    // taste
                                    let res = taste::taste_commit(
                                        &ws,
                                        &mut history,
                                        &push,
                                        &cur_c,
                                        improvement_threshold,
                                        regression_threshold,
                                        timeout,
                                    );
                                    match res {
                                        Err(e) => println!(
                                            "ERROR: failed to taste commit {}: {}",
                                            c.id,
                                            e
                                        ),
                                        Ok((cfg, tr)) => notify(cfg.as_ref(), &tr, &push, &cur_c),
                                    }
                                }
                            } else if !commits.is_empty() {
                                println!(
                                    "Skipping {} remaining commits in push!",
                                    commits.len() - 1
                                );
                            }
                        }
                    }
                }
            }
            _ => (),
        }
    });

    let srvc = Server::http(&addr[..]).unwrap().handle(hub);

    println!("Taster listening on {}", addr);
    srvc.unwrap();
}
<|endoftext|>


<commit_before>extern crate rucc;
use rucc::version_info;
use rucc::parser;
use rucc::codegen;

extern crate regex;
use regex::Regex;

fn main() {
    let args: Vec<String> = std::env::args().collect();

    if args.len() < 2 {
        version_info::show_version();
        version_info::show_usage();
        let ast = parser::Parser::run_file("c.c".to_string());
    } else {
        let ref input_file_name = args[1];
        let ast = parser::Parser::run_file(input_file_name.to_string());

        // for node in &ast {
        //     node.show();
        // }

        println!("\nllvm-ir test output:");
        unsafe {
            let mut codegen = codegen::Codegen::new("rucc");
            codegen.run(ast);

            let output_file_name = Regex::new(r"\..*$")
                .unwrap()
                .replace_all(input_file_name, ".ll");
            codegen.write_llvmir_to_file(output_file_name.to_string().as_str());
        }
    }
}
<commit_msg>deleted unnecessary code<commit_after>extern crate rucc;
use rucc::version_info;
use rucc::parser;
use rucc::codegen;

extern crate regex;
use regex::Regex;

fn main() {
    let args: Vec<String> = std::env::args().collect();

    if args.len() < 2 {
        version_info::show_version();
        version_info::show_usage();
    } else {
        let ref input_file_name = args[1];
        let ast = parser::Parser::run_file(input_file_name.to_string());

        // for node in &ast {
        //     node.show();
        // }

        println!("\nllvm-ir test output:");
        unsafe {
            let mut codegen = codegen::Codegen::new("rucc");
            codegen.run(ast);

            let output_file_name = Regex::new(r"\..*$")
                .unwrap()
                .replace_all(input_file_name, ".ll");
            codegen.write_llvmir_to_file(output_file_name.to_string().as_str());
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

use nom::{IResult, space, hex_digit};

named!(statement, take_until_either_and_consume!("."));

fn is_pn_chars_base(chr: &u8) -> bool {
    (*chr >=    0x41 && *chr <=    0x5A) ||
    (*chr >=    0x61 && *chr <=    0x7A) ||
    (*chr >=    0xC0 && *chr <=    0xD6) ||
    (*chr >=    0xD8 && *chr <=    0xF6) ||
    (*chr >=    0xF8 && *chr <=   0x2FF) ||
    (*chr >=   0x370 && *chr <=   0x37D) ||
    (*chr >=   0x37F && *chr <=  0x1FFF) ||
    (*chr >=  0x200C && *chr <=  0x200D) ||
    (*chr >=  0x2C00 && *chr <=  0x2FEF) ||
    (*chr >=  0x3001 && *chr <=  0xD7FF) ||
    (*chr >=  0xF900 && *chr <=  0xFDCF) ||
    (*chr >=  0xFDF0 && *chr <=  0xFFFD) ||
    (*chr >= 0x10000 && *chr <= 0xEFFFF)
}
fn _pn_chars_base(input:&[u8]) -> IResult<&[u8],&[u8]> {
    for c in input {
        if ! is_pn_chars_base(c) {
            return IResult::Error(nom::ErrorKind::Custom(20))
        }
    }
    IResult::Done(&input[1..], &input[0..1])
}
/* [163s] PN_CHARS_BASE */
named!(pn_chars_base, flat_map!(
    take!(1),
    _pn_chars_base
));

/* [169s] PLX */
named!(plx, alt!(percent | pn_local_esc));

/* [170s] PERCENT */
named!(percent, do_parse!(
    tag!("%") >>
    a: flat_map!(
        take!(2),
        hex_digit
    ) >>
    (a)
));

/* [172s]  PN_LOCAL_ESC */
named!(pn_local_esc, escaped!(
    call!(space),
    '\\',
    one_of!("_~.-!$&'()*+,;=/?#@%")
));

fn main() {
    assert_eq!(statement(&b"a b c. d e f."[..]), IResult::Done(&b" d e f."[..], &b"a b c"[..]));
    assert_eq!(pn_chars_base(&b"a%2Ab"[..]),     IResult::Done(&b"%2Ab"[..]   , &b"a"[..]    ));
    assert_eq!(plx(&b"%2Abc"[..]),               IResult::Done(&b"bc"[..]     , &b"2A"[..]   ));
    assert_eq!(plx(&b"\\.%2A"[..]),              IResult::Done(&b"%2A"[..]    , &b"\\."[..]  ));
    assert_eq!(percent(&b"%2Abc"[..]),           IResult::Done(&b"bc"[..]     , &b"2A"[..]   ));
    assert_eq!(pn_local_esc(&b"\\.a b c"[..])  , IResult::Done(&b"a b c"[..]  , &b"\\."[..]  ));
}
<commit_msg>Implement PN_CHARS<commit_after>#[macro_use]
extern crate nom;

use std::str;
use nom::{IResult, space, hex_digit};

named!(statement, take_until_either_and_consume!("."));

fn is_pn_chars_base(c: char) -> bool {
    let u = c as u32;
    (u >=    0x41 && u <=    0x5A) || // [A-Z]
    (u >=    0x61 && u <=    0x7A) || // [a-z]
    (u >=    0xC0 && u <=    0xD6) ||
    (u >=    0xD8 && u <=    0xF6) ||
    (u >=    0xF8 && u <=   0x2FF) ||
    (u >=   0x370 && u <=   0x37D) ||
    (u >=   0x37F && u <=  0x1FFF) ||
    (u >=  0x200C && u <=  0x200D) ||
    (u >=  0x2C00 && u <=  0x2FEF) ||
    (u >=  0x3001 && u <=  0xD7FF) ||
    (u >=  0xF900 && u <=  0xFDCF) ||
    (u >=  0xFDF0 && u <=  0xFFFD) ||
    (u >= 0x10000 && u <= 0xEFFFF)
}
fn _pn_chars_base(input:&[u8]) -> IResult<&[u8],&[u8]> {
    for c in str::from_utf8(input).unwrap().chars() {
        if ! is_pn_chars_base(c) {
            return IResult::Error(nom::ErrorKind::Custom(20)) //TODO: Use correct Error.
        }
    }
    IResult::Done(&b""[..], &input[..])
}

/* [163s] PN_CHARS_BASE */
named!(pn_chars_base, flat_map!(
    take!(1),
    _pn_chars_base
));

fn is_pn_chars_u(c: char) -> bool {
    is_pn_chars_base(c) || c == '_'
}
fn _pn_chars_u(input:&[u8]) -> IResult<&[u8],&[u8]> {
    for c in str::from_utf8(input).unwrap().chars() {
        if ! is_pn_chars_u(c) {
            return IResult::Error(nom::ErrorKind::Custom(20)) //TODO: Use correct Error.
        }
    }
    IResult::Done(&b""[..], &input[..])
}

/* [164s] PN_CHARS_U */
named!(pn_chars_u, flat_map!(
    take!(1),
    _pn_chars_u
));

fn is_pn_chars(c: char) -> bool {
    let u = c as u32;
    is_pn_chars_u(c)             ||
    u == '-' as u32              ||
    u ==  0xB7                   ||
    (u >=   0x30 && u <=   0x39) || // [0-9]
    (u >=  0x300 && u <=  0x36F) ||
    (u >= 0x203F && u <= 0x2040)
}
fn _pn_chars(input:&[u8]) -> IResult<&[u8],&[u8]> {
    for c in str::from_utf8(input).unwrap().chars() {
        if ! is_pn_chars(c) {
            return IResult::Error(nom::ErrorKind::Custom(20)) //TODO: Use correct Error.
        }
    }
    IResult::Done(&b""[..], &input[..])
}

/* [166s] PN_CHARS */
named!(pn_chars, flat_map!(
    take!(1),
    _pn_chars
));

/* [169s] PLX */
named!(plx, alt!(percent | pn_local_esc));

/* [170s] PERCENT */
named!(percent, do_parse!(
    tag!("%") >>
    hex2: flat_map!(
        take!(2),
        hex_digit
    ) >>
    (hex2)
));

/* [172s]  PN_LOCAL_ESC */
named!(pn_local_esc, escaped!(
    call!(space),
    '\\',
    one_of!("_~.-!$&'()*+,;=/?#@%")
));

fn main() {
    assert_eq!(statement(&b"a b c. d e f."[..]), IResult::Done(&b" d e f."[..], &b"a b c"[..]));
    assert_eq!(pn_chars_base(&b"a%2Ab"[..])    , IResult::Done(&b"%2Ab"[..]   , &b"a"[..]    ));
    assert_eq!(pn_chars_u(&b"_a"[..])          , IResult::Done(&b"a"[..]      , &b"_"[..]    ));
    assert_eq!(pn_chars(&b"-_a"[..])           , IResult::Done(&b"_a"[..]     , &b"-"[..]    ));
    assert_eq!(plx(&b"%2Abc"[..])              , IResult::Done(&b"bc"[..]     , &b"2A"[..]   ));
    assert_eq!(plx(&b"\\.%2A"[..])             , IResult::Done(&b"%2A"[..]    , &b"\\."[..]  ));
    assert_eq!(percent(&b"%2Abc"[..])          , IResult::Done(&b"bc"[..]     , &b"2A"[..]   ));
    assert_eq!(pn_local_esc(&b"\\.a b c"[..])  , IResult::Done(&b"a b c"[..]  , &b"\\."[..]  ));
}
<|endoftext|>


<commit_before>#![feature(slice_patterns)]
extern crate nix;
extern crate libc;
use std::{env, ptr,mem};
use libc::{pid_t, c_void, waitpid};
use nix::sys::ptrace;
use nix::sys::ptrace::ptrace::{PTRACE_ATTACH, PTRACE_DETACH, PTRACE_GETREGS};

// #[cfg(target_arch = "x86_64")]
#[derive(Debug,Default)]
#[repr(C)]
struct user_regs_struct {
    r15: u64,
    r14: u64,
    r13: u64,
    r12: u64,
    rbp: u64,
    rbx: u64,
    r11: u64,
    r10: u64,
    r9: u64,
    r8: u64,
    rax: u64,
    rcx: u64,
    rdx: u64,
    rsi: u64,
    rdi: u64,
    orig_rax: u64,
    rip: u64,
    cs: u64,
    eflags: u64,
    rsp: u64,
    ss: u64,
    fs_base: u64,
    gs_base: u64,
    ds: u64,
    es: u64,
    fs: u64,
    gs: u64,
}

fn infect(pid: pid_t) -> Result<(), ()> {
    ptrace::ptrace(PTRACE_ATTACH, pid, 0 as *mut c_void, 0 as *mut c_void);
    let mut regs: user_regs_struct;
    unsafe {
        waitpid(pid, 0 as *mut i32, 0);
        regs = mem::uninitialized();
    }

    ptrace::ptrace(PTRACE_GETREGS,
                   pid,
                   &mut regs as *mut user_regs_struct as *mut c_void,
                   &mut regs as *mut user_regs_struct as *mut c_void);
    println!("{:?}", regs);
    ptrace::ptrace(PTRACE_DETACH, pid, 0 as *mut c_void, 0 as *mut c_void);
    Ok(())
}
fn main() {
    let args: Vec<String> = env::args().collect();

    match &args[1..] {
        &[ref pid, ref code] => {
            infect(pid.parse::<i32>().unwrap());
        }
        _ => unimplemented!(),
    }
}
<commit_msg>assert ptrace<commit_after>#![feature(slice_patterns)]
extern crate nix;
extern crate libc;
use std::{env, ptr, mem, fmt};
use libc::{pid_t, c_void, waitpid};
use nix::sys::ptrace;
use nix::sys::ptrace::ptrace::{PTRACE_ATTACH, PTRACE_DETACH, PTRACE_GETREGS, PTRACE_POKETEXT,
                               PTRACE_SETREGS};

// #[cfg(target_arch = "x86_64")]
#[derive(Debug, Default)]
#[repr(C)]
struct user_regs_struct {
    r15: u64,
    r14: u64,
    r13: u64,
    r12: u64,
    rbp: u64,
    rbx: u64,
    r11: u64,
    r10: u64,
    r9: u64,
    r8: u64,
    rax: u64,
    rcx: u64,
    rdx: u64,
    rsi: u64,
    rdi: u64,
    orig_rax: u64,
    rip: u64,
    cs: u64,
    eflags: u64,
    rsp: u64,
    ss: u64,
    fs_base: u64,
    gs_base: u64,
    ds: u64,
    es: u64,
    fs: u64,
    gs: u64,
}

fn infect(pid: pid_t, buffer: &[u8]) -> Result<(), ()> {
    assert_eq!(ptrace::ptrace(PTRACE_ATTACH, pid, 0 as *mut c_void, 0 as *mut c_void).unwrap(),0);
    let mut regs: user_regs_struct;
    unsafe {
        waitpid(pid, 0 as *mut i32, 0);
        regs = mem::uninitialized();
    }

    assert_eq!(ptrace::ptrace(PTRACE_GETREGS,
                   pid,
                   &mut regs as *mut user_regs_struct as *mut c_void,
                   &mut regs as *mut user_regs_struct as *mut c_void).unwrap(),0);
    println!("{:?}", regs);

    regs.rsp -= 4; // decrement rsp
    println!("New rsp {:x}", regs.rsp);

    assert_eq!(ptrace::ptrace(PTRACE_POKETEXT,
                              pid,
                              regs.rsp as *mut libc::c_void,
                              regs.rip as *mut libc::c_void).unwrap(),
               0);// poke rip -> rsp

    let ptr = regs.rsp - 1024; // inject rsp - 1024
    let beginning = ptr;

    println!("injecting into: {:x}", beginning);

    regs.rip = beginning + 2; // set rip as value of rsp - 1024
    println!("rip is at: {:x}", regs.rip);

    ptrace::ptrace(PTRACE_SETREGS,
                   pid,
                   regs.rsp as *mut libc::c_void,
                   regs.rip as *mut libc::c_void);

    for byte in buffer {
        ptrace::ptrace(PTRACE_POKETEXT,
                       pid,
                       regs.rsp as *mut libc::c_void,
                       regs.rip as *mut libc::c_void);
    }

    ptrace::ptrace(PTRACE_DETACH, pid, 0 as *mut c_void, 0 as *mut c_void);
    Ok(())
}

fn main() {
    let args: Vec<String> = env::args().collect();

    match &args[1..] {
        &[ref pid, ref code] => {
            infect(pid.parse::<i32>().unwrap(), &[]);
        }
        _ => unimplemented!(),
    }
}
<|endoftext|>


<commit_before>extern crate num;

use std::env;
use std::fmt::Display;
use std::str::FromStr;

use num::Bounded;

macro_rules! err_exit {
    ($($arg:tt)*) => (
        {
            use std::io::prelude::*;
            use std::process;
            if let Err(e) = write!(&mut ::std::io::stderr(), "{}\n", format_args!($($arg)*)) {
                panic!("Failed to write to stderr.\
                    \nOriginal error output: {}\
                    \nSecondary error writing to stderr: {}", format!($($arg)*), e);
            }
            process::exit(1)
        }
    )
}

fn main() {
    let threads: usize = parse_command_line_argument(1, "threads");
    let max_prime: usize = parse_command_line_argument(2, "max_prime");

    let sieve = Sieve {
        threads: threads,
        max_prime: max_prime
    };
    println!("{:?}", sieve);
}

fn parse_command_line_argument<T: FromStr + Bounded + Display>(position: usize, name: &str) -> T {
    match env::args().nth(position) {
        None => err_exit!("Usage: sieve_multithreaded_shared <threads> <max_prime>"),
        Some(val) => match val.parse::<T>() {
            Err(_) => err_exit!("Expected <{}>: {} to be >= 0 and <= {}", name, val, T::max_value()),
            Ok(val) => val
        }
    }
}

#[derive(Debug)]
struct Sieve {
    threads: usize,
    max_prime: usize
}<commit_msg>Restrict the number of threads such that the first thread always contains all numbers smaller or equal to the square root of the max prime.<commit_after>extern crate num;

use std::cmp;
use std::env;
use std::fmt::Display;
use std::str::FromStr;

use num::Bounded;

macro_rules! err_exit {
    ($($arg:tt)*) => (
        {
            use std::io::prelude::*;
            use std::process;
            if let Err(e) = write!(&mut ::std::io::stderr(), "{}\n", format_args!($($arg)*)) {
                panic!("Failed to write to stderr.\
                    \nOriginal error output: {}\
                    \nSecondary error writing to stderr: {}", format!($($arg)*), e);
            }
            process::exit(1)
        }
    )
}

fn main() {
    let requested_threads: usize = parse_command_line_argument(1, "threads");
    let max_prime: usize = parse_command_line_argument(2, "max_prime");

    let threads = calculate_actual_threads(requested_threads, max_prime);

    let sieve = Sieve {
        threads: threads,
        max_prime: max_prime
    };
    println!("{:?}", sieve);
}

fn parse_command_line_argument<T: FromStr + Bounded + Display>(position: usize, name: &str) -> T {
    match env::args().nth(position) {
        None => err_exit!("Usage: sieve_multithreaded_shared <threads> <max_prime>"),
        Some(val) => match val.parse::<T>() {
            Err(_) => err_exit!("Expected <{}>: {} to be >= 0 and <= {}", name, val, T::max_value()),
            Ok(val) => val
        }
    }
}

fn calculate_actual_threads(requested_threads: usize, max_prime: usize) -> usize {
    let sqrt_prime = (max_prime as f64).sqrt().ceil() as usize;
    cmp::min(sqrt_prime, requested_threads)
}

#[derive(Debug)]
struct Sieve {
    threads: usize,
    max_prime: usize
}<|endoftext|>


<commit_before>extern crate hyper;
extern crate encoding;
extern crate html5ever;

mod lib1;
mod lib2;

use std::io::{self, Write};

use lib1::Company;

fn main() {
    let mut name_code_list : Vec<(String, String)> = Vec::new();
    let mut company_list : Vec<Company> = Vec::new();

    // get code list
    if lib2::get_name_code_list("list.csv", &mut name_code_list) == 0 {
        println!("Read csv fail!");
        return;
    }

    // get company info
    let name_code_list_len = name_code_list.len();
    let mut cnt = 0;
    for (name, code) in name_code_list {
        match lib1::get_values_with_code(&code) {
            Err(_)  => {
                cnt = cnt + 1;
            },
            Ok((roe, per, pbr))   => {
                cnt = cnt + 1;

                company_list.push(Company::new(&name, &code, roe, per, pbr));

                print!("\r[{}/{}]", cnt, name_code_list_len);
                io::stdout().flush().unwrap();
            }
        };
    }

    // compose candidate list
    for item in company_list {
        // filtering
        // - pbr, per, roe 중 하나라도 정보가 없으면 아웃.
        if item.roe() <= 0.0 || item.per() <= 0.0 || item.pbr() <= 0.0 {
            continue;
        }
        // 2. pbr 이 1.0 보다 크면 아웃.
        if item.pbr() > 1.0 {
            continue;
        }
        // 3. roe 가 1.1 보다 작으면 아웃.
        if item.roe() < 11.0 {
            continue;
        }

        // print out candidate
        println!("\r\n{}, {}, ROE[{}], PER[{}], PBR[{}]",
            item.name(), item.code(), item.roe(), item.per(), item.pbr());
    }
}
<commit_msg>출력 포맷 수정<commit_after>extern crate hyper;
extern crate encoding;
extern crate html5ever;

mod lib1;
mod lib2;

use std::io::{self, Write};

use lib1::Company;

fn main() {
    let mut name_code_list : Vec<(String, String)> = Vec::new();
    let mut company_list : Vec<Company> = Vec::new();

    // get code list
    if lib2::get_name_code_list("list.csv", &mut name_code_list) == 0 {
        println!("Read csv fail!");
        return;
    }

    // get company info
    let name_code_list_len = name_code_list.len();
    let mut cnt = 0;
    for (name, code) in name_code_list {
        match lib1::get_values_with_code(&code) {
            Err(_)  => {
                cnt = cnt + 1;
            },
            Ok((roe, per, pbr))   => {
                cnt = cnt + 1;

                company_list.push(Company::new(&name, &code, roe, per, pbr));

                print!("\r[{}/{}]", cnt, name_code_list_len);
                io::stdout().flush().unwrap();
            }
        };
    }

    println!("");

    // compose candidate list
    for item in company_list {
        // filtering
        // - pbr, per, roe 중 하나라도 정보가 없으면 아웃.
        if item.roe() <= 0.0 || item.per() <= 0.0 || item.pbr() <= 0.0 {
            continue;
        }
        // 2. pbr 이 1.0 보다 크면 아웃.
        if item.pbr() > 1.0 {
            continue;
        }
        // 3. roe 가 1.1 보다 작으면 아웃.
        if item.roe() < 11.0 {
            continue;
        }

        // print out candidate
        println!("{}, {}, ROE[{}], PER[{}], PBR[{}]",
            item.name(), item.code(), item.roe(), item.per(), item.pbr());
    }
}
<|endoftext|>


<commit_before>extern crate ordered_float;
extern crate thrift;
extern crate try_from;

mod kv_server;
use std::collections::HashMap;
use std::convert::{From, Into};
use std::default::Default;

use thrift::server::TServer;
use std::cell::RefCell;
use std::rc::Rc;
use thrift::protocol::{TInputProtocolFactory, TOutputProtocolFactory};
use thrift::protocol::{TCompactInputProtocolFactory, TCompactOutputProtocolFactory};
use thrift::transport::{TFramedReadTransportFactory, TFramedWriteTransportFactory};
use kv_server::{KeyNotFound, ServiceException};
use kv_server::{KVObject};
use kv_server::{KVServerSyncHandler, KVServerSyncProcessor};

fn main() {
    match run() {
        Ok(()) => println!("tutorial server ran successfully"),
        Err(e) => {
            println!("tutorial server failed with error {:?}", e);
            std::process::exit(1);
        }
    }
}

fn run() -> thrift::Result<()> {

    let listen_address = format!("127.0.0.1:6677");

    println!("binding to {}", listen_address);

    let i_tran_fact: Box<TFramedReadTransportFactory> = Box::new(TFramedReadTransportFactory::new());
    let i_prot_fact: Box<TInputProtocolFactory> = Box::new(TCompactInputProtocolFactory::new());

    let o_tran_fact: Box<TFramedWriteTransportFactory> = Box::new(TFramedWriteTransportFactory::new());
    let o_prot_fact: Box<TOutputProtocolFactory> = Box::new(TCompactOutputProtocolFactory::new());

    // demux incoming messages
    let processor = KVServerSyncProcessor::new(KVServer { ..Default::default() });

    // create the server and start listening
    let mut server = TServer::new(i_tran_fact,
                                        i_prot_fact,
                                        o_tran_fact,
                                        o_prot_fact,
                                        processor,
                                        10);

    server.listen(&listen_address)
}

struct KVServer {
    log: HashMap<i32, KVObject>,
}

impl Default for KVServer {
    fn default() -> KVServer {
        KVServer { log: HashMap::new() }
    }
}

impl KVServerSyncHandler for KVServer {
    fn handle_set_key(&self, kv: kv_server::KVObject) -> std::result::Result<bool, thrift::Error> {
         unimplemented!();
    }

    fn handle_get_val(&self, key: String)  -> std::result::Result<std::string::String, thrift::Error>{
         unimplemented!();
    }

    fn handle_get_obj(&self, key: String)  -> std::result::Result<kv_server::KVObject, thrift::Error>{
         unimplemented!();
    }

    fn handle_del_key(&self, key: String) -> std::result::Result<(), thrift::Error> {
         unimplemented!();
    }
}
<commit_msg>Add logic for set_key, get_val and get_obj<commit_after>extern crate ordered_float;
extern crate thrift;
extern crate try_from;

mod kv_server;
use std::collections::HashMap;
use std::convert::{From, Into};
use std::default::Default;

use thrift::server::TServer;
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::RwLock;
use std::result::Result;
use std::ops::{DerefMut, Deref};
use thrift::protocol::{TInputProtocolFactory, TOutputProtocolFactory};
use thrift::protocol::{TCompactInputProtocolFactory, TCompactOutputProtocolFactory};
use thrift::transport::{TFramedReadTransportFactory, TFramedWriteTransportFactory};
use kv_server::{KeyNotFound, ServiceException};
use kv_server::{KVObject};
use kv_server::{KVServerSyncHandler, KVServerSyncProcessor};

fn main() {
    match run() {
        Ok(()) => println!("tutorial server ran successfully"),
        Err(e) => {
            println!("tutorial server failed with error {:?}", e);
            std::process::exit(1);
        }
    }
}

fn run() -> thrift::Result<()> {

    let listen_address = format!("127.0.0.1:6677");

    println!("binding to {}", listen_address);

    let i_tran_fact: Box<TFramedReadTransportFactory> = Box::new(TFramedReadTransportFactory::new());
    let i_prot_fact: Box<TInputProtocolFactory> = Box::new(TCompactInputProtocolFactory::new());

    let o_tran_fact: Box<TFramedWriteTransportFactory> = Box::new(TFramedWriteTransportFactory::new());
    let o_prot_fact: Box<TOutputProtocolFactory> = Box::new(TCompactOutputProtocolFactory::new());

    // demux incoming messages
    let processor = KVServerSyncProcessor::new(KVServer { ..Default::default() });

    // create the server and start listening
    let mut server = TServer::new(i_tran_fact,
                                        i_prot_fact,
                                        o_tran_fact,
                                        o_prot_fact,
                                        processor,
                                        10);

    server.listen(&listen_address)
}

struct KVStore {
    store: HashMap<String, String>,
}

impl KVStore{
    fn new() -> KVStore {
        KVStore{store: HashMap::new()}
    }
}

struct KVServer {
    store: RwLock<KVStore>
}

impl Default for KVServer {
    fn default() -> KVServer {
        KVServer { store: RwLock::new(KVStore::new()) }
    }
}

impl KVServerSyncHandler for KVServer {
    fn handle_set_key(&self, kv: kv_server::KVObject) -> Result<bool, thrift::Error> {
        let key = kv.key.unwrap();
        let value = kv.value.unwrap();
        println!("Storing value: {}  into key: {}", value, key);
        let mut store = self.store.write().unwrap();
        {
            let w_store = store.deref_mut();
            w_store.store.insert(key, value);
        }
        Ok(true)
    }

    fn handle_get_val(&self, key: String)  -> Result<std::string::String, thrift::Error>{
         let store = self.store.read().unwrap();
         let r_store = store.deref();
         if r_store.store.contains_key(&key) {
             let val = r_store.store.get(&key).unwrap().clone();
             Ok(val)
         } else {
             Err(thrift::Error::from(KeyNotFound{ key: Some(key) }))
         }
    }

    fn handle_get_obj(&self, key: String)  -> Result<kv_server::KVObject, thrift::Error> {
        let store = self.store.read().unwrap();
        let r_store = store.deref();
        if r_store.store.contains_key(&key) {
            let val = r_store.store.get(&key).unwrap().clone();
            let obj = kv_server::KVObject{key: Some(key), value: Some(val)};
            Ok(obj)
        } else {
            Err(thrift::Error::from(KeyNotFound{ key: Some(key) }))
        }
    }

    fn handle_del_key(&self, key: String) -> Result<(), thrift::Error> {
         unimplemented!();
    }
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate errno;

use std::io::Write;

const ETH_P_ARP: libc::c_int = 0x0806;

fn main() {
    let mut args = std::env::args();
    if args.len() != 3 {
        std::io::stderr().write("Usage: arpmasqd LISTEN_ADDR SEND_ADDR\n".as_ref()).unwrap();
        panic!("number of arguments");
    }
    let listen_addr = args.next();
    let send_addr = args.next();
    let listen_socket = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_RAW, ETH_P_ARP.to_be()) };
    if listen_socket == -1 {
        let err = errno::errno();
        panic!("Error opening socket: {} ({})", err, err.0);
    }
    let bind_result = unsafe { libc::bind(listen_socket, &listen_sockaddr, std::mem::size_of_val(listen_sockaddr)) };
    if bind_result == -1 {
        let err = errno::errno();
        panic!("Error binding socket: {} ({})", err, err.0);
    }
}
<commit_msg>Actually working socket binding<commit_after>#![feature(slice_bytes)]

extern crate libc;
extern crate errno;

use std::io::Write;

const ETH_P_ARP: u16 = 0x0806;
const IFNAMSIZ: usize = 16; // net/if.h
const SIOCGIFINDEX: libc::c_int = 0x8933;

#[allow(non_camel_case_types)]
struct ifreq {
    ifr_name: [u8; IFNAMSIZ],
    ifr_ifindex: libc::c_int
}

fn ifindex_from_ifname(ifname: &str, sock: libc::c_int) -> libc::c_int {
    let mut ifr = ifreq {
        ifr_name: [0; IFNAMSIZ],
        ifr_ifindex: 0
    };
    std::slice::bytes::copy_memory(ifname.as_bytes(), &mut ifr.ifr_name);
    if unsafe { libc::funcs::bsd44::ioctl(sock, SIOCGIFINDEX, &ifr) } == -1 {
        let err = errno::errno();
        panic!("Error getting ifindex: {} ({})", err, err.0);
    }
    return ifr.ifr_ifindex;

}

fn main() {
    let mut args = std::env::args();
    if args.len() != 3 {
        std::io::stderr().write("Usage: arpmasqd LISTEN_ADDR SEND_ADDR\n".as_ref()).unwrap();
        panic!("number of arguments");
    }
    args.next();
    //unwrap is ok because arg count has been checked
    let listen_iface = args.next().unwrap();
    let send_addr = args.next().unwrap();
    let listen_socket = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_RAW, ETH_P_ARP.to_be() as i32) };
    if listen_socket == -1 {
        let err = errno::errno();
        panic!("Error opening socket: {} ({})", err, err.0);
    }
    let listen_sockaddr = libc::sockaddr_ll {
        sll_family: libc::AF_PACKET as u16,
        sll_protocol: ETH_P_ARP.to_be(),
        sll_ifindex: ifindex_from_ifname(&listen_iface, listen_socket),
        sll_hatype: 0,
        sll_pkttype: 0,
        sll_halen: 0,
        sll_addr: [0; 8]
    };
    let bind_result = unsafe { libc::bind(listen_socket, std::mem::transmute(&listen_sockaddr), std::mem::size_of_val(&listen_sockaddr) as u32) };
    if bind_result == -1 {
        let err = errno::errno();
        panic!("Error binding socket: {} ({})", err, err.0);
    }
}
<|endoftext|>


<commit_before>/* main.rs - Main source file for mymdb
 * (c) 2016 Zack Hixon under MIT license.
 * See LICENSE.txt for more details. */

extern crate rusqlite;
extern crate time;
extern crate rand;
extern crate regex;

use time::Timespec;
use rusqlite::Connection;
use std::io;
use std::path::Path;
use std::env;
use regex::Regex;

#[derive(Debug)]
struct Movie {
    id: i32,
    name: String,
    time_created: Timespec,
    opinion: String,
    rating: i32
}

impl Movie {
    fn new(id: i32, name: String, time_created: Timespec, opinion: String, rating: i32) -> Movie {
        Movie {
            id: id,
            name: name,
            time_created: time_created,
            opinion: opinion,
            rating: rating,
        }
    }

    fn get_name(self) -> String {
        self.name
    }

    fn get_opinion(self) -> String {
        self.opinion
    }

    fn get_id(self) -> i32 {
        self.id
    }

    fn get_rating(self) -> i32 {
        self.rating
    }

    fn get_time(self) -> Timespec {
        self.time_created
    }
}

fn main() {
    let conn = Connection::open(Path::new(".movies.db")).unwrap();

    conn.execute("CREATE TABLE IF NOT EXISTS movies (
        id INTEGER UNIQUE NOT NULL,
        name TEXT NOT NULL,
        time_created TEXT NOT NULL,
        opinion TEXT NOT NULL,
        rating INTEGER)", &[]).unwrap();
    let args: Vec<String> = env::args().collect();
    let length = args.len();

    if length == 1 {
        println!("for help, use \"mymdb help\"");
    }
    else if length == 2 {
        for i in &args {
            if i == "help" { print_help(); }
            else if i == "add" {
                let newMovie = new_movie();
                conn.execute("INSERT INTO movies VALUES ($1, $2, $3, $4, $5)",
                    &[&newMovie.id, &newMovie.name, &newMovie.time_created,
                    &newMovie.opinion, &newMovie.rating]).unwrap();
                println!("Your movie has been added. ID# {}", &newMovie.id);
            }
            else if i == "remove" {
                println!("ID of movie to be removed: (number)");
                let id: i32 = number_input();

                let mut stmt = conn.prepare("SELECT * FROM movies WHERE id=$1").unwrap();
                let mut movie_iter = stmt.query_map(&[&id,], |row| {
                    Movie {
                        id: row.get(0),
                        name: row.get(1),
                        time_created: row.get(2),
                        opinion: row.get(3),
                        rating: row.get(4)
                    }
                }).unwrap();

                let mut q = Movie::new(0, String::new(), time::get_time(), String::new(), 0);
                for i in movie_iter {
                    q = i.unwrap();
                }

                if q.name.is_empty() {
                    println!("Cannot find movie with ID of {}", id);
                    return
                }

                println!("Are you sure you want to remove {}?", q.name.trim());

                let resp1 = get_input();
                let resp2 = resp1.to_lowercase();
                let resp = resp2.trim();

                if resp == String::from("yes") {
                    conn.execute("DELETE FROM movies WHERE id=$1", &[&id,]).unwrap();
                    println!("{} has been removed from the database.", q.name.trim());
                } else if resp == String::from("y") {
                    conn.execute("DELETE FROM movies WHERE id=$1", &[&id,]).unwrap();
                    println!("{} has been removed from the database.", q.name.trim());
                } else {
                    println!("Movie will not be removed.");
                }
            }
            else if i == "show" {
                let mut stmt = conn.prepare("SELECT * FROM movies").unwrap();
                let mut movie_iter = stmt.query_map(&[], |row| {
                    Movie {
                        id: row.get(0),
                        name: row.get(1),
                        time_created: row.get(2),
                        opinion: row.get(3),
                        rating: row.get(4)
                    }
                }).unwrap();

                let mut count = 0;
                let mut movies: Vec<Movie> = vec![];
                for movie in movie_iter {
                    movies.push(movie.unwrap());
                    count = count + 1;
                }

                println!("Found {} movie(s)", count);

                for z in movies {
                    println!("Name:    {}\nOpinion: {}\nRating:  {}\nID:      {}\nTime:    {}\n",
                             z.name.trim(),
                             z.opinion.trim(),
                             z.rating,
                             z.id,
                             time(z.time_created));
                }
            }
            else {
                // TODO: make this not ridiculous
                let re = Regex::new(r"mymdb").unwrap();
                if !re.is_match(&i) {
                    println!("Not an option: {}", i);
                } else {
                    continue;
                }
            }
        }
    }
    else {
        let mut arg3: &String = &String::from("");
        let mut arg4: &String = &String::from("");
        let mut arg5: i32 = 0;
        if length >= 3 {
            arg3 = &args[2];
        }
        if length == 5 {
            arg4 = &args[3];
            arg5 = args[4].trim().parse().expect("3rd arg must be a number");
        }
        for i in &args {
            if i == "-a" {
                let id = rand::random::<i32>().abs() / 1000;
                conn.execute("INSERT INTO movies VALUES ($1, $2, $3, $4, $5)",
                    &[&id, arg3, &(time::get_time()),
                    arg4, &arg5]).unwrap();
                println!("Your movie has been added. ID# {}", id);
            }
            else if i == "-r" {
                let id: i32 = arg3.trim().parse().expect("arg must be a number");

                let mut stmt = conn.prepare("SELECT * FROM movies WHERE id=$1").unwrap();
                let mut movie_iter = stmt.query_map(&[&id,], |row| {
                    Movie {
                        id: row.get(0),
                        name: row.get(1),
                        time_created: row.get(2),
                        opinion: row.get(3),
                        rating: row.get(4)
                    }
                }).unwrap();

                let mut q = Movie::new(0, String::new(), time::get_time(), String::new(), 0);
                for i in movie_iter {
                    q = i.unwrap();
                }

                if q.name.is_empty() {
                    println!("Cannot find movie with ID of {}", id);
                    return
                }

                conn.execute("DELETE FROM movies WHERE id=$1", &[&id,]).unwrap();
                println!("{} has been removed from the database.", q.name.trim());
            }
        }
    }
}

fn new_movie() -> Movie {
    println!("Name of movie:");
    let name: String = get_input();

    println!("Thoughts:");
    let opinion: String = get_input();

    println!("Rating: (number)");
    let rating: i32 = number_input();

    Movie::new(rand::random::<i32>().abs() / 1000, name,
        time::get_time(), opinion, rating)
}

fn time(t: Timespec) -> String {
    let real_time = time::at(t);
    String::from(format!("{}-{}-{} {}:{}", (real_time.tm_year + 1900), real_time.tm_mon,
                 real_time.tm_mday, real_time.tm_hour, real_time.tm_min))
}

fn print_help() {
    println!("mymdb - personal movie database");
    println!("usage:");
    println!("mymdb <command> [options]");
    println!("commands:");
    println!("\tshow - lists movies in database");
    println!("\tadd - adds movie to database (interactively)");
    println!("\tremove - removes movie from database (interactively)");
    println!("options:");
    println!("\t-r <movie ID> - removes movie from database");
    println!("\t-a <movie name> <opinion> <rating>");
    println!("mymdb creates a movie database that the program is run in.");
    println!("It looks for a sqlite file called .movies.db, and if it does");
    println!("not exist, it is created automatically.");
}

fn number_input() -> i32 {
    let n = match get_input().trim().parse::<i32>() {
        Ok(n) => n,
        Err(e) => { println!("Not a number"); 0 },
    };

    n
}

fn get_input() -> String {
    let mut i = String::new();
    let handle = io::stdin();

    match handle.read_line(&mut i) {
        Ok(n) => {},
        Err(e) => println!("What's your problem?")
    }

    i
}
<commit_msg>fix embarassing errors<commit_after>/* main.rs - Main source file for mymdb
 * (c) 2016 Zack Hixon under MIT license.
 * See LICENSE.txt for more details. */

extern crate rusqlite;
extern crate time;
extern crate rand;
extern crate regex;

use time::Timespec;
use rusqlite::Connection;
use std::io;
use std::path::Path;
use std::env;
use regex::Regex;

#[derive(Debug)]
struct Movie {
    id: i32,
    name: String,
    time_created: Timespec,
    opinion: String,
    rating: i32
}

impl Movie {
    fn new(id: i32, name: String, time_created: Timespec, opinion: String, rating: i32) -> Movie {
        Movie {
            id: id,
            name: name,
            time_created: time_created,
            opinion: opinion,
            rating: rating,
        }
    }

    /*
    fn get_name(self) -> String {
        self.name
    }

    fn get_opinion(self) -> String {
        self.opinion
    }

    fn get_id(self) -> i32 {
        self.id
    }

    fn get_rating(self) -> i32 {
        self.rating
    }

    fn get_time(self) -> Timespec {
        self.time_created
    }
    */
}

fn main() {
    let conn = Connection::open(Path::new(".movies.db")).unwrap();

    conn.execute("CREATE TABLE IF NOT EXISTS movies (
        id INTEGER UNIQUE NOT NULL,
        name TEXT NOT NULL,
        time_created TEXT NOT NULL,
        opinion TEXT NOT NULL,
        rating INTEGER)", &[]).unwrap();
    let args: Vec<String> = env::args().collect();
    let length = args.len();

    if length == 1 {
        println!("for help, use \"mymdb help\"");
    }
    else if length == 2 {
        for i in &args {
            if i == "help" { print_help(); }
            else if i == "add" {
                let new_movie = new_movie();
                conn.execute("INSERT INTO movies VALUES ($1, $2, $3, $4, $5)",
                    &[&new_movie.id, &new_movie.name, &new_movie.time_created,
                    &new_movie.opinion, &new_movie.rating]).unwrap();
                println!("Your movie has been added. ID# {}", &new_movie.id);
            }
            else if i == "remove" {
                println!("ID of movie to be removed: (number)");
                let id: i32 = number_input();

                let mut stmt = conn.prepare("SELECT * FROM movies WHERE id=$1").unwrap();
                let movie_iter = stmt.query_map(&[&id,], |row| {
                    Movie {
                        id: row.get(0),
                        name: row.get(1),
                        time_created: row.get(2),
                        opinion: row.get(3),
                        rating: row.get(4)
                    }
                }).unwrap();

                let mut q = Movie::new(0, String::new(), time::get_time(), String::new(), 0);
                for i in movie_iter {
                    q = i.unwrap();
                }

                if q.name.is_empty() {
                    println!("Cannot find movie with ID of {}", id);
                    return
                }

                println!("Are you sure you want to remove {}?", q.name.trim());

                let resp1 = get_input();
                let resp2 = resp1.to_lowercase();
                let resp = resp2.trim();

                if resp == String::from("yes") {
                    conn.execute("DELETE FROM movies WHERE id=$1", &[&id,]).unwrap();
                    println!("{} has been removed from the database.", q.name.trim());
                } else if resp == String::from("y") {
                    conn.execute("DELETE FROM movies WHERE id=$1", &[&id,]).unwrap();
                    println!("{} has been removed from the database.", q.name.trim());
                } else {
                    println!("Movie will not be removed.");
                }
            }
            else if i == "show" {
                let mut stmt = conn.prepare("SELECT * FROM movies").unwrap();
                let movie_iter = stmt.query_map(&[], |row| {
                    Movie {
                        id: row.get(0),
                        name: row.get(1),
                        time_created: row.get(2),
                        opinion: row.get(3),
                        rating: row.get(4)
                    }
                }).unwrap();

                let mut count = 0;
                let mut movies: Vec<Movie> = vec![];
                for movie in movie_iter {
                    movies.push(movie.unwrap());
                    count = count + 1;
                }

                println!("Found {} movie(s)", count);

                for z in movies {
                    println!("Name:    {}\nOpinion: {}\nRating:  {}\nID:      {}\nTime:    {}\n",
                             z.name.trim(),
                             z.opinion.trim(),
                             z.rating,
                             z.id,
                             time(z.time_created));
                }
            }
            else {
                // TODO: make this not ridiculous
                let re = Regex::new(r"mymdb").unwrap();
                if !re.is_match(&i) {
                    println!("Not an option: {}", i);
                } else {
                    continue;
                }
            }
        }
    }
    else {
        let mut arg3: &String = &String::from("");
        let mut arg4: &String = &String::from("");
        let mut arg5: i32 = 0;
        if length >= 3 {
            arg3 = &args[2];
        }
        if length == 5 {
            arg4 = &args[3];
            arg5 = args[4].trim().parse().expect("3rd arg must be a number");
        }
        for i in &args {
            if i == "-a" {
                let id = rand::random::<i32>().abs() / 1000;
                conn.execute("INSERT INTO movies VALUES ($1, $2, $3, $4, $5)",
                    &[&id, arg3, &(time::get_time()),
                    arg4, &arg5]).unwrap();
                println!("Your movie has been added. ID# {}", id);
            }
            else if i == "-r" {
                let id: i32 = arg3.trim().parse().expect("arg must be a number");

                let mut stmt = conn.prepare("SELECT * FROM movies WHERE id=$1").unwrap();
                let movie_iter = stmt.query_map(&[&id,], |row| {
                    Movie {
                        id: row.get(0),
                        name: row.get(1),
                        time_created: row.get(2),
                        opinion: row.get(3),
                        rating: row.get(4)
                    }
                }).unwrap();

                let mut q = Movie::new(0, String::new(), time::get_time(), String::new(), 0);
                for i in movie_iter {
                    q = i.unwrap();
                }

                if q.name.is_empty() {
                    println!("Cannot find movie with ID of {}", id);
                    return
                }

                conn.execute("DELETE FROM movies WHERE id=$1", &[&id,]).unwrap();
                println!("{} has been removed from the database.", q.name.trim());
            }
        }
    }
}

fn new_movie() -> Movie {
    println!("Name of movie:");
    let name: String = get_input();

    println!("Thoughts:");
    let opinion: String = get_input();

    println!("Rating: (number)");
    let rating: i32 = number_input();

    Movie::new(rand::random::<i32>().abs() / 1000, name,
        time::get_time(), opinion, rating)
}

fn time(t: Timespec) -> String {
    let real_time = time::at(t);
    String::from(format!("{}-{}-{} {}:{}", (real_time.tm_year + 1900), real_time.tm_mon,
                 real_time.tm_mday, real_time.tm_hour, real_time.tm_min))
}

fn print_help() {
    println!("mymdb - personal movie database");
    println!("usage:");
    println!("mymdb <command> [options]");
    println!("commands:");
    println!("\tshow - lists movies in database");
    println!("\tadd - adds movie to database (interactively)");
    println!("\tremove - removes movie from database (interactively)");
    println!("options:");
    println!("\t-r <movie ID> - removes movie from database");
    println!("\t-a <movie name> <opinion> <rating>");
    println!("mymdb creates a movie database that the program is run in.");
    println!("It looks for a sqlite file called .movies.db, and if it does");
    println!("not exist, it is created automatically.");
}

fn number_input() -> i32 {
    let n = match get_input().trim().parse::<i32>() {
        Ok(n) => n,
        Err(e) => { println!("Not a number"); 0 },
    };

    n
}

fn get_input() -> String {
    let mut i = String::new();
    let handle = io::stdin();

    match handle.read_line(&mut i) {
        Ok(n) => {},
        Err(e) => println!("What's your problem?")
    }

    i
}
<|endoftext|>


<commit_before>extern crate image;
extern crate clap;
extern crate rand;
extern crate itertools;

use clap::*;

mod codec;

mod rgba;

mod utils;

fn main()
{
    let matches = App::new("stag")
        .version("0.0.1")
        .about("Image steganography")
        .subcommand(SubCommand::with_name("encode")
            .about("encodes a file")
            .arg(Arg::with_name("mode")
                 .short("m")
                 .long("mode")
                 .value_name("MODE")
                 .help("Set the encoding mode, default depends on SOURCE type")
                 .takes_value(true))
            .arg(Arg::with_name("SOURCE")
                 .help("The image source")
                 .index(1)
                 .required(true))
            .arg(Arg::with_name("OUTPUT")
                 .help("The output image")
                 .index(2)
                 .required(true)))
        .subcommand(SubCommand::with_name("decode")
            .about("decodes a file")
            .arg(Arg::with_name("mode")
                 .short("m")
                 .long("mode")
                 .value_name("MODE")
                 .help("Set the decoding mode, default depends on SOURCE type")
                 .takes_value(true))
            .arg(Arg::with_name("SOURCE")
                 .help("The image source")
                 .index(1)
                 .required(true))
            .arg(Arg::with_name("length")
                 .short("l")
                 .long("length")
                 .help("the amount of bytes to decode")
                 .required(true)))
        .subcommand(SubCommand::with_name("estimate")
                .about("estimate how many bytes will fit into a file")
                .arg(Arg::with_name("SOURCE")
                     .help("The image source")
                     .index(1)
                     .takes_value(true))
                .arg(Arg::with_name("mode")
                     .short("m")
                     .long("mode")
                     .value_name("MODE")
                     .help("The encoding mode, default depends on SOURCE type")
                     .takes_value(true)))
        .get_matches();

    if let Some(matches) = matches.subcommand_matches("encode")
    {
        dispatch_encode(
            matches.value_of("mode"),
            matches.value_of("SOURCE").unwrap(),
            matches.value_of("OUTPUT").unwrap()
        );
    }

    if let Some(matches) = matches.subcommand_matches("decode")
    {
        dispatch_decode(
            matches.value_of("mode"),
            matches.value_of("SOURCE").unwrap(),
            matches.value_of("length").unwrap()
        );
    }

    if let Some(matches) = matches.subcommand_matches("estimate")
    {
        dispatch_estimate(
            matches.value_of("mode"),
            matches.value_of("SOURCE").unwrap()
        );
    }
}

use std::io::{stdin, stdout, Read, Write};
use std::str::FromStr;

use image::{open, DynamicImage};
use rand::StdRng;

use codec::Codec;
use rgba::RgbaCodec;

fn dispatch_encode(mode: Option<&str>, source: &str, output: &str)
{
    let dyimage = match open(source)
    {
        Ok(di) => di,
        Err(_) => error_out("Error opening source image for encoding")
    };

    match dyimage
    {
        DynamicImage::ImageRgba8(image) =>
        {
            match encode::<RgbaCodec>(image, mode).save(output)
            {
                Ok(_) => {},
                Err(_) => error_out("Error saving encoded output file"),
            };
        },
        _ => error_out("Unsupported filetype"),
    }
}

fn dispatch_decode(mode: Option<&str>, source: &str, len: &str)
{
    let len = match len.parse::<usize>()
    {
        Ok(l) => l,
        Err(_) => error_out("len argument to decode is not a number"),
    };

    let dyimage = match open(source)
    {
        Ok(di) => di,
        Err(_) => error_out("Error opening source image for decoding"),
    };

    match dyimage
    {
        DynamicImage::ImageRgba8(image) =>
        {
            decode::<RgbaCodec>(image, mode, len);
        },
        _ => error_out("Unsupported filetype"),
    }
}

fn dispatch_estimate(mode: Option<&str>, source: &str)
{
    let dyimage = match open(source)
    {
        Ok(di) => di,
        Err(_) => error_out("Error opening source image for estimating"),
    };

    match dyimage
    {
        DynamicImage::ImageRgba8(image) =>
        {
            estimate::<RgbaCodec>(image, mode);
        },
        _ => error_out("Unsupported filetype"),
    }
}

fn encode<C: Codec>(mut image: C::Input, mode: Option<&str>) -> C::Input
{
    let mode = if let Some(mode) = mode
    {
        match C::Mode::from_str(mode)
        {
            Ok(mode) => mode,
            Err(_) => error_out("Error parsing mode string"),
        }
    }
    else
    {
        C::Mode::default()
    };

    let rng = match StdRng::new()
    {
        Ok(r) => r,
        Err(_) => error_out("Error creating source of randomness"),
    };

    let mut payload = String::new();
    stdin().read_to_string(&mut payload).unwrap();

    C::encode(&mut image, payload.as_bytes(), mode, rng);

    image
}

fn decode<C: Codec>(image: C::Input, mode: Option<&str>, len: usize)
{
    let mode = if let Some(mode) = mode
    {
        match C::Mode::from_str(mode)
        {
            Ok(mode) => mode,
            Err(_) => error_out("Error parsing mode string"),
        }
    }
    else
    {
        C::Mode::default()
    };

    let mut buf = vec![0; len];

    C::decode(&image, &mut buf, len, mode);

    match stdout().write(&buf)
    {
        Ok(_) => {},
        Err(_) => error_out("Error writing decoded payload"),
    };
}

fn estimate<C: Codec>(image: C::Input, mode: Option<&str>)
{
    let mode = if let Some(mode) = mode
    {
        match C::Mode::from_str(mode)
        {
            Ok(mode) => mode,
            Err(_) => error_out("Error parsing mode string"),
        }
    }
    else
    {
        C::Mode::default()
    };

    match C::estimate(&image, mode)
    {
        Some(i) => println!("Estimate {} bytes", i),
        None => println!("Could not make an estimate"),
    }
}

fn error_out(msg: &str) -> !
{
    eprintln!("{}", msg);
    ::std::process::exit(1)
}
<commit_msg>Fixed decoding not taking a length<commit_after>extern crate image;
extern crate clap;
extern crate rand;
extern crate itertools;

use clap::*;

mod codec;

mod rgba;

mod utils;

fn main()
{
    let matches = App::new("stag")
        .version("0.0.1")
        .about("Image steganography")
        .subcommand(SubCommand::with_name("encode")
            .about("encodes a file")
            .arg(Arg::with_name("mode")
                 .short("m")
                 .long("mode")
                 .value_name("MODE")
                 .help("Set the encoding mode, default depends on SOURCE type")
                 .takes_value(true))
            .arg(Arg::with_name("SOURCE")
                 .help("The image source")
                 .index(1)
                 .required(true))
            .arg(Arg::with_name("OUTPUT")
                 .help("The output image")
                 .index(2)
                 .required(true)))
        .subcommand(SubCommand::with_name("decode")
            .about("decodes a file")
            .arg(Arg::with_name("mode")
                 .short("m")
                 .long("mode")
                 .value_name("MODE")
                 .help("Set the decoding mode, default depends on SOURCE type")
                 .takes_value(true))
            .arg(Arg::with_name("SOURCE")
                 .help("The image source")
                 .index(1)
                 .required(true))
            .arg(Arg::with_name("length")
                 .short("l")
                 .long("length")
                 .help("the amount of bytes to decode")
                 .value_name("LENGTH")
                 .takes_value(true)
                 .required(true)))
        .subcommand(SubCommand::with_name("estimate")
                .about("estimate how many bytes will fit into a file")
                .arg(Arg::with_name("SOURCE")
                     .help("The image source")
                     .index(1)
                     .takes_value(true))
                .arg(Arg::with_name("mode")
                     .short("m")
                     .long("mode")
                     .value_name("MODE")
                     .help("The encoding mode, default depends on SOURCE type")
                     .takes_value(true)))
        .get_matches();

    if let Some(matches) = matches.subcommand_matches("encode")
    {
        dispatch_encode(
            matches.value_of("mode"),
            matches.value_of("SOURCE").unwrap(),
            matches.value_of("OUTPUT").unwrap()
        );
    }

    if let Some(matches) = matches.subcommand_matches("decode")
    {
        dispatch_decode(
            matches.value_of("mode"),
            matches.value_of("SOURCE").unwrap(),
            matches.value_of("length").unwrap()
        );
    }

    if let Some(matches) = matches.subcommand_matches("estimate")
    {
        dispatch_estimate(
            matches.value_of("mode"),
            matches.value_of("SOURCE").unwrap()
        );
    }
}

use std::io::{stdin, stdout, Read, Write};
use std::str::FromStr;

use image::{open, DynamicImage};
use rand::StdRng;

use codec::Codec;
use rgba::RgbaCodec;

fn dispatch_encode(mode: Option<&str>, source: &str, output: &str)
{
    let dyimage = match open(source)
    {
        Ok(di) => di,
        Err(_) => error_out("Error opening source image for encoding")
    };

    match dyimage
    {
        DynamicImage::ImageRgba8(image) =>
        {
            match encode::<RgbaCodec>(image, mode).save(output)
            {
                Ok(_) => {},
                Err(_) => error_out("Error saving encoded output file"),
            };
        },
        _ => error_out("Unsupported filetype"),
    }
}

fn dispatch_decode(mode: Option<&str>, source: &str, len: &str)
{
    let len = match len.parse::<usize>()
    {
        Ok(l) => l,
        Err(_) => error_out("len argument to decode is not a number"),
    };

    let dyimage = match open(source)
    {
        Ok(di) => di,
        Err(_) => error_out("Error opening source image for decoding"),
    };

    match dyimage
    {
        DynamicImage::ImageRgba8(image) =>
        {
            decode::<RgbaCodec>(image, mode, len);
        },
        _ => error_out("Unsupported filetype"),
    }
}

fn dispatch_estimate(mode: Option<&str>, source: &str)
{
    let dyimage = match open(source)
    {
        Ok(di) => di,
        Err(_) => error_out("Error opening source image for estimating"),
    };

    match dyimage
    {
        DynamicImage::ImageRgba8(image) =>
        {
            estimate::<RgbaCodec>(image, mode);
        },
        _ => error_out("Unsupported filetype"),
    }
}

fn encode<C: Codec>(mut image: C::Input, mode: Option<&str>) -> C::Input
{
    let mode = if let Some(mode) = mode
    {
        match C::Mode::from_str(mode)
        {
            Ok(mode) => mode,
            Err(_) => error_out("Error parsing mode string"),
        }
    }
    else
    {
        C::Mode::default()
    };

    let rng = match StdRng::new()
    {
        Ok(r) => r,
        Err(_) => error_out("Error creating source of randomness"),
    };

    let mut payload = String::new();
    stdin().read_to_string(&mut payload).unwrap();

    C::encode(&mut image, payload.as_bytes(), mode, rng);

    image
}

fn decode<C: Codec>(image: C::Input, mode: Option<&str>, len: usize)
{
    let mode = if let Some(mode) = mode
    {
        match C::Mode::from_str(mode)
        {
            Ok(mode) => mode,
            Err(_) => error_out("Error parsing mode string"),
        }
    }
    else
    {
        C::Mode::default()
    };

    let mut buf = vec![0; len];

    C::decode(&image, &mut buf, len, mode);

    match stdout().write(&buf)
    {
        Ok(_) => {},
        Err(_) => error_out("Error writing decoded payload"),
    };
}

fn estimate<C: Codec>(image: C::Input, mode: Option<&str>)
{
    let mode = if let Some(mode) = mode
    {
        match C::Mode::from_str(mode)
        {
            Ok(mode) => mode,
            Err(_) => error_out("Error parsing mode string"),
        }
    }
    else
    {
        C::Mode::default()
    };

    match C::estimate(&image, mode)
    {
        Some(i) => println!("Estimate {} bytes", i),
        None => println!("Could not make an estimate"),
    }
}

fn error_out(msg: &str) -> !
{
    eprintln!("{}", msg);
    ::std::process::exit(1)
}
<|endoftext|>


<commit_before>extern crate rudit;
extern crate termion;

use std::io::{Write, stdout};
use termion::raw::IntoRawMode;
use termion::event::Key;
use termion::input::TermRead;
use rudit::gapbuffer::GapBuffer;

fn main() {
    let mut buffer = GapBuffer::new(30);
    let mut stdout = stdout().into_raw_mode().unwrap();
    let mut index = 0;
    let mut cx = 1;
    let mut cy = 1;
    write!(stdout,
           "{}{}",
           termion::clear::All,
           termion::cursor::Goto(cx as u16, cy as u16))
        .unwrap();
    stdout.flush().unwrap();
    loop {
        for c in std::io::stdin().keys() {
            match c.unwrap() {
                Key::Char('\n') => {
                    cx = 1;
                    cy += 1;
                }
                Key::Char(c) => {
                    buffer.insert(index, c);
                    index += 1;
                    cx += 1;
                }
                Key::Left => {
                    if cx > 0 {
                        cx -= 1
                    }
                }
                Key::Right => {
                    if cx <= buffer.len() {
                        cx += 1
                    }
                }
                Key::Esc => break,
                _ => (),
            }
            // move cursor
            write!(stdout, "{}", termion::cursor::Goto(cx as u16, cy as u16)).unwrap();
            stdout.flush().unwrap();
        }
        break;
    }
}
<commit_msg>start implement of line drawing<commit_after>extern crate rudit;
extern crate termion;

use std::io::{Write, stdout};
use termion::raw::IntoRawMode;
use termion::event::Key;
use termion::input::TermRead;
use rudit::gapbuffer::GapBuffer;

fn main() {
    let mut buffer = GapBuffer::new(30);
    let mut stdout = stdout().into_raw_mode().unwrap();
    let mut index = 0;
    let mut cx: u16 = 1;
    let mut cy: u16 = 1;
    write!(stdout,
           "{}{}",
           termion::clear::All,
           termion::cursor::Goto(cx, cy))
        .unwrap();
    stdout.flush().unwrap();
    'main: loop {

        write!(stdout, "{}", termion::clear::All).unwrap();
        stdout.flush().unwrap();

        draw_lines(&mut stdout);
        draw_cursor(&mut stdout, cx, cy);

        for c in std::io::stdin().keys() {
            match c.unwrap() {
                Key::Char('\n') => {
                    buffer.insert(index, '\n');
                    cx = 1;
                    cy += 1;
                }
                Key::Char(c) => {
                    buffer.insert(index, c);
                    index += 1;
                    cx += 1;
                }
                Key::Left => {
                    if cx > 0 {
                        cx -= 1
                    }
                }
                Key::Right => {
                    if cx as usize <= buffer.len() {
                        cx += 1
                    }
                }
                Key::Esc => break,
                _ => (),
            }
            continue 'main;
        }
        write!(stdout, "{}", termion::clear::All).unwrap();
        stdout.flush().unwrap();
        break;
    }
}
fn draw_lines(stdout: &mut termion::raw::RawTerminal<std::io::Stdout>) {
    // TODO
    // implement real drawing of buffer lines and line numbers
    for i in 0..5 {
        write!(stdout,
               "{}{}",
               termion::cursor::Goto(0, i + 1),
               (i + 1).to_string())
            .unwrap();
    }
    stdout.flush().unwrap();
}

fn draw_cursor(stdout: &mut termion::raw::RawTerminal<std::io::Stdout>, cx: u16, cy: u16) {
    write!(stdout, "{}", termion::cursor::Goto(cx, cy)).unwrap();
    stdout.flush().unwrap();
}
<|endoftext|>