<commit_before>use std::env;
use std::path::PathBuf;
use std::process;
use std::{cell::RefCell, str::FromStr};

use getopts::Options;
use hprof::Profiler;
use libgir::{self as gir, Config, Library, WorkMode};

fn print_usage(program: &str, opts: Options) {
    let brief = format!(
        "Usage: {program} [options] [<library> <version>]
       {program} (-h | --help)",
        program = program
    );
    print!("{}", opts.usage(&brief));
}

trait OptionStr {
    fn as_str_ref(&self) -> Option<&str>;
}

impl<S: AsRef<str>> OptionStr for Option<S> {
    fn as_str_ref(&self) -> Option<&str> {
        self.as_ref().map(|string| string.as_ref())
    }
}

#[allow(clippy::large_enum_variant)]
enum RunKind {
    Config(Config),
    CheckGirFile(String),
}

fn build_config() -> Result<RunKind, String> {
    let args: Vec<_> = env::args().collect();
    let program = args[0].clone();

    let mut options = Options::new();
    options.optopt(
        "c",
        "config",
        "Config file path (default: Gir.toml)",
        "CONFIG",
    );
    options.optflag("h", "help", "Show this message");
    options.optopt("d", "gir-directory", "Directory for girs", "GIRSPATH");
    options.optopt(
        "m",
        "mode",
        "Work mode: doc, normal, sys or not_bound",
        "MODE",
    );
    options.optopt("o", "target", "Target path", "PATH");
    options.optopt("p", "doc-target-path", "Doc target path", "PATH");
    options.optflag("b", "make-backup", "Make backup before generating");
    options.optflag("s", "stats", "Show statistics");
    options.optflag("", "disable-format", "Disable formatting generated code");
    options.optopt(
        "",
        "check-gir-file",
        "Check if the given `.gir` file is valid",
        "PATH",
    );

    let matches = match options.parse(&args[1..]) {
        Ok(matches) => matches,
        Err(e) => return Err(e.to_string()),
    };

    if let Some(check_gir_file) = matches.opt_str("check-gir-file") {
        return Ok(RunKind::CheckGirFile(check_gir_file));
    }

    if matches.opt_present("h") {
        print_usage(&program, options);
        process::exit(0);
    }

    let work_mode = match matches.opt_str("m") {
        None => None,
        Some(s) => match WorkMode::from_str(&s) {
            Ok(w) => Some(w),
            Err(e) => {
                eprintln!("Error (switching to default work mode): {}", e);
                None
            }
        },
    };

    Config::new(
        matches.opt_str("c").as_str_ref(),
        work_mode,
        matches.opt_str("d").as_str_ref(),
        matches.free.get(0).as_str_ref(),
        matches.free.get(1).as_str_ref(),
        matches.opt_str("o").as_str_ref(),
        matches.opt_str("doc-target-path").as_str_ref(),
        matches.opt_present("b"),
        matches.opt_present("s"),
        matches.opt_present("disable-format"),
    )
    .map(RunKind::Config)
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
    if let Err(ref e) = do_main() {
        eprintln!("{}", e);

        ::std::process::exit(1);
    }
}

fn run_check(check_gir_file: &str) -> Result<(), String> {
    let path = PathBuf::from(check_gir_file);
    if !path.is_file() {
        return Err(format!("`{}`: file not found", check_gir_file));
    }
    let lib_name = path
        .file_stem()
        .ok_or(format!("Failed to get file stem from `{}`", check_gir_file))?;
    let lib_name = lib_name
        .to_str()
        .ok_or("failed to convert OsStr to str".to_owned())?;
    let mut library = Library::new(lib_name);
    let parent = path.parent().ok_or(format!(
        "Failed to get parent directory from `{}`",
        check_gir_file
    ))?;

    library.read_file(&parent, &mut vec![lib_name.to_owned()])
}

fn do_main() -> Result<(), String> {
    if std::env::var_os("RUST_LOG").is_none() {
        std::env::set_var("RUST_LOG", "gir=warn");
        std::env::set_var("RUST_LOG", "libgir=warn");
    }
    env_logger::init();

    let mut cfg = match build_config() {
        Ok(RunKind::CheckGirFile(check_gir_file)) => return run_check(&check_gir_file),
        Ok(RunKind::Config(cfg)) => cfg,
        Err(err) => return Err(err),
    };
    cfg.check_disable_format();

    let statistics = Profiler::new("Gir");
    statistics.start_frame();

    let watcher_total = statistics.enter("Total");

    let mut library = {
        let _watcher = statistics.enter("Loading");

        let mut library = Library::new(&cfg.library_name);
        library.read_file(&cfg.girs_dir, &mut vec![cfg.library_full_name()])?;
        library
    };

    {
        let _watcher = statistics.enter("Preprocessing");
        library.preprocessing(cfg.work_mode);
    }

    {
        let _watcher = statistics.enter("Update library by config");
        gir::update_version::apply_config(&mut library, &cfg);
    }

    {
        let _watcher = statistics.enter("Postprocessing");
        library.postprocessing(&cfg);
    }

    {
        let _watcher = statistics.enter("Resolving type ids");
        cfg.resolve_type_ids(&library);
    }

    {
        let _watcher = statistics.enter("Checking versions");
        gir::update_version::check_function_real_version(&mut library);
    }

    let mut env = {
        let _watcher = statistics.enter("Namespace/symbol/class analysis");

        let namespaces = gir::namespaces_run(&library);
        let symbols = gir::symbols_run(&library, &namespaces);
        let class_hierarchy = gir::class_hierarchy_run(&library);

        gir::Env {
            library,
            config: cfg,
            namespaces,
            symbols: RefCell::new(symbols),
            class_hierarchy,
            analysis: Default::default(),
        }
    };

    if env.config.work_mode != WorkMode::Sys {
        let _watcher = statistics.enter("Analyzing");
        gir::analysis_run(&mut env);
    }

    if env.config.work_mode != WorkMode::DisplayNotBound {
        let _watcher = statistics.enter("Generating");
        gir::codegen_generate(&env);
    }

    if !env.config.disable_format && env.config.work_mode.is_generate_rust_files() {
        let _watcher = statistics.enter("Formatting");
        gir::fmt::format(&env.config.target_path);
    }

    drop(watcher_total);
    statistics.end_frame();

    if env.config.show_statistics {
        statistics.print_timing();
    }
    if env.config.work_mode == WorkMode::DisplayNotBound {
        env.library.show_non_bound_types(&env);
    }

    Ok(())
}
<commit_msg>Simplify Err => return Err() into .map_err()?<commit_after>use std::env;
use std::path::PathBuf;
use std::process;
use std::{cell::RefCell, str::FromStr};

use getopts::Options;
use hprof::Profiler;
use libgir::{self as gir, Config, Library, WorkMode};

fn print_usage(program: &str, opts: Options) {
    let brief = format!(
        "Usage: {program} [options] [<library> <version>]
       {program} (-h | --help)",
        program = program
    );
    print!("{}", opts.usage(&brief));
}

trait OptionStr {
    fn as_str_ref(&self) -> Option<&str>;
}

impl<S: AsRef<str>> OptionStr for Option<S> {
    fn as_str_ref(&self) -> Option<&str> {
        self.as_ref().map(|string| string.as_ref())
    }
}

#[allow(clippy::large_enum_variant)]
enum RunKind {
    Config(Config),
    CheckGirFile(String),
}

fn build_config() -> Result<RunKind, String> {
    let args: Vec<_> = env::args().collect();
    let program = args[0].clone();

    let mut options = Options::new();
    options.optopt(
        "c",
        "config",
        "Config file path (default: Gir.toml)",
        "CONFIG",
    );
    options.optflag("h", "help", "Show this message");
    options.optopt("d", "gir-directory", "Directory for girs", "GIRSPATH");
    options.optopt(
        "m",
        "mode",
        "Work mode: doc, normal, sys or not_bound",
        "MODE",
    );
    options.optopt("o", "target", "Target path", "PATH");
    options.optopt("p", "doc-target-path", "Doc target path", "PATH");
    options.optflag("b", "make-backup", "Make backup before generating");
    options.optflag("s", "stats", "Show statistics");
    options.optflag("", "disable-format", "Disable formatting generated code");
    options.optopt(
        "",
        "check-gir-file",
        "Check if the given `.gir` file is valid",
        "PATH",
    );

    let matches = options.parse(&args[1..]).map_err(|e| e.to_string())?;

    if let Some(check_gir_file) = matches.opt_str("check-gir-file") {
        return Ok(RunKind::CheckGirFile(check_gir_file));
    }

    if matches.opt_present("h") {
        print_usage(&program, options);
        process::exit(0);
    }

    let work_mode = match matches.opt_str("m") {
        None => None,
        Some(s) => match WorkMode::from_str(&s) {
            Ok(w) => Some(w),
            Err(e) => {
                eprintln!("Error (switching to default work mode): {}", e);
                None
            }
        },
    };

    Config::new(
        matches.opt_str("c").as_str_ref(),
        work_mode,
        matches.opt_str("d").as_str_ref(),
        matches.free.get(0).as_str_ref(),
        matches.free.get(1).as_str_ref(),
        matches.opt_str("o").as_str_ref(),
        matches.opt_str("doc-target-path").as_str_ref(),
        matches.opt_present("b"),
        matches.opt_present("s"),
        matches.opt_present("disable-format"),
    )
    .map(RunKind::Config)
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
    if let Err(ref e) = do_main() {
        eprintln!("{}", e);

        ::std::process::exit(1);
    }
}

fn run_check(check_gir_file: &str) -> Result<(), String> {
    let path = PathBuf::from(check_gir_file);
    if !path.is_file() {
        return Err(format!("`{}`: file not found", check_gir_file));
    }
    let lib_name = path
        .file_stem()
        .ok_or(format!("Failed to get file stem from `{}`", check_gir_file))?;
    let lib_name = lib_name
        .to_str()
        .ok_or("failed to convert OsStr to str".to_owned())?;
    let mut library = Library::new(lib_name);
    let parent = path.parent().ok_or(format!(
        "Failed to get parent directory from `{}`",
        check_gir_file
    ))?;

    library.read_file(&parent, &mut vec![lib_name.to_owned()])
}

fn do_main() -> Result<(), String> {
    if std::env::var_os("RUST_LOG").is_none() {
        std::env::set_var("RUST_LOG", "gir=warn");
        std::env::set_var("RUST_LOG", "libgir=warn");
    }
    env_logger::init();

    let mut cfg = match build_config() {
        Ok(RunKind::CheckGirFile(check_gir_file)) => return run_check(&check_gir_file),
        Ok(RunKind::Config(cfg)) => cfg,
        Err(err) => return Err(err),
    };
    cfg.check_disable_format();

    let statistics = Profiler::new("Gir");
    statistics.start_frame();

    let watcher_total = statistics.enter("Total");

    let mut library = {
        let _watcher = statistics.enter("Loading");

        let mut library = Library::new(&cfg.library_name);
        library.read_file(&cfg.girs_dir, &mut vec![cfg.library_full_name()])?;
        library
    };

    {
        let _watcher = statistics.enter("Preprocessing");
        library.preprocessing(cfg.work_mode);
    }

    {
        let _watcher = statistics.enter("Update library by config");
        gir::update_version::apply_config(&mut library, &cfg);
    }

    {
        let _watcher = statistics.enter("Postprocessing");
        library.postprocessing(&cfg);
    }

    {
        let _watcher = statistics.enter("Resolving type ids");
        cfg.resolve_type_ids(&library);
    }

    {
        let _watcher = statistics.enter("Checking versions");
        gir::update_version::check_function_real_version(&mut library);
    }

    let mut env = {
        let _watcher = statistics.enter("Namespace/symbol/class analysis");

        let namespaces = gir::namespaces_run(&library);
        let symbols = gir::symbols_run(&library, &namespaces);
        let class_hierarchy = gir::class_hierarchy_run(&library);

        gir::Env {
            library,
            config: cfg,
            namespaces,
            symbols: RefCell::new(symbols),
            class_hierarchy,
            analysis: Default::default(),
        }
    };

    if env.config.work_mode != WorkMode::Sys {
        let _watcher = statistics.enter("Analyzing");
        gir::analysis_run(&mut env);
    }

    if env.config.work_mode != WorkMode::DisplayNotBound {
        let _watcher = statistics.enter("Generating");
        gir::codegen_generate(&env);
    }

    if !env.config.disable_format && env.config.work_mode.is_generate_rust_files() {
        let _watcher = statistics.enter("Formatting");
        gir::fmt::format(&env.config.target_path);
    }

    drop(watcher_total);
    statistics.end_frame();

    if env.config.show_statistics {
        statistics.print_timing();
    }
    if env.config.work_mode == WorkMode::DisplayNotBound {
        env.library.show_non_bound_types(&env);
    }

    Ok(())
}
<|endoftext|>


<commit_before>// extern crate rand;
#[macro_use]
extern crate clap;
extern crate image;

use std::path::Path;
// use rand::Rng;
use clap::{Arg, App};
use image::{DynamicImage, GenericImage, RgbaImage};

arg_enum!{
    //#[derive(Debug)]
    enum Mode {
        brute
    }
}

fn main() {
    let matches = App::new("asami")
        .version("0.1.0")
        .author("Sebastian Schulz <mail@sesc.me>")
        .about("pixel sorter")
        /*.arg(Arg::with_name("input")
            .short("i")
            .long("input")
            .value_name("PATH")
            .help("path to input file")
            .takes_value(true)
            .required(true))
        .arg(Arg::with_name("output")
            .short("o")
            .long("output")
            .value_name("PATH")
            .help("path to output file")
            .takes_value(true)
            .required(true))
        .arg(Arg::with_name("mode")
            .short("m")
            .long("mode")
            .value_name("MODE")
            .help("path to input file")
            .takes_value(true)
            .possible_values(&Mode::variants())
            .required(true))*/
        .args_from_usage(
            "<INPUT> 'Sets the input file to use'
             <OUTPUT> 'Sets the output file to use'")
        .arg(Arg::from_usage("-m --mode <MODE> 'Sets the mode to use")
            .possible_values(&Mode::variants())
            .default_value("brute"))
        .get_matches();

    let input = matches.value_of("INPUT").unwrap();
    let output = matches.value_of("OUTPUT").unwrap();

    let mode = matches.value_of("mode").unwrap();
    println!("{}", mode);

    handle_request(input, output);
}

fn handle_request(input: &str, output: &str) {
    println!("input: {}, output: {}", input, output);

    let ref in_img = image::open(&Path::new(input)).unwrap();

    println!("dimensions {:?}", in_img.dimensions());
    println!("{:?}", in_img.color());

    let out_img = brute_sort(in_img);

    let _ = out_img.save(output).unwrap();
}

fn brute_sort(input: &DynamicImage) -> RgbaImage {
    let mut output = RgbaImage::new(input.width(), input.height());

    let mut x = 0;
    let mut y = 0;

    let mut tmp = Vec::new();

    for (_, _, pixel) in input.pixels() {
        tmp.push(pixel);
        if tmp.len() > 100 {
            tmp.sort_by(|a, b| (a[3]).cmp(&b[1]));
            while !tmp.is_empty() {
                output.put_pixel(x, y, tmp.pop().unwrap());
                y = y + (x + 1) / input.width();
                x = (x + 1) % input.width();
            }
        }
    }
    output
}
<commit_msg>random chunk sizes<commit_after>extern crate rand;
#[macro_use]
extern crate clap;
extern crate image;

use std::path::Path;
use rand::Rng;
use clap::{Arg, App};
use image::{DynamicImage, GenericImage, RgbaImage};

arg_enum!{
    enum Mode {
        Brute
    }
}

fn main() {
    let matches = App::new("asami")
        .version("0.1.0")
        .author("Sebastian Schulz <mail@sesc.me>")
        .about("pixel sorter")
        .args_from_usage(
            "<INPUT> 'The input file to use'
             <OUTPUT> 'The output file to use'")
        .arg(Arg::from_usage("-m --mode <MODE> 'The mode to use")
            .possible_values(&Mode::variants())
            .default_value("Brute"))
        .get_matches();

    let input = matches.value_of("INPUT").unwrap();
    let output = matches.value_of("OUTPUT").unwrap();

    let mode = matches.value_of("mode").unwrap();
    println!("{}", mode);

    handle_request(input, output);
}

fn handle_request(input: &str, output: &str) {
    println!("input: {}, output: {}", input, output);

    let ref in_img = image::open(&Path::new(input)).unwrap();

    println!("dimensions {:?}", in_img.dimensions());
    println!("{:?}", in_img.color());

    let out_img = brute_sort(in_img, 32, 64);

    let _ = out_img.save(output).unwrap();
}

fn brute_sort(input: &DynamicImage, chunk_min_length: u32, chunk_max_length: u32) -> RgbaImage {
    let mut output = RgbaImage::new(input.width(), input.height());

    let mut out_x = 0;
    let mut out_y = 0;

    let mut tmp = Vec::new();

    let mut threshold = calculate_chunk_threshold(chunk_min_length, chunk_max_length);

    for (_, _, pixel) in input.pixels() {
        tmp.push(pixel);
        if tmp.len() > threshold as usize {
            threshold = calculate_chunk_threshold(chunk_min_length, chunk_max_length);
            tmp.sort_by(|a, b| (a[3]).cmp(&b[1]));
            write_pixel_to_image(&mut output, &mut out_x, &mut out_y, &mut tmp);
        }
    }
    output
}

fn calculate_chunk_threshold(chunk_min_length: u32, chunk_max_length: u32) -> u32 {
    rand::thread_rng().gen_range(chunk_min_length, chunk_max_length + 1)
}

fn write_pixel_to_image(image: &mut RgbaImage, x: &mut u32, y: &mut u32, pixels: &mut Vec<image::Rgba<u8>>){
    while !pixels.is_empty() {
        image.put_pixel(*x, *y, pixels.pop().unwrap());
        *y = *y + (*x + 1) / image.width();
        *x = (*x + 1) % image.width();
    }
}
<|endoftext|>


<commit_before>extern crate rusqlite;
extern crate time;
extern crate rand;

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

#[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 \"movies help\"");
    }

    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, it's id is {}", &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:\t{}\nOpinion:\t{}\nRating:\t{}\nID:\t{}\nTime:\t{}\n",
                         z.name.trim(),
                         z.opinion.trim(),
                         z.rating,
                         z.id,
                         time(z.time_created));
            }
        }
        else { continue; }
    }
}

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!("help!");
}

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 alignment<commit_after>extern crate rusqlite;
extern crate time;
extern crate rand;

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

#[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 \"movies help\"");
    }

    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, it's id is {}", &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 { continue; }
    }
}

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!("help!");
}

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>//! A Rust snippet runner.
//!
//! Please see [readme](https://github.com/stevedonovan/runner/blob/master/readme.md)
extern crate easy_shortcuts as es;
extern crate lapp;
use es::traits::*;
use std::process;
use std::env;
use std::fs;
use std::path::PathBuf;
use std::collections::HashMap;
use std::io::Write;

mod crate_utils;
mod platform;

use platform::{open,edit,EXE};

fn rustup_lib() -> String {
    es::shell("rustc --print sysroot") + "/lib"
}

// this will be initially written to ~/.cargo/.runner/prelude and
// can then be edited.
const PRELUDE: &'static str = "
#![allow(unused_imports)]
#![allow(dead_code)]
use std::fs;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::env;
use std::path::{PathBuf,Path};
#[allow(unused_macros)]
macro_rules! debug {
    ($x:expr) => {
        println!(\"{} = {:?}\",stringify!($x),$x);
    }
}

";

fn runner_directory() -> PathBuf {
    let mut home = env::home_dir().or_die("no home!");
    home.push(".cargo");
    home.push(".runner");
    home
}

fn cargo(args: &[&str]) {
    let res = process::Command::new("cargo")
        .args(args)
        .status()
        .or_die("can't run cargo");
    if ! res.success() {
        es::quit("cargo failed");
    }
}

const STATIC_CACHE: &str = "static-cache";
const DYNAMIC_CACHE: &str = "dy-cache";

fn static_cache_dir() -> PathBuf {
    runner_directory().join(STATIC_CACHE)
}

fn static_cache_dir_check(args: &lapp::Args) -> PathBuf {
    let static_cache = static_cache_dir();
    if ! static_cache.exists() {
        args.quit("please build static cache with --create first");
    }
    static_cache
}

fn build_static_cache() {
    cargo(&["build"]);
    cargo(&["build","--release"]);
    cargo(&["doc"]);
}

fn create_static_cache(crates: &[String], create: bool) {
    use std::io::prelude::*;
    let mut home = runner_directory();
    env::set_current_dir(&home).or_die("cannot change to home directory");
    if create {
        cargo(&["new","--bin",STATIC_CACHE]);
    }
    home.push(STATIC_CACHE);
    env::set_current_dir(&home).or_die("could not create static cache");
    {
        let mut deps = fs::OpenOptions::new().append(true)
            .open("Cargo.toml").or_die("could not append to cargo.toml");
        for c in crates {
            write!(deps,"{}=\"*\"\n",c).or_die("could not modify cargo.toml");
        }
    }
    build_static_cache();
}

// this is always called first and has the important role to ensure that
// runner's directory structure is created properly.
fn get_prelude() -> String {
    let home = runner_directory();
    let pristine = ! home.is_dir();
    if pristine {
        fs::create_dir(&home).or_die("cannot create runner directory");
    }
    let prelude = home.join("prelude");
    let bin = home.join("bin");
    if pristine {
        es::write_all(&prelude,PRELUDE);
        fs::create_dir(&home.join(DYNAMIC_CACHE)).or_die("cannot create dynamic cache");
    }
    if pristine || ! bin.is_dir() {
        fs::create_dir(&bin).or_die("cannot create output directory");
    }
    es::read_to_string(&prelude)
}

fn get_cache(build_static: bool, optimize: bool) -> PathBuf {
    let mut home = runner_directory();
    let scache;
    let cache = if build_static {
        let dir = if optimize {"release"} else {"debug"};
        scache = format!("{}/target/{}/deps",STATIC_CACHE,dir);
        &scache
    } else {DYNAMIC_CACHE};
    home.push(cache);
    home
}

fn add_aliases(aliases: Vec<String>) {
    if aliases.len() == 0 { return; }
    let alias_file = runner_directory().join("alias");
    let mut f = if alias_file.is_file() {
        fs::OpenOptions::new().append(true).open(&alias_file)
    } else {
        fs::File::create(&alias_file)
    }.or_die("cannot open runner alias file");

    for crate_alias in aliases {
        write!(f,"{}\n",crate_alias).or_die("cannot write to runner alias file");
    }
}

fn get_aliases() -> HashMap<String,String> {
    let alias_file = runner_directory().join("alias");
    if ! alias_file.is_file() { return HashMap::new(); }
	es::lines(es::open(&alias_file))
      .filter_map(|s| s.split_at_delim('=').trim()) // split into (String,String)
	  .to_map()
}

fn massage_snippet(code: String, prelude: String, extern_crates: Vec<String>, wild_crates: Vec<String>) -> String {
    fn indent_line(line: &str) -> String {
        format!("    {}\n",line)
    }
    let mut prefix = prelude;
    let mut body = String::new();
    {
        if extern_crates.len() > 0 {
            let aliases = get_aliases();
            for c in extern_crates {
                prefix += &if let Some(aliased) = aliases.get(&c) {
                    format!("extern crate {} as {};",aliased,c)
                } else {
                    format!("extern crate {};",c)
                };
            }
            for c in wild_crates {
                prefix += &format!("use {}::*;",c);
            }
        }
        let mut lines = code.lines();
        let mut first = true;
        for line in lines.by_ref() {
            let line = line.trim_left();
            if first { // files may start with #! shebang...
                if line.starts_with("#!") {
                    continue;
                }
                first = false;
            }
            if line.starts_with("//") || line.starts_with("#[macro_use") ||
                line.starts_with("extern ") || line.starts_with("use ") {
                prefix += line;
                prefix.push('\n');
            } else
            if line.len() > 0 {
                body += &indent_line(line);
                break;
            }
        }
        // and indent the rest!
        body.extend(lines.map(indent_line));
    }

    format!("{}
use std::error::Error;
fn run() -> Result<(),Box<Error>> {{
{}    Ok(())
}}
fn main() {{
    run().unwrap();
}}
        ",prefix,body)

}

const USAGE: &str = "
Compile and run small Rust snippets
  -s, --static build statically (default is dynamic)
  -O, --optimize optimized static build
  -e, --expression evaluate an expression
  -i, --iterator evaluate an iterator
  -n, --lines evaluate expression over stdin; 'line' is defined
  -x, --extern... (string) add an extern crate to the snippet
  -X, --wild... (string) like -x but implies wildcard use

  Cache Management:
  --create (string...) initialize the static cache with crates
  --add  (string...) add new crates to the cache (after --create)
  --edit  edit the static cache Cargo.toml
  --build rebuild the static cache
  --doc  display documentation
  --edit-prelude edit the default prelude for snippets
  --alias (string...) crate aliases in form alias=crate_name (used with -x)

  Dynamic compilation:
  -P, --crate-path show path of crate source in Cargo cache
  -C, --compile  compile crate dynamically (limited)
  --cfg... (string) pass configuration variables to rustc
  --libc  link dynamically against libc (special case)

  <program> (string) Rust program, snippet or expression
  <args> (string...) arguments to pass to program
";

fn main() {
    let args = lapp::parse_args(USAGE);
    let prelude = get_prelude();

    let aliases = args.get_strings("alias");
    if aliases.len() > 0 {
        add_aliases(aliases);
        return;
    }

    if args.get_bool("edit-prelude") {
        let rdir = runner_directory().join("prelude");
        edit(&rdir);
        return;
    }

    // Static Cache Management
    let crates = args.get_strings("create");
    if crates.len() > 0 {
        create_static_cache(&crates,true);
        return;
    }
    let crates = args.get_strings("add");
    if crates.len() > 0 {
        static_cache_dir_check(&args);
        create_static_cache(&crates,false);
        return;
    }

    if args.get_bool("edit") || args.get_bool("build") || args.get_bool("doc") {
        let static_cache = static_cache_dir_check(&args);
        if args.get_bool("build") {
            env::set_current_dir(&static_cache).or_die("static cache wasn't a directory?");
            build_static_cache();
        } else
        if args.get_bool("doc") {
            let docs = static_cache.join("target/doc/static_cache/index.html");
            open(&docs);
        } else {
            let toml = static_cache.join("Cargo.toml");
            edit(&toml);
        }
        return;
    }

    let first_arg = args.get_string("program");
    let file = PathBuf::from(&first_arg);

    // Dynamically linking crates (experimental!)
    if args.get_bool("crate-path") || args.get_bool("compile") {
        let (crate_path,crate_name) = if file.exists() {
            let filename = crate_utils::path_file_name(&file);
            if file.is_dir() { // assumed to be Cargo directory
                if ! file.join("Cargo.toml").exists() {
                    args.quit("not a Cargo project directory");
                }
                (file.join("src/lib.rs"), filename)
            } else { // should be just a Rust source file
                if file.extension().or_die("expecting extension") != "rs" {
                    args.quit("expecting Rust source file");
                }
                let name = crate_utils::path_file_name(&file.with_extension(""));
                (file, name)
            }
        } else {
            (crate_utils::cache_path(&first_arg).join("src/lib.rs"), first_arg)
        };
        if args.get_bool("crate-path") {
            println!("{}",crate_utils::cache_path(&crate_name).display());
        } else {
            let valid_crate_name = crate_name.replace('-',"_");
            let cache = get_cache(false, false);
            let mut builder = process::Command::new("rustc");
                builder.args(&["-C","prefer-dynamic"]).args(&["-C","debuginfo=0"])
                .arg("-L").arg(&cache)
                .args(&["--crate-type","dylib"])
                .arg("--out-dir").arg(&cache)
                .arg("--crate-name").arg(&valid_crate_name)
                .arg(crate_path);
           for c in args.get_strings("cfg") {
                builder.arg("--cfg").arg(&c);
           }
           if args.get_bool("libc") {
                builder.arg("--extern").arg(&format!("libc={}/liblibc.so",cache.display()));
           }
           builder.status().or_die("can't run rustc");
        }
        return;
    }

    let build_static = args.get_bool("static");
    let optimize = args.get_bool("optimize");

    // we'll pass rest of arguments to program
    let program_args = args.get_strings("args");

    let cache = get_cache(build_static, optimize);

    let mut snippet = false;
    let mut code = if args.get_bool("expression") {
        // Evaluating an expression: just print it out.
        format!("println!(\"{{:?}}\",{});", first_arg)
    } else
    if args.get_bool("iterator") {
        // The expression is anything that implements IntoIterator
        format!("let iter = {};\n for val in iter {{ println!(\"{{:?}}\",val);}}", first_arg)
    } else
    if args.get_bool("lines") {
        // The variable 'line' is available to an expression, evaluated for each line in stdin
        format!("
            let stdin = io::stdin();
            for line in stdin.lock().lines() {{
                let line = line?;
                let val = {};
                println!(\"{{:?}}\",val);
            }}
            ", first_arg)
    } else { // otherwise, just a file
        snippet = true;
        es::read_to_string(&file)
    };

    // proper Rust programs are accepted (this is a bit rough)
    if code.find("fn main").is_none() {
        let mut extern_crates = args.get_strings("extern");
        let wild_crates = args.get_strings("wild");
        if wild_crates.len() > 0 {
            extern_crates.extend(wild_crates.iter().cloned());
        }
        code = massage_snippet(code,prelude, extern_crates, wild_crates);
    }

    // we are going to put the expanded source and resulting exe in the runner bin dir
    let mut out_file = runner_directory().join("bin");
    if snippet {
        out_file.push(&file);
        out_file.set_extension("rs");
    } else {
        out_file.push("tmp.rs");
    }
    let mut program = out_file.clone();
    program.set_extension(EXE);

    es::write_all(&out_file,&code);

    let mut builder = process::Command::new("rustc");
    if ! build_static {
        builder.args(&["-C","prefer-dynamic"]).args(&["-C","debuginfo=0"]);
    } else {
        builder.arg(if optimize {"-O"} else {"-g"});
    }
    builder.arg("-L").arg(&cache);
    let status = builder.arg("-o").arg(&program)
        .arg(&out_file)
        .status().or_die("can't run rustc");
    if ! status.success() {
        return;
    }

    let mut builder = process::Command::new(&program);
    if ! build_static {
        builder.env("LD_LIBRARY_PATH",format!("{}:{}",rustup_lib(),cache.display()));
    }
    builder.args(&program_args)
        .status()
        .or_die(&format!("can't run program {:?}",program));

}

<commit_msg>respect CARGO_HOME<commit_after>//! A Rust snippet runner.
//!
//! Please see [readme](https://github.com/stevedonovan/runner/blob/master/readme.md)
extern crate easy_shortcuts as es;
extern crate lapp;
use es::traits::*;
use std::process;
use std::env;
use std::fs;
use std::path::PathBuf;
use std::collections::HashMap;
use std::io::Write;

mod crate_utils;
mod platform;

use platform::{open,edit,EXE};

fn rustup_lib() -> String {
    es::shell("rustc --print sysroot") + "/lib"
}

// this will be initially written to ~/.cargo/.runner/prelude and
// can then be edited.
const PRELUDE: &'static str = "
#![allow(unused_imports)]
#![allow(dead_code)]
use std::fs;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::env;
use std::path::{PathBuf,Path};
#[allow(unused_macros)]
macro_rules! debug {
    ($x:expr) => {
        println!(\"{} = {:?}\",stringify!($x),$x);
    }
}

";

fn runner_directory() -> PathBuf {
    let mut home = crate_utils::cargo_home();
    home.push(".runner");
    home
}

fn cargo(args: &[&str]) {
    let res = process::Command::new("cargo")
        .args(args)
        .status()
        .or_die("can't run cargo");
    if ! res.success() {
        es::quit("cargo failed");
    }
}

const STATIC_CACHE: &str = "static-cache";
const DYNAMIC_CACHE: &str = "dy-cache";

fn static_cache_dir() -> PathBuf {
    runner_directory().join(STATIC_CACHE)
}

fn static_cache_dir_check(args: &lapp::Args) -> PathBuf {
    let static_cache = static_cache_dir();
    if ! static_cache.exists() {
        args.quit("please build static cache with --create first");
    }
    static_cache
}

fn build_static_cache() {
    cargo(&["build"]);
    cargo(&["build","--release"]);
    cargo(&["doc"]);
}

fn create_static_cache(crates: &[String], create: bool) {
    use std::io::prelude::*;
    let mut home = runner_directory();
    env::set_current_dir(&home).or_die("cannot change to home directory");
    if create {
        cargo(&["new","--bin",STATIC_CACHE]);
    }
    home.push(STATIC_CACHE);
    env::set_current_dir(&home).or_die("could not create static cache");
    {
        let mut deps = fs::OpenOptions::new().append(true)
            .open("Cargo.toml").or_die("could not append to cargo.toml");
        for c in crates {
            write!(deps,"{}=\"*\"\n",c).or_die("could not modify cargo.toml");
        }
    }
    build_static_cache();
}

// this is always called first and has the important role to ensure that
// runner's directory structure is created properly.
fn get_prelude() -> String {
    let home = runner_directory();
    let pristine = ! home.is_dir();
    if pristine {
        fs::create_dir(&home).or_die("cannot create runner directory");
    }
    let prelude = home.join("prelude");
    let bin = home.join("bin");
    if pristine {
        es::write_all(&prelude,PRELUDE);
        fs::create_dir(&home.join(DYNAMIC_CACHE)).or_die("cannot create dynamic cache");
    }
    if pristine || ! bin.is_dir() {
        fs::create_dir(&bin).or_die("cannot create output directory");
    }
    es::read_to_string(&prelude)
}

fn get_cache(build_static: bool, optimize: bool) -> PathBuf {
    let mut home = runner_directory();
    let scache;
    let cache = if build_static {
        let dir = if optimize {"release"} else {"debug"};
        scache = format!("{}/target/{}/deps",STATIC_CACHE,dir);
        &scache
    } else {DYNAMIC_CACHE};
    home.push(cache);
    home
}

fn add_aliases(aliases: Vec<String>) {
    if aliases.len() == 0 { return; }
    let alias_file = runner_directory().join("alias");
    let mut f = if alias_file.is_file() {
        fs::OpenOptions::new().append(true).open(&alias_file)
    } else {
        fs::File::create(&alias_file)
    }.or_die("cannot open runner alias file");

    for crate_alias in aliases {
        write!(f,"{}\n",crate_alias).or_die("cannot write to runner alias file");
    }
}

fn get_aliases() -> HashMap<String,String> {
    let alias_file = runner_directory().join("alias");
    if ! alias_file.is_file() { return HashMap::new(); }
	es::lines(es::open(&alias_file))
      .filter_map(|s| s.split_at_delim('=').trim()) // split into (String,String)
	  .to_map()
}

fn massage_snippet(code: String, prelude: String, extern_crates: Vec<String>, wild_crates: Vec<String>) -> String {
    fn indent_line(line: &str) -> String {
        format!("    {}\n",line)
    }
    let mut prefix = prelude;
    let mut body = String::new();
    {
        if extern_crates.len() > 0 {
            let aliases = get_aliases();
            for c in extern_crates {
                prefix += &if let Some(aliased) = aliases.get(&c) {
                    format!("extern crate {} as {};",aliased,c)
                } else {
                    format!("extern crate {};",c)
                };
            }
            for c in wild_crates {
                prefix += &format!("use {}::*;",c);
            }
        }
        let mut lines = code.lines();
        let mut first = true;
        for line in lines.by_ref() {
            let line = line.trim_left();
            if first { // files may start with #! shebang...
                if line.starts_with("#!") {
                    continue;
                }
                first = false;
            }
            if line.starts_with("//") || line.starts_with("#[macro_use") ||
                line.starts_with("extern ") || line.starts_with("use ") {
                prefix += line;
                prefix.push('\n');
            } else
            if line.len() > 0 {
                body += &indent_line(line);
                break;
            }
        }
        // and indent the rest!
        body.extend(lines.map(indent_line));
    }

    format!("{}
use std::error::Error;
fn run() -> Result<(),Box<Error>> {{
{}    Ok(())
}}
fn main() {{
    run().unwrap();
}}
        ",prefix,body)

}

const USAGE: &str = "
Compile and run small Rust snippets
  -s, --static build statically (default is dynamic)
  -O, --optimize optimized static build
  -e, --expression evaluate an expression
  -i, --iterator evaluate an iterator
  -n, --lines evaluate expression over stdin; 'line' is defined
  -x, --extern... (string) add an extern crate to the snippet
  -X, --wild... (string) like -x but implies wildcard use

  Cache Management:
  --create (string...) initialize the static cache with crates
  --add  (string...) add new crates to the cache (after --create)
  --edit  edit the static cache Cargo.toml
  --build rebuild the static cache
  --doc  display documentation
  --edit-prelude edit the default prelude for snippets
  --alias (string...) crate aliases in form alias=crate_name (used with -x)

  Dynamic compilation:
  -P, --crate-path show path of crate source in Cargo cache
  -C, --compile  compile crate dynamically (limited)
  --cfg... (string) pass configuration variables to rustc
  --libc  link dynamically against libc (special case)

  <program> (string) Rust program, snippet or expression
  <args> (string...) arguments to pass to program
";

fn main() {
    let args = lapp::parse_args(USAGE);
    let prelude = get_prelude();

    let aliases = args.get_strings("alias");
    if aliases.len() > 0 {
        add_aliases(aliases);
        return;
    }

    if args.get_bool("edit-prelude") {
        let rdir = runner_directory().join("prelude");
        edit(&rdir);
        return;
    }

    // Static Cache Management
    let crates = args.get_strings("create");
    if crates.len() > 0 {
        create_static_cache(&crates,true);
        return;
    }
    let crates = args.get_strings("add");
    if crates.len() > 0 {
        static_cache_dir_check(&args);
        create_static_cache(&crates,false);
        return;
    }

    if args.get_bool("edit") || args.get_bool("build") || args.get_bool("doc") {
        let static_cache = static_cache_dir_check(&args);
        if args.get_bool("build") {
            env::set_current_dir(&static_cache).or_die("static cache wasn't a directory?");
            build_static_cache();
        } else
        if args.get_bool("doc") {
            let docs = static_cache.join("target/doc/static_cache/index.html");
            open(&docs);
        } else {
            let toml = static_cache.join("Cargo.toml");
            edit(&toml);
        }
        return;
    }

    let first_arg = args.get_string("program");
    let file = PathBuf::from(&first_arg);

    // Dynamically linking crates (experimental!)
    if args.get_bool("crate-path") || args.get_bool("compile") {
        let (crate_path,crate_name) = if file.exists() {
            let filename = crate_utils::path_file_name(&file);
            if file.is_dir() { // assumed to be Cargo directory
                if ! file.join("Cargo.toml").exists() {
                    args.quit("not a Cargo project directory");
                }
                (file.join("src/lib.rs"), filename)
            } else { // should be just a Rust source file
                if file.extension().or_die("expecting extension") != "rs" {
                    args.quit("expecting Rust source file");
                }
                let name = crate_utils::path_file_name(&file.with_extension(""));
                (file, name)
            }
        } else {
            (crate_utils::cache_path(&first_arg).join("src/lib.rs"), first_arg)
        };
        if args.get_bool("crate-path") {
            println!("{}",crate_utils::cache_path(&crate_name).display());
        } else {
            let valid_crate_name = crate_name.replace('-',"_");
            let cache = get_cache(false, false);
            let mut builder = process::Command::new("rustc");
                builder.args(&["-C","prefer-dynamic"]).args(&["-C","debuginfo=0"])
                .arg("-L").arg(&cache)
                .args(&["--crate-type","dylib"])
                .arg("--out-dir").arg(&cache)
                .arg("--crate-name").arg(&valid_crate_name)
                .arg(crate_path);
           for c in args.get_strings("cfg") {
                builder.arg("--cfg").arg(&c);
           }
           if args.get_bool("libc") {
                builder.arg("--extern").arg(&format!("libc={}/liblibc.so",cache.display()));
           }
           builder.status().or_die("can't run rustc");
        }
        return;
    }

    let build_static = args.get_bool("static");
    let optimize = args.get_bool("optimize");

    // we'll pass rest of arguments to program
    let program_args = args.get_strings("args");

    let cache = get_cache(build_static, optimize);

    let mut snippet = false;
    let mut code = if args.get_bool("expression") {
        // Evaluating an expression: just print it out.
        format!("println!(\"{{:?}}\",{});", first_arg)
    } else
    if args.get_bool("iterator") {
        // The expression is anything that implements IntoIterator
        format!("let iter = {};\n for val in iter {{ println!(\"{{:?}}\",val);}}", first_arg)
    } else
    if args.get_bool("lines") {
        // The variable 'line' is available to an expression, evaluated for each line in stdin
        format!("
            let stdin = io::stdin();
            for line in stdin.lock().lines() {{
                let line = line?;
                let val = {};
                println!(\"{{:?}}\",val);
            }}
            ", first_arg)
    } else { // otherwise, just a file
        snippet = true;
        es::read_to_string(&file)
    };

    // proper Rust programs are accepted (this is a bit rough)
    if code.find("fn main").is_none() {
        let mut extern_crates = args.get_strings("extern");
        let wild_crates = args.get_strings("wild");
        if wild_crates.len() > 0 {
            extern_crates.extend(wild_crates.iter().cloned());
        }
        code = massage_snippet(code,prelude, extern_crates, wild_crates);
    }

    // we are going to put the expanded source and resulting exe in the runner bin dir
    let mut out_file = runner_directory().join("bin");
    if snippet {
        out_file.push(&file);
        out_file.set_extension("rs");
    } else {
        out_file.push("tmp.rs");
    }
    let mut program = out_file.clone();
    program.set_extension(EXE);

    es::write_all(&out_file,&code);

    let mut builder = process::Command::new("rustc");
    if ! build_static {
        builder.args(&["-C","prefer-dynamic"]).args(&["-C","debuginfo=0"]);
    } else {
        builder.arg(if optimize {"-O"} else {"-g"});
    }
    builder.arg("-L").arg(&cache);
    let status = builder.arg("-o").arg(&program)
        .arg(&out_file)
        .status().or_die("can't run rustc");
    if ! status.success() {
        return;
    }

    let mut builder = process::Command::new(&program);
    if ! build_static {
        builder.env("LD_LIBRARY_PATH",format!("{}:{}",rustup_lib(),cache.display()));
    }
    builder.args(&program_args)
        .status()
        .or_die(&format!("can't run program {:?}",program));

}

<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate env_logger;
extern crate irc;
extern crate github;

use irc::client::prelude::*;

fn main() {
    env_logger::init().unwrap();

    // This could be in a JSON config, but then we need to figure out how
    // to find that JSON config
    let irc_config : Config = Config {
        owners: Some(vec![format!("dbaron")]),
        nickname: Some(format!("wgmeeting-github-bot")),
        alt_nicks: Some(vec![format!("wgmeeting-github-bot-"), format!("wgmeeting-github-bot--")]),
        username: Some(format!("dbaron-gh-bot")),
        realname: Some(format!("Bot to add meeting minutes to github issues.")),
        server: Some(format!("irc.w3.org")),
        port: Some(6667),
        use_ssl: Some(false),
        encoding: Some(format!("UTF-8")),
        channels: Some(vec![format!("#cssbottest")]),
        user_info: Some(format!("Bot to add meeting minutes to github issues.")),
        //source: Some(format!("https://github.com/dbaron/wgmeeting-github-ircbot")), // FIXME: why doesn't this work as documented?
        .. Default::default()
    };

    let server = IrcServer::from_config(irc_config).unwrap();
    server.identify().unwrap();
    for message in server.iter() {
        let message = message.unwrap(); // panic if there's an error

        match message.command {
            Command::PRIVMSG(ref target, ref msg) => {
                match message.source_nickname() {
                    None => {
                        warn!("PRIVMSG without a source! {}", message); // FIXME: trailing \n
                    },
                    Some(ref source) => {
                        let mynick = server.current_nickname();
                        if target == mynick {
                            handle_bot_command(&server, msg, source, None)
                        } else if target.starts_with('#') {
                            match check_command_in_channel(mynick, msg) {
                                Some(ref command) => {
                                    handle_bot_command(&server, command, target, Some(source))
                                },
                                None => {
                                    // unimplemented!();
                                }
                            }
                        } else {
                            warn!("UNEXPECTED TARGET {} in message {}", target, message); // FIXME: trailing \n
                        }
                    }
                }
            },
            _ => (),
        }
    }
}

// Take a message in the channel, and see if it was a message sent to
// this bot.
fn check_command_in_channel(mynick: &str, msg: &String) -> Option<String> {
    if !msg.starts_with(mynick)  {
        return None;
    }
    let after_nick = &msg[mynick.len()..];
    if !after_nick.starts_with(":") && !after_nick.starts_with(",") {
        return None;
    }
    let after_punct = &after_nick[1..];
    Some(String::from(after_punct.trim_left()))
}

fn handle_bot_command(server: &IrcServer, command: &str, response_target: &str, response_username: Option<&str>) {

    let send_line = |response_username: Option<&str>, line: &str| {
        let adjusted_line = match response_username {
            None => String::from(line),
            Some(username) => String::from(username) + ", " + line
        };
        server.send_privmsg(response_target, &adjusted_line).unwrap();
    };

    if command == "help" {
        send_line(response_username, "The commands I understand are:");
        send_line(None, "  help     Send this message.");
        return;
    }

    send_line(response_username, "Sorry, I don't understand that command.  Try 'help'.");
}
<commit_msg>Fix indentation.<commit_after>#[macro_use]
extern crate log;
extern crate env_logger;
extern crate irc;
extern crate github;

use irc::client::prelude::*;

fn main() {
    env_logger::init().unwrap();

    // This could be in a JSON config, but then we need to figure out how
    // to find that JSON config
    let irc_config : Config = Config {
        owners: Some(vec![format!("dbaron")]),
        nickname: Some(format!("wgmeeting-github-bot")),
        alt_nicks: Some(vec![format!("wgmeeting-github-bot-"), format!("wgmeeting-github-bot--")]),
        username: Some(format!("dbaron-gh-bot")),
        realname: Some(format!("Bot to add meeting minutes to github issues.")),
        server: Some(format!("irc.w3.org")),
        port: Some(6667),
        use_ssl: Some(false),
        encoding: Some(format!("UTF-8")),
        channels: Some(vec![format!("#cssbottest")]),
        user_info: Some(format!("Bot to add meeting minutes to github issues.")),
        //source: Some(format!("https://github.com/dbaron/wgmeeting-github-ircbot")), // FIXME: why doesn't this work as documented?
        .. Default::default()
    };

    let server = IrcServer::from_config(irc_config).unwrap();
    server.identify().unwrap();
    for message in server.iter() {
        let message = message.unwrap(); // panic if there's an error

        match message.command {
            Command::PRIVMSG(ref target, ref msg) => {
                match message.source_nickname() {
                    None => {
                        warn!("PRIVMSG without a source! {}", message); // FIXME: trailing \n
                    },
                    Some(ref source) => {
                        let mynick = server.current_nickname();
                        if target == mynick {
                            handle_bot_command(&server, msg, source, None)
                        } else if target.starts_with('#') {
                            match check_command_in_channel(mynick, msg) {
                                Some(ref command) => {
                                    handle_bot_command(&server, command, target, Some(source))
                                },
                                None => {
                                    // unimplemented!();
                                }
                            }
                        } else {
                            warn!("UNEXPECTED TARGET {} in message {}", target, message); // FIXME: trailing \n
                        }
                    }
                }
            },
            _ => (),
        }
    }
}

// Take a message in the channel, and see if it was a message sent to
// this bot.
fn check_command_in_channel(mynick: &str, msg: &String) -> Option<String> {
    if !msg.starts_with(mynick)  {
        return None;
    }
    let after_nick = &msg[mynick.len()..];
    if !after_nick.starts_with(":") && !after_nick.starts_with(",") {
        return None;
    }
    let after_punct = &after_nick[1..];
    Some(String::from(after_punct.trim_left()))
}

fn handle_bot_command(server: &IrcServer, command: &str, response_target: &str, response_username: Option<&str>) {

    let send_line = |response_username: Option<&str>, line: &str| {
        let adjusted_line = match response_username {
            None => String::from(line),
            Some(username) => String::from(username) + ", " + line
        };
        server.send_privmsg(response_target, &adjusted_line).unwrap();
    };

    if command == "help" {
        send_line(response_username, "The commands I understand are:");
        send_line(None,              "  help     Send this message.");
        return;
    }

    send_line(response_username, "Sorry, I don't understand that command.  Try 'help'.");
}
<|endoftext|>


<commit_before>extern crate crypto;
extern crate base64;
extern crate byteorder;
extern crate docopt;
extern crate rustc_serialize;
extern crate rpassword;
extern crate ring;
extern crate untrusted;
#[macro_use]
extern crate error_chain;

use std::process;
use std::mem;
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::{OpenOptions, File};
use std::path::Path;

use ring::rand::SystemRandom;
use ring::signature::Ed25519KeyPair;
use ring::digest;
use crypto::bcrypt_pbkdf::bcrypt_pbkdf;

use docopt::Docopt;

mod structs;
mod errors;

use structs::*;
use errors::*;

const USAGE: &'static str = "
signify-rs

Usage:
  signify -h
  signify -G [-n] [-c <comment>] -p <pubkey> -s <seckey>
  signify -S [-x <sigfile>] -s <seckey> -m <message>
  signify -V [-x <sigfile>] -p <pubkey> -m <message>

Options:
  -h --help     Show this screen.
  -c <comment>  Specify the comment to be added during key generation.
  -m <message>  When signing, the file containing the message to sign.  When verifying, the file containing the
                message to verify.  When verifying with -e, the file to create.
  -n            Do not ask for a passphrase during key generation. Otherwise, signify will prompt the user for a
                passphrase to protect the secret key.
  -p <pubkey>   Public key produced by -G, and used by -V to check a signature.
  -s <seckey>   Secret (private) key produced by -G, and used by -S to sign a message.
  -x <sigfile>  The signature file to create or verify.  The default is <message>.sig.
";

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable)]
struct Args {
    flag_G: bool,
    flag_S: bool,
    flag_V: bool,

    flag_x: Option<String>,
    flag_c: Option<String>,

    flag_p: String,
    flag_s: String,
    flag_m: String,
    flag_n: bool,
}

enum FileContent {
    PublicKey(PublicKey),
    PrivateKey(PrivateKey),
    Signature(Signature),
}

fn write_base64_file<P: AsRef<Path>>(file: P, comment: &str, buf: &[u8]) -> Result<()> {
    let mut f = try!(OpenOptions::new().write(true).create_new(true).open(file));

    try!(write!(f, "{}", COMMENTHDR));
    try!(write!(f, "{}\n", comment));
    let out = base64::encode(buf);
    try!(write!(f, "{}\n", out));

    Ok(())
}

fn read_base64_file<P: AsRef<Path>>(file: P) -> Result<FileContent> {
    let file_display = format!("{}", file.as_ref().display());
    let f = try!(File::open(file));
    let mut reader = BufReader::new(f);

    let mut comment_line = String::new();
    let len = try!(reader.read_line(&mut comment_line));

    if len == 0 || len < COMMENTHDRLEN || !comment_line.starts_with(COMMENTHDR) {
        return Err(format!("invalid comment in {}; must start with '{}'", file_display, COMMENTHDR).into());
    }

    if &comment_line[len-1..len] != "\n" {
        return Err(format!("missing new line after comment in {}", file_display).into());
    }

    if len > COMMENTHDRLEN + COMMENTMAXLEN {
        return Err(format!("comment too long").into());
    }

    let mut base64_line = String::new();
    let len = try!(reader.read_line(&mut base64_line));

    if len == 0 {
        return Err(format!("missing line in {}", file_display).into());
    }

    if &base64_line[len-1..len] != "\n" {
        return Err(format!("missing new line after comment in {}", file_display).into());
    }

    let base64_line = &base64_line[0..len-1];

    let data = try!(base64::decode(base64_line)
                    .chain_err(|| format!("invalid base64 encoding in {}", file_display)));

    if &data[0..2] != PKGALG {
        return Err(format!("unsupported file {}", file_display).into());
    }

    match data.len() {
        x if x == mem::size_of::<PublicKey>() => {
            return PublicKey::from_buf(&data)
                .map(FileContent::PublicKey);
        },
        x if x == mem::size_of::<PrivateKey>() => {
            return PrivateKey::from_buf(&data)
                .map(FileContent::PrivateKey);
        },
        x if x == mem::size_of::<Signature>() => {
            return Signature::from_buf(&data)
                .map(FileContent::Signature);
        },
        _ => {
            return Err(format!("unsupported file {}", file_display).into());
        },
    };
}

fn verify(pubkey_path: String, msg_path: String, signature_path: Option<String>) -> Result<()> {
    let pkey = match read_base64_file(&pubkey_path) {
        Ok(FileContent::PublicKey(pkey)) => pkey,
        _ => return Err("an error occured.".into()),
    };

    let signature_path = match signature_path {
        Some(path) => path,
        None => format!("{}.sig", msg_path)
    };

    let signature = match read_base64_file(&signature_path) {
        Ok(FileContent::Signature(sig)) => sig,
        _ => return Err(format!("Can't read signature from {}", signature_path).into()),
    };

    let mut msgfile = try!(File::open(&msg_path).chain_err(|| read_error(&msg_path)));
    let mut msg = vec![];
    try!(msgfile.read_to_end(&mut msg).chain_err(|| read_error(&msg_path)));

    if signature.keynum != pkey.keynum {
        return Err("signature verification failed: checked against wrong key".into());
    }

    if signature.verify(&msg, &pkey) {
        println!("Signature Verified");
        return Ok(());
    } else {
        return Err("signature verification failed".into());
    }
}

fn sign(seckey_path: String, msg_path: String, signature_path: Option<String>) -> Result<()> {
    let mut skey = match read_base64_file(&seckey_path) {
        Ok(FileContent::PrivateKey(skey)) => skey,
        _ => return Err("an error occured.".into()),
    };

    let rounds = skey.kdfrounds;
    let xorkey = try!(kdf(&skey.salt, rounds, false, SECRETBYTES));

    for (prv, xor) in skey.seckey.iter_mut().zip(xorkey.iter()) {
        *prv = *prv ^ xor;
    }
    let skey = skey;

    let mut msgfile = try!(File::open(&msg_path)
                           .chain_err(|| read_error(&msg_path)).into());
    let mut msg = vec![];
    try!(msgfile.read_to_end(&mut msg).chain_err(|| read_error(&msg_path)));

    let signature_path = match signature_path {
        Some(path) => path,
        None => format!("{}.sig", msg_path)
    };

    let sig = try!(skey.sign(&msg).chain_err(|| "Failed to sign message"));

    let mut out = vec![];
    try!(sig.write(&mut out).chain_err(|| "Can't write to internal buffer"));

    let sig_comment = "signature from signify secret key";

    write_base64_file(&signature_path, sig_comment, &out)
        .chain_err(|| "Failed to write signature file")
}

fn read_password(prompt: &str) -> Result<String> {
    let mut stdout = std::io::stdout();
    try!(stdout.write_all(prompt.as_bytes()).chain_err(|| "Write to stdout failed"));
    try!(stdout.flush().chain_err(|| "Flushing stdout failed"));

    rpassword::read_password()
        .chain_err(|| "unable to read passphrase")
}

fn kdf(salt: &[u8], rounds: u32, confirm: bool, keylen: usize) -> Result<Vec<u8>> {
    let mut result = vec![0; keylen];
    if rounds == 0 {
        return Ok(result);
    }

    let passphrase = try!(read_password("passphrase: "));

    if confirm {
        let confirm_passphrase = try!(read_password("confirm passphrase: "));

        if passphrase != confirm_passphrase {
            return Err("passwords don't match".into());
        }
    }

    bcrypt_pbkdf(passphrase.as_bytes(), salt, rounds, &mut result);
    Ok(result)
}

fn generate(pubkey_path: String, privkey_path: String, comment: Option<String>, kdfrounds: u32) -> Result<()> {
    let comment = match comment {
        Some(s) => s,
        None    => "signify".into()
    };

    let mut keynum = [0; KEYNUMLEN];
    try!(SystemRandom.fill(&mut keynum).chain_err(|| "Can't fill keynum randomly"));

    let (_, keypair_bytes) = try!(Ed25519KeyPair::generate_serializable(&SystemRandom));
    let mut skey = keypair_bytes.private_key;
    let pkey = keypair_bytes.public_key;

    let mut salt = [0; 16];
    try!(SystemRandom.fill(&mut salt).chain_err(|| "Can't fill salt randomly"));

    let xorkey = try!(kdf(&salt, kdfrounds, true, SECRETBYTES));

    for (prv, xor) in skey.iter_mut().zip(xorkey.iter()) {
        *prv = *prv ^ xor;
    }

    // signify stores the extended key as the private key,
    // that is the 32 byte of the secret key, followed by the 32 byte of the public key,
    // summing up to 64 byte.
    //
    //  *ring* separates them, so we need to stick them together again.
    let mut complete_key = [0; 64];
    complete_key[0..32].copy_from_slice(&skey[0..32]);
    complete_key[32..].copy_from_slice(&pkey);

    // Store private key
    let digest = digest::digest(&digest::SHA512, &complete_key);
    let mut checksum = [0; 8];
    checksum.copy_from_slice(&digest.as_ref()[0..8]);

    let private_key = PrivateKey {
        pkgalg: PKGALG,
        kdfalg: KDFALG,
        kdfrounds: kdfrounds,
        salt: salt,
        checksum: checksum,
        keynum: keynum,
        seckey: complete_key,
    };

    let mut out = vec![];
    try!(private_key.write(&mut out).chain_err(|| "Can't write to internal buffer"));

    let priv_comment = format!("{} secret key", comment);
    try!(write_base64_file(&privkey_path, &priv_comment, &out)
        .chain_err(|| write_error(&privkey_path))
    );

    // Store public key
    let public_key = PublicKey::with_key_and_keynum(pkey, keynum);

    let mut out = vec![];
    try!(public_key.write(&mut out).chain_err(|| "Can't write to internal buffer"));

    let pub_comment = format!("{} public key", comment);
    write_base64_file(&pubkey_path, &pub_comment, &out)
        .chain_err(|| write_error(&pubkey_path))
}

fn human(res: Result<()>) {
    match res {
        Err(e) => {
            let mut it = e.iter();
            let e = it.next().unwrap();
            let next_err = it.next();
            if let Some(next_err) = next_err {
                println!("{}: {}", e, next_err);
            } else {
                println!("{}", e);
            }

            process::exit(1);
        },
        Ok(()) => {}
    }
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    if args.flag_V {
        human(verify(args.flag_p, args.flag_m, args.flag_x));
    } else if args.flag_G {
        let rounds = if args.flag_n { 0 } else { 42 };
        human(generate(args.flag_p, args.flag_s, args.flag_c, rounds));
    } else if args.flag_S {
        human(sign(args.flag_s, args.flag_m, args.flag_x));
    }
}
<commit_msg>refactor: Fix clippy warnings<commit_after>extern crate crypto;
extern crate base64;
extern crate byteorder;
extern crate docopt;
extern crate rustc_serialize;
extern crate rpassword;
extern crate ring;
extern crate untrusted;
#[macro_use]
extern crate error_chain;

use std::process;
use std::mem;
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::{OpenOptions, File};
use std::path::Path;

use ring::rand::SystemRandom;
use ring::signature::Ed25519KeyPair;
use ring::digest;
use crypto::bcrypt_pbkdf::bcrypt_pbkdf;

use docopt::Docopt;

mod structs;
mod errors;

use structs::*;
use errors::*;

const USAGE: &'static str = "
signify-rs

Usage:
  signify -h
  signify -G [-n] [-c <comment>] -p <pubkey> -s <seckey>
  signify -S [-x <sigfile>] -s <seckey> -m <message>
  signify -V [-x <sigfile>] -p <pubkey> -m <message>

Options:
  -h --help     Show this screen.
  -c <comment>  Specify the comment to be added during key generation.
  -m <message>  When signing, the file containing the message to sign.  When verifying, the file containing the
                message to verify.  When verifying with -e, the file to create.
  -n            Do not ask for a passphrase during key generation. Otherwise, signify will prompt the user for a
                passphrase to protect the secret key.
  -p <pubkey>   Public key produced by -G, and used by -V to check a signature.
  -s <seckey>   Secret (private) key produced by -G, and used by -S to sign a message.
  -x <sigfile>  The signature file to create or verify.  The default is <message>.sig.
";

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable)]
struct Args {
    flag_G: bool,
    flag_S: bool,
    flag_V: bool,

    flag_x: Option<String>,
    flag_c: Option<String>,

    flag_p: String,
    flag_s: String,
    flag_m: String,
    flag_n: bool,
}

enum FileContent {
    PublicKey(PublicKey),
    PrivateKey(PrivateKey),
    Signature(Signature),
}

fn write_base64_file<P: AsRef<Path>>(file: P, comment: &str, buf: &[u8]) -> Result<()> {
    let mut f = try!(OpenOptions::new().write(true).create_new(true).open(file));

    try!(write!(f, "{}", COMMENTHDR));
    try!(write!(f, "{}\n", comment));
    let out = base64::encode(buf);
    try!(write!(f, "{}\n", out));

    Ok(())
}

fn read_base64_file<P: AsRef<Path>>(file: P) -> Result<FileContent> {
    let file_display = format!("{}", file.as_ref().display());
    let f = try!(File::open(file));
    let mut reader = BufReader::new(f);

    let mut comment_line = String::new();
    let len = try!(reader.read_line(&mut comment_line));

    if len == 0 || len < COMMENTHDRLEN || !comment_line.starts_with(COMMENTHDR) {
        return Err(format!("invalid comment in {}; must start with '{}'", file_display, COMMENTHDR).into());
    }

    if &comment_line[len-1..len] != "\n" {
        return Err(format!("missing new line after comment in {}", file_display).into());
    }

    if len > COMMENTHDRLEN + COMMENTMAXLEN {
        return Err("comment too long".into());
    }

    let mut base64_line = String::new();
    let len = try!(reader.read_line(&mut base64_line));

    if len == 0 {
        return Err(format!("missing line in {}", file_display).into());
    }

    if &base64_line[len-1..len] != "\n" {
        return Err(format!("missing new line after comment in {}", file_display).into());
    }

    let base64_line = &base64_line[0..len-1];

    let data = try!(base64::decode(base64_line)
                    .chain_err(|| format!("invalid base64 encoding in {}", file_display)));

    if &data[0..2] != PKGALG {
        return Err(format!("unsupported file {}", file_display).into());
    }

    match data.len() {
        x if x == mem::size_of::<PublicKey>() => {
            PublicKey::from_buf(&data)
                .map(FileContent::PublicKey)
        }
        x if x == mem::size_of::<PrivateKey>() => {
            PrivateKey::from_buf(&data)
                .map(FileContent::PrivateKey)
        }
        x if x == mem::size_of::<Signature>() => {
            Signature::from_buf(&data)
                .map(FileContent::Signature)
        },
        _ => {
            Err(format!("unsupported file {}", file_display).into())
        }
    }
}

fn verify(pubkey_path: String, msg_path: String, signature_path: Option<String>) -> Result<()> {
    let pkey = match read_base64_file(&pubkey_path) {
        Ok(FileContent::PublicKey(pkey)) => pkey,
        _ => return Err("an error occured.".into()),
    };

    let signature_path = match signature_path {
        Some(path) => path,
        None => format!("{}.sig", msg_path)
    };

    let signature = match read_base64_file(&signature_path) {
        Ok(FileContent::Signature(sig)) => sig,
        _ => return Err(format!("Can't read signature from {}", signature_path).into()),
    };

    let mut msgfile = try!(File::open(&msg_path).chain_err(|| read_error(&msg_path)));
    let mut msg = vec![];
    try!(msgfile.read_to_end(&mut msg).chain_err(|| read_error(&msg_path)));

    if signature.keynum != pkey.keynum {
        return Err("signature verification failed: checked against wrong key".into());
    }

    if signature.verify(&msg, &pkey) {
        println!("Signature Verified");
        Ok(())
    } else {
        Err("signature verification failed".into())
    }
}

fn sign(seckey_path: String, msg_path: String, signature_path: Option<String>) -> Result<()> {
    let mut skey = match read_base64_file(&seckey_path) {
        Ok(FileContent::PrivateKey(skey)) => skey,
        _ => return Err("an error occured.".into()),
    };

    let rounds = skey.kdfrounds;
    let xorkey = try!(kdf(&skey.salt, rounds, false, SECRETBYTES));

    for (prv, xor) in skey.seckey.iter_mut().zip(xorkey.iter()) {
        *prv = *prv ^ xor;
    }
    let skey = skey;

    let mut msgfile = try!(File::open(&msg_path)
                           .chain_err(|| read_error(&msg_path)).into());
    let mut msg = vec![];
    try!(msgfile.read_to_end(&mut msg).chain_err(|| read_error(&msg_path)));

    let signature_path = match signature_path {
        Some(path) => path,
        None => format!("{}.sig", msg_path)
    };

    let sig = try!(skey.sign(&msg).chain_err(|| "Failed to sign message"));

    let mut out = vec![];
    try!(sig.write(&mut out).chain_err(|| "Can't write to internal buffer"));

    let sig_comment = "signature from signify secret key";

    write_base64_file(&signature_path, sig_comment, &out)
        .chain_err(|| "Failed to write signature file")
}

fn read_password(prompt: &str) -> Result<String> {
    let mut stdout = std::io::stdout();
    try!(stdout.write_all(prompt.as_bytes()).chain_err(|| "Write to stdout failed"));
    try!(stdout.flush().chain_err(|| "Flushing stdout failed"));

    rpassword::read_password()
        .chain_err(|| "unable to read passphrase")
}

fn kdf(salt: &[u8], rounds: u32, confirm: bool, keylen: usize) -> Result<Vec<u8>> {
    let mut result = vec![0; keylen];
    if rounds == 0 {
        return Ok(result);
    }

    let passphrase = try!(read_password("passphrase: "));

    if confirm {
        let confirm_passphrase = try!(read_password("confirm passphrase: "));

        if passphrase != confirm_passphrase {
            return Err("passwords don't match".into());
        }
    }

    bcrypt_pbkdf(passphrase.as_bytes(), salt, rounds, &mut result);
    Ok(result)
}

fn generate(pubkey_path: String, privkey_path: String, comment: Option<String>, kdfrounds: u32) -> Result<()> {
    let comment = match comment {
        Some(s) => s,
        None    => "signify".into()
    };

    let mut keynum = [0; KEYNUMLEN];
    try!(SystemRandom.fill(&mut keynum).chain_err(|| "Can't fill keynum randomly"));

    let (_, keypair_bytes) = try!(Ed25519KeyPair::generate_serializable(&SystemRandom));
    let mut skey = keypair_bytes.private_key;
    let pkey = keypair_bytes.public_key;

    let mut salt = [0; 16];
    try!(SystemRandom.fill(&mut salt).chain_err(|| "Can't fill salt randomly"));

    let xorkey = try!(kdf(&salt, kdfrounds, true, SECRETBYTES));

    for (prv, xor) in skey.iter_mut().zip(xorkey.iter()) {
        *prv = *prv ^ xor;
    }

    // signify stores the extended key as the private key,
    // that is the 32 byte of the secret key, followed by the 32 byte of the public key,
    // summing up to 64 byte.
    //
    //  *ring* separates them, so we need to stick them together again.
    let mut complete_key = [0; 64];
    complete_key[0..32].copy_from_slice(&skey[0..32]);
    complete_key[32..].copy_from_slice(&pkey);

    // Store private key
    let digest = digest::digest(&digest::SHA512, &complete_key);
    let mut checksum = [0; 8];
    checksum.copy_from_slice(&digest.as_ref()[0..8]);

    let private_key = PrivateKey {
        pkgalg: PKGALG,
        kdfalg: KDFALG,
        kdfrounds: kdfrounds,
        salt: salt,
        checksum: checksum,
        keynum: keynum,
        seckey: complete_key,
    };

    let mut out = vec![];
    try!(private_key.write(&mut out).chain_err(|| "Can't write to internal buffer"));

    let priv_comment = format!("{} secret key", comment);
    try!(write_base64_file(&privkey_path, &priv_comment, &out)
        .chain_err(|| write_error(&privkey_path))
    );

    // Store public key
    let public_key = PublicKey::with_key_and_keynum(pkey, keynum);

    let mut out = vec![];
    try!(public_key.write(&mut out).chain_err(|| "Can't write to internal buffer"));

    let pub_comment = format!("{} public key", comment);
    write_base64_file(&pubkey_path, &pub_comment, &out)
        .chain_err(|| write_error(&pubkey_path))
}

fn human(res: Result<()>) {
    match res {
        Err(e) => {
            let mut it = e.iter();
            let e = it.next().unwrap();
            let next_err = it.next();
            if let Some(next_err) = next_err {
                println!("{}: {}", e, next_err);
            } else {
                println!("{}", e);
            }

            process::exit(1);
        },
        Ok(()) => {}
    }
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    if args.flag_V {
        human(verify(args.flag_p, args.flag_m, args.flag_x));
    } else if args.flag_G {
        let rounds = if args.flag_n { 0 } else { 42 };
        human(generate(args.flag_p, args.flag_s, args.flag_c, rounds));
    } else if args.flag_S {
        human(sign(args.flag_s, args.flag_m, args.flag_x));
    }
}
<|endoftext|>


<commit_before>use ::wasm_opcodes::*;
use ::util::*;

#[no_mangle]
pub fn push_i32(buf: &mut Vec<u8>, v: i32) {
    buf.push(OP_I32CONST);
    write_leb_i32(buf, v);
}

#[no_mangle]
pub fn push_u32(buf: &mut Vec<u8>, v: u32) {
    buf.push(OP_I32CONST);
    write_leb_u32(buf, v);
}

#[no_mangle]
pub fn load_aligned_u16(buf: &mut Vec<u8>, addr: u32) {
    // doesn't cause a failure in the generated code, but it will be much slower
    dbg_assert!((addr & 1) == 0);

    buf.push(OP_I32CONST);
    write_leb_u32(buf, addr);
    buf.push(OP_I32LOAD16U);
    buf.push(MEM_ALIGN16);
    buf.push(MEM_IMM_OFFSET);
}

#[no_mangle]
pub fn load_aligned_i32(buf: &mut Vec<u8>, addr: u32) {
    // doesn't cause a failure in the generated code, but it will be much slower
    dbg_assert!((addr & 3) == 0);

    buf.push(OP_I32CONST);
    write_leb_u32(buf, addr);
    buf.push(OP_I32LOAD);
    buf.push(MEM_ALIGN32);
    buf.push(MEM_IMM_OFFSET);
}

#[no_mangle]
pub fn store_aligned_u16(buf: &mut Vec<u8>) {
    buf.push(OP_I32STORE16);
    buf.push(MEM_ALIGN16);
    buf.push(MEM_IMM_OFFSET);
}

#[no_mangle]
pub fn store_aligned_i32(buf: &mut Vec<u8>) {
    buf.push(OP_I32STORE);
    buf.push(MEM_ALIGN32);
    buf.push(MEM_IMM_OFFSET);
}

#[no_mangle]
pub fn add_i32(buf: &mut Vec<u8>) {
    buf.push(OP_I32ADD);
}

#[no_mangle]
pub fn and_i32(buf: &mut Vec<u8>) {
    buf.push(OP_I32AND);
}

#[no_mangle]
pub fn or_i32(buf: &mut Vec<u8>) {
    buf.push(OP_I32OR);
}

#[no_mangle]
pub fn shl_i32(buf: &mut Vec<u8>) {
    buf.push(OP_I32SHL);
}

#[no_mangle]
pub fn call_fn(buf: &mut Vec<u8>, fn_idx: u8) {
    buf.push(OP_CALL);
    buf.push(fn_idx);
}

#[no_mangle]
pub fn call_fn_with_arg(buf: &mut Vec<u8>, fn_idx: u8, arg0: i32) {
    push_i32(buf, arg0);
    call_fn(buf, fn_idx);
}
<commit_msg>add new wasm_util functions<commit_after>use ::wasm_opcodes::*;
use ::util::*;

#[no_mangle]
pub fn push_i32(buf: &mut Vec<u8>, v: i32) {
    buf.push(OP_I32CONST);
    write_leb_i32(buf, v);
}

#[no_mangle]
pub fn push_u32(buf: &mut Vec<u8>, v: u32) {
    buf.push(OP_I32CONST);
    write_leb_u32(buf, v);
}

#[no_mangle]
pub fn load_aligned_u16(buf: &mut Vec<u8>, addr: u32) {
    // doesn't cause a failure in the generated code, but it will be much slower
    dbg_assert!((addr & 1) == 0);

    buf.push(OP_I32CONST);
    write_leb_u32(buf, addr);
    buf.push(OP_I32LOAD16U);
    buf.push(MEM_ALIGN16);
    buf.push(MEM_IMM_OFFSET);
}

#[no_mangle]
pub fn load_aligned_i32(buf: &mut Vec<u8>, addr: u32) {
    // doesn't cause a failure in the generated code, but it will be much slower
    dbg_assert!((addr & 3) == 0);

    buf.push(OP_I32CONST);
    write_leb_u32(buf, addr);
    buf.push(OP_I32LOAD);
    buf.push(MEM_ALIGN32);
    buf.push(MEM_IMM_OFFSET);
}

#[no_mangle]
pub fn store_aligned_u16(buf: &mut Vec<u8>) {
    buf.push(OP_I32STORE16);
    buf.push(MEM_ALIGN16);
    buf.push(MEM_IMM_OFFSET);
}

#[no_mangle]
pub fn store_aligned_i32(buf: &mut Vec<u8>) {
    buf.push(OP_I32STORE);
    buf.push(MEM_ALIGN32);
    buf.push(MEM_IMM_OFFSET);
}

#[no_mangle]
pub fn add_i32(buf: &mut Vec<u8>) {
    buf.push(OP_I32ADD);
}

#[no_mangle]
pub fn and_i32(buf: &mut Vec<u8>) {
    buf.push(OP_I32AND);
}

#[no_mangle]
pub fn or_i32(buf: &mut Vec<u8>) {
    buf.push(OP_I32OR);
}

#[no_mangle]
pub fn shl_i32(buf: &mut Vec<u8>) {
    buf.push(OP_I32SHL);
}

#[no_mangle]
pub fn call_fn(buf: &mut Vec<u8>, fn_idx: u8) {
    buf.push(OP_CALL);
    buf.push(fn_idx);
}

#[no_mangle]
pub fn call_fn_with_arg(buf: &mut Vec<u8>, fn_idx: u8, arg0: i32) {
    push_i32(buf, arg0);
    call_fn(buf, fn_idx);
}

#[no_mangle]
pub fn eq_i32(buf: &mut Vec<u8>) {
    buf.push(OP_I32EQ);
}

#[no_mangle]
pub fn ne_i32(buf: &mut Vec<u8>) {
    buf.push(OP_I32NE);
}

#[no_mangle]
pub fn le_i32(buf: &mut Vec<u8>) {
    buf.push(OP_I32LES);
}

#[no_mangle]
pub fn lt_i32(buf: &mut Vec<u8>) {
    buf.push(OP_I32LTS);
}

#[no_mangle]
pub fn ge_i32(buf: &mut Vec<u8>) {
    buf.push(OP_I32GES);
}

#[no_mangle]
pub fn gt_i32(buf: &mut Vec<u8>) {
    buf.push(OP_I32GTS);
}
<|endoftext|>