<commit_before>#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate clap;

extern crate qrcode;
extern crate image;
extern crate regex;
extern crate urlparse;
extern crate term;

use clap::{App, AppSettings, Arg, Shell, SubCommand};
use qrcode::{QrCode, EcLevel};
use term::color;
use image::Luma;
use std::io::prelude::*;
use std::process::exit;
use std::fs;

mod payloads;

const WIFI_COMMAND: &'static str = "wifi";
const MAIL_COMMAND: &'static str = "mail";
const SMS_COMMAND: &'static str = "sms";
const MMS_COMMAND: &'static str = "mms";
const GEO_COMMAND: &'static str = "geo";
const PHONE_COMMAND: &'static str = "phone";
const SKYPE_COMMAND: &'static str = "skype";
const WHATSAPP_COMMAND: &'static str = "whatsapp";
const URL_COMMAND: &'static str = "url";
const BOOKMARK_COMMAND: &'static str = "bookmark";
const BITCOIN_COMMAND: &'static str = "bitcoin";
// const GIRO_COMMAND: &'static str = "giro";
// const CALENDAR_COMMAND: &'static str = "calendar";
// const CONTACT_COMMAND: &'static str = "contact";

/*TODO: add arguments for:
- Add help texts for the subcommands
- Add error texts for some exit branches (mostly file output and qrcode gen)
- implement different types of qr payloads
- write unit tests for the payloads
- write integration tests for edge case inputs
*/
fn main() {
    // match all input args
    let matches = build_cli().get_matches();

    // write the completions if they were requested, then exit and dont print any qr-code
    if let Some(comp) = matches.subcommand_matches("completions") {
        let dir = comp.value_of("comp_dir").unwrap();

        let shell = match comp.value_of("shell") {
            Some("ps") => Shell::PowerShell,
            Some("zsh") => Shell::Zsh,
            Some("fish") => Shell::Fish,
            _ => Shell::Bash,
        };

        // create directory if necessary
        fs::create_dir_all(&dir).unwrap();

        build_cli().gen_completions("qr", shell, dir);

        println!(
            "Completion file for the {:?} shell was writen to: {:?}",
            shell,
            dir
        );

        // exit and dont generate a qr-code
        exit(0);
    }

    // deduce the string payload
    let payload = get_payload(&matches);

    // should we draw a white border (safe zone) around the code?
    let safe = match matches.occurrences_of("safe_zone") {
        0 => true,
        _ => false,
    };

    // what error level can we expect? defaults to "H"
    let error: EcLevel = match matches.value_of("error").unwrap() {
        "L" => EcLevel::L,
        "M" => EcLevel::M,
        "Q" => EcLevel::Q,
        &_ => EcLevel::H,
    };

    //TODO: catch the possible errors
    let code = QrCode::with_error_correction_level(&payload, error).unwrap();

    // are we drawing to the terminal or to a file?
    match matches.occurrences_of("output") {
        1 => save(&code, safe, matches.value_of("output").unwrap()),
        _ => draw(&code, safe),
    }

    // shall we also print the payload to the screen?
    if matches.occurrences_of("payload") > 0 {
        println!("{:?}", payload);
    }
}

// deduces wich kind of string we are going to encode
fn get_payload(matches: &clap::ArgMatches) -> String {
    if let Some(sub) = matches.subcommand_matches(WIFI_COMMAND) {
        let auth = match sub.value_of("mode") {
            Some("WEP") => payloads::Authentication::WEP,
            Some("WPA") => payloads::Authentication::WPA,
            _ => payloads::Authentication::nopass,
        };
        return payloads::wifi_string(
            sub.value_of("ssid").unwrap(),
            sub.value_of("pwd").unwrap(),
            &auth,
            sub.value_of("hidden").unwrap() == "true",
        );
    } else if let Some(sub) = matches.subcommand_matches(MAIL_COMMAND) {
        let encoding = match sub.value_of("encoding") {
            Some("MATMSG") => payloads::MailEncoding::MATMSG,
            Some("SMTP") => payloads::MailEncoding::SMTP,
            _ => payloads::MailEncoding::MAILTO,
        };
        return payloads::mail_string(
            sub.value_of("receiver").unwrap(),
            sub.value_of("subject").unwrap(),
            sub.value_of("message").unwrap(),
            &encoding,
        );
    } else if let Some(sub) = matches.subcommand_matches(URL_COMMAND) {
        return payloads::url_string(sub.value_of("url").unwrap());
    } else if let Some(sub) = matches.subcommand_matches(PHONE_COMMAND) {
        return payloads::phone_string(sub.value_of("phone").unwrap());
    } else if let Some(sub) = matches.subcommand_matches(SKYPE_COMMAND) {
        return payloads::skype_string(sub.value_of("name").unwrap());
    } else if let Some(sub) = matches.subcommand_matches(WHATSAPP_COMMAND) {
        return payloads::whatsapp_string(sub.value_of("message").unwrap());
    } else if let Some(sub) = matches.subcommand_matches(SMS_COMMAND) {
        let encoding = match sub.value_of("encoding") {
            Some("SMSTO") => payloads::SMSEncoding::SMSTO,
            Some("SMS_iOS") => payloads::SMSEncoding::SMS_iOS,
            _ => payloads::SMSEncoding::SMS,
        };
        return payloads::sms_string(
            sub.value_of("number").unwrap(),
            sub.value_of("subject").unwrap(),
            &encoding,
        );
    } else if let Some(sub) = matches.subcommand_matches(MMS_COMMAND) {
        let encoding = match sub.value_of("encoding") {
            Some("MMSTO") => payloads::MMSEncoding::MMSTO,
            _ => payloads::MMSEncoding::MMS,
        };
        return payloads::mms_string(
            sub.value_of("number").unwrap(),
            sub.value_of("subject").unwrap(),
            &encoding,
        );
    } else if let Some(sub) = matches.subcommand_matches(GEO_COMMAND) {
        let encoding = match sub.value_of("encoding") {
            Some("GoogleMaps") => payloads::GeolocationEncoding::GoogleMaps,
            _ => payloads::GeolocationEncoding::GEO,
        };
        return payloads::geo_string(
            sub.value_of("latitude").unwrap(),
            sub.value_of("longitude").unwrap(),
            &encoding,
        );
    } else if let Some(sub) = matches.subcommand_matches(BOOKMARK_COMMAND) {
        return payloads::bookmark_string(
            sub.value_of("title").unwrap(),
            sub.value_of("url").unwrap(),
        );
    } else if let Some(sub) = matches.subcommand_matches(BITCOIN_COMMAND) {
        return payloads::bitcoin_string(
            sub.value_of("address").unwrap(),
            sub.value_of("amount").map(|a| a.parse::<f64>().unwrap_or_default()),
            sub.value_of("label"),
            sub.value_of("message"),
        );
    } else {
        return String::from(matches.value_of("INPUT").unwrap());
    }
}

// save to a file at the path
fn save(code: &QrCode, safe: bool, path: &str) {
    // render to a image struct
    let image = code.render::<Luma<u8>>().quiet_zone(safe).build();

    // save the image
    match image.save(path) {
        Ok(..) => println!("Image successfully saved to: {:?}", path),
        Err(e) => {
            println!(
                "Tried to create file but there was a problem: {:?}",
                if let Some(inner_err) = e.get_ref() {
                    inner_err.to_string()
                } else {
                    e.to_string()
                }
            )
        }
    };
}

// draw to the terminal
fn draw(code: &QrCode, safe: bool) {
    // get "bit" array
    let bit_array = code.to_colors();

    // get the terminal output pipe
    let mut t = term::stdout().unwrap();

    // get the code width and add extra space for the safe zone
    let w = code.width();
    let wide = w + 6;

    // draw the first white safe zone
    if safe {
        for a in 1..(wide * 3) + 1 {
            t.bg(color::BRIGHT_WHITE).unwrap();
            write!(t, "  ").unwrap();
            if a % wide == 0 {
                t.reset().unwrap();
                writeln!(t, "").unwrap();
            }
        }
    }

    // main drawing loop
    for (i, item) in bit_array.iter().enumerate() {
        // left safe zone
        if safe && i % w == 0 {
            t.bg(color::BRIGHT_WHITE).unwrap();
            write!(t, "      ").unwrap();
        }

        // draw black or white blocks
        if *item == qrcode::Color::Dark {
            t.bg(color::BLACK).unwrap();
            write!(t, "  ").unwrap();
        } else {
            t.bg(color::BRIGHT_WHITE).unwrap();
            write!(t, "  ").unwrap();
        }

        if (i + 1) % w == 0 {
            if safe {
                // draw right safe zone
                t.bg(color::BRIGHT_WHITE).unwrap();
                write!(t, "      ").unwrap();
            }
            t.reset().unwrap();
            writeln!(t, "").unwrap();
        }
    }

    // draw the last white safe zone
    if safe {
        for a in 1..(wide * 3) + 1 {
            t.bg(color::BRIGHT_WHITE).unwrap();
            write!(t, "  ").unwrap();
            if a % wide == 0 {
                t.reset().unwrap();
                writeln!(t, "").unwrap();
            }
        }
    }

    // reset to normal color and flush write buffer
    t.reset().unwrap();
    t.flush().unwrap();
}

// create the interface for the app with all subcommands, flags and args
fn build_cli() -> App<'static, 'static> {
    App::new(crate_name!())
        .version(crate_version!())
        .author(crate_authors!("\n"))
        .about(crate_description!())
        .global_setting(AppSettings::SubcommandsNegateReqs)
        .arg(
            Arg::with_name("safe_zone")
                .global(true)
                .short("s")
                .long("safe-zone")
                .help(
                    "Sets wether the safe zone around the code should be drawn or not.",
                )
                .takes_value(false),
        )
        .arg(
            Arg::with_name("output")
                .global(true)
                .short("o")
                .long("output")
                .help(
                    "Prints the QR-Code to a file.
            The image format is derived from the file extension.
            Currently only jpeg and png files are supported.",
                )
                .value_name("FILE"),
        )
        .arg(
            Arg::with_name("payload")
                .global(true)
                .short("p")
                .long("payload")
                .help(
                    "If this flag is set, the generated payload will also be printed to the terminal."
                )
                .takes_value(false)
        )
        .arg(
            Arg::with_name("error")
                .global(true)
                .short("e")
                .long("error")
                .help("Set the desired error correction level.")
                .value_name("LEVEL")
                .possible_values(&["L", "M", "Q", "H"])
                .default_value("H"),
        )
        .arg(
            Arg::with_name("INPUT")
                .help("The input string to use")
                .required(true),
        )
        .subcommand(
            SubCommand::with_name("completions")
                .about("Outputs completion files for various shells.")
                .arg(
                    Arg::with_name("comp_dir")
                        .required(true)
                        .help("The directory to write the completion file to.")
                        .value_name("DIR"),
                )
                .arg(
                    Arg::with_name("shell")
                        .long("shell")
                        .help("For which shell the completions should be generated for.")
                        .value_name("SHELL")
                        .possible_values(&["bash", "zsh", "fish", "ps"])
                        .default_value("bash"),
                ),
        )
        .subcommand(
            SubCommand::with_name(WIFI_COMMAND)
                .about("formats to a wifi access string QR-Code")
                .arg(Arg::with_name("ssid").required(true))
                .arg(Arg::with_name("pwd").required(true))
                .arg(
                    Arg::with_name("mode")
                        .value_name("MODE")
                        .possible_values(&["WEP", "WPA", "nopass"])
                        .default_value("WPA"),
                )
                .arg(
                    Arg::with_name("hidden")
                        .value_name("HIDDEN")
                        .possible_values(&["true", "false"])
                        .default_value("false"),
                ),
        )
        .subcommand(
            SubCommand::with_name(MAIL_COMMAND)
                .about("formats to a mail adress string QR-Code")
                .arg(Arg::with_name("receiver").required(true))
                .arg(Arg::with_name("subject"))
                .arg(Arg::with_name("message"))
                .arg(
                    Arg::with_name("encoding")
                        .value_name("ENCODING")
                        .possible_values(&["MAILTO", "MATMSG", "SMTP"])
                        .default_value("MAILTO"),
                ),
        )
        .subcommand(
            SubCommand::with_name(URL_COMMAND)
                .about("formats to an URL QR-Code")
                .arg(Arg::with_name("url").required(true).value_name("URL")),
        )
        .subcommand(
            SubCommand::with_name(PHONE_COMMAND)
                .about("formats to a phone number QR-Code")
                .arg(Arg::with_name("number").required(true).value_name("NUMBER")),
        )
        .subcommand(
            SubCommand::with_name(SKYPE_COMMAND)
                .about("formats to a skype call QR-Code")
                .arg(Arg::with_name("name").required(true).value_name("HANDLE")),
        )
        .subcommand(
            SubCommand::with_name(WHATSAPP_COMMAND)
                .about("formats to a whatsapp message QR-Code")
                .arg(Arg::with_name("message").required(true).value_name(
                    "MESSAGE",
                )),
        )
        .subcommand(
            SubCommand::with_name(SMS_COMMAND)
                .about("formats to a sms message QR-Code")
                .arg(Arg::with_name("number").required(true))
                .arg(Arg::with_name("subject").default_value(""))
                .arg(
                    Arg::with_name("encoding")
                        .possible_values(&["SMS", "SMSTO", "SMS_iOS"])
                        .default_value("SMS"),
                ),
        )
        .subcommand(
            SubCommand::with_name(MMS_COMMAND)
                .about("formats to a mms message QR-Code")
                .arg(Arg::with_name("number").required(true))
                .arg(Arg::with_name("subject").default_value(""))
                .arg(
                    Arg::with_name("encoding")
                        .possible_values(&["MMS", "MMSTO"])
                        .default_value("MMS"),
                ),
        )
        .subcommand(
            SubCommand::with_name(GEO_COMMAND)
                .about("formats to a geospacial location QR-Code")
                .arg(Arg::with_name("latitude").required(true))
                .arg(Arg::with_name("longitude").required(true))
                .arg(
                    Arg::with_name("encoding")
                        .possible_values(&["GEO", "GoogleMaps"])
                        .default_value("GEO"),
                ),
        )
        .subcommand(
            SubCommand::with_name(BOOKMARK_COMMAND)
                .about("formats to a bookmark QR-Code")
                .arg(Arg::with_name("title").required(true))
                .arg(Arg::with_name("url").required(true)),
        )
        .subcommand(
            SubCommand::with_name(BITCOIN_COMMAND)
                .about("outputs a bitcoin adress/transaction")
                .arg(Arg::with_name("address").required(true))
                .arg(Arg::with_name("amount"))
                .arg(Arg::with_name("label"))
                .arg(Arg::with_name("message")),
        )
}
<commit_msg>some clippy lints<commit_after>#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate clap;

extern crate qrcode;
extern crate image;
extern crate regex;
extern crate urlparse;
extern crate term;

use clap::{App, AppSettings, Arg, Shell, SubCommand};
use qrcode::{QrCode, EcLevel};
use term::color;
use image::Luma;
use std::io::prelude::*;
use std::process::exit;
use std::fs;

mod payloads;

const WIFI_COMMAND: &str = "wifi";
const MAIL_COMMAND: &str = "mail";
const SMS_COMMAND: &str = "sms";
const MMS_COMMAND: &str = "mms";
const GEO_COMMAND: &str = "geo";
const PHONE_COMMAND: &str = "phone";
const SKYPE_COMMAND: &str = "skype";
const WHATSAPP_COMMAND: &str = "whatsapp";
const URL_COMMAND: &str = "url";
const BOOKMARK_COMMAND: &str = "bookmark";
const BITCOIN_COMMAND: &str = "bitcoin";
// const GIRO_COMMAND: &'static str = "giro";
// const CALENDAR_COMMAND: &'static str = "calendar";
// const CONTACT_COMMAND: &'static str = "contact";

/*TODO: add arguments for:
- Add help texts for the subcommands
- Add error texts for some exit branches (mostly file output and qrcode gen)
- implement different types of qr payloads
- write unit tests for the payloads
- write integration tests for edge case inputs
*/
fn main() {
    // match all input args
    let matches = build_cli().get_matches();

    // write the completions if they were requested, then exit and dont print any qr-code
    if let Some(comp) = matches.subcommand_matches("completions") {
        let dir = comp.value_of("comp_dir").unwrap();

        let shell = match comp.value_of("shell") {
            Some("ps") => Shell::PowerShell,
            Some("zsh") => Shell::Zsh,
            Some("fish") => Shell::Fish,
            _ => Shell::Bash,
        };

        // create directory if necessary
        fs::create_dir_all(&dir).unwrap();

        build_cli().gen_completions("qr", shell, dir);

        println!(
            "Completion file for the {:?} shell was writen to: {:?}",
            shell,
            dir
        );

        // exit and dont generate a qr-code
        exit(0);
    }

    // deduce the string payload
    let payload = get_payload(&matches);

    // should we draw a white border (safe zone) around the code?
    let safe = match matches.occurrences_of("safe_zone") {
        0 => true,
        _ => false,
    };

    // what error level can we expect? defaults to "H"
    let error: EcLevel = match matches.value_of("error").unwrap() {
        "L" => EcLevel::L,
        "M" => EcLevel::M,
        "Q" => EcLevel::Q,
        &_ => EcLevel::H,
    };

    //TODO: catch the possible errors
    let code = QrCode::with_error_correction_level(&payload, error).unwrap();

    // are we drawing to the terminal or to a file?
    match matches.occurrences_of("output") {
        1 => save(&code, safe, matches.value_of("output").unwrap()),
        _ => draw(&code, safe),
    }

    // shall we also print the payload to the screen?
    if matches.occurrences_of("payload") > 0 {
        println!("{:?}", payload);
    }
}

// deduces wich kind of string we are going to encode
fn get_payload(matches: &clap::ArgMatches) -> String {
    if let Some(sub) = matches.subcommand_matches(WIFI_COMMAND) {
        let auth = match sub.value_of("mode") {
            Some("WEP") => payloads::Authentication::WEP,
            Some("WPA") => payloads::Authentication::WPA,
            _ => payloads::Authentication::nopass,
        };
        return payloads::wifi_string(
            sub.value_of("ssid").unwrap(),
            sub.value_of("pwd").unwrap(),
            &auth,
            sub.value_of("hidden").unwrap() == "true",
        );
    } else if let Some(sub) = matches.subcommand_matches(MAIL_COMMAND) {
        let encoding = match sub.value_of("encoding") {
            Some("MATMSG") => payloads::MailEncoding::MATMSG,
            Some("SMTP") => payloads::MailEncoding::SMTP,
            _ => payloads::MailEncoding::MAILTO,
        };
        return payloads::mail_string(
            sub.value_of("receiver").unwrap(),
            sub.value_of("subject").unwrap(),
            sub.value_of("message").unwrap(),
            &encoding,
        );
    } else if let Some(sub) = matches.subcommand_matches(URL_COMMAND) {
        return payloads::url_string(sub.value_of("url").unwrap());
    } else if let Some(sub) = matches.subcommand_matches(PHONE_COMMAND) {
        return payloads::phone_string(sub.value_of("phone").unwrap());
    } else if let Some(sub) = matches.subcommand_matches(SKYPE_COMMAND) {
        return payloads::skype_string(sub.value_of("name").unwrap());
    } else if let Some(sub) = matches.subcommand_matches(WHATSAPP_COMMAND) {
        return payloads::whatsapp_string(sub.value_of("message").unwrap());
    } else if let Some(sub) = matches.subcommand_matches(SMS_COMMAND) {
        let encoding = match sub.value_of("encoding") {
            Some("SMSTO") => payloads::SMSEncoding::SMSTO,
            Some("SMS_iOS") => payloads::SMSEncoding::SMS_iOS,
            _ => payloads::SMSEncoding::SMS,
        };
        return payloads::sms_string(
            sub.value_of("number").unwrap(),
            sub.value_of("subject").unwrap(),
            &encoding,
        );
    } else if let Some(sub) = matches.subcommand_matches(MMS_COMMAND) {
        let encoding = match sub.value_of("encoding") {
            Some("MMSTO") => payloads::MMSEncoding::MMSTO,
            _ => payloads::MMSEncoding::MMS,
        };
        return payloads::mms_string(
            sub.value_of("number").unwrap(),
            sub.value_of("subject").unwrap(),
            &encoding,
        );
    } else if let Some(sub) = matches.subcommand_matches(GEO_COMMAND) {
        let encoding = match sub.value_of("encoding") {
            Some("GoogleMaps") => payloads::GeolocationEncoding::GoogleMaps,
            _ => payloads::GeolocationEncoding::GEO,
        };
        return payloads::geo_string(
            sub.value_of("latitude").unwrap(),
            sub.value_of("longitude").unwrap(),
            &encoding,
        );
    } else if let Some(sub) = matches.subcommand_matches(BOOKMARK_COMMAND) {
        return payloads::bookmark_string(
            sub.value_of("title").unwrap(),
            sub.value_of("url").unwrap(),
        );
    } else if let Some(sub) = matches.subcommand_matches(BITCOIN_COMMAND) {
        return payloads::bitcoin_string(
            sub.value_of("address").unwrap(),
            sub.value_of("amount").map(|a| a.parse::<f64>().unwrap_or_default()),
            sub.value_of("label"),
            sub.value_of("message"),
        );
    } else {
        return String::from(matches.value_of("INPUT").unwrap());
    }
}

// save to a file at the path
fn save(code: &QrCode, safe: bool, path: &str) {
    // render to a image struct
    let image = code.render::<Luma<u8>>().quiet_zone(safe).build();

    // save the image
    match image.save(path) {
        Ok(..) => println!("Image successfully saved to: {:?}", path),
        Err(e) => {
            println!(
                "Tried to create file but there was a problem: {:?}",
                if let Some(inner_err) = e.get_ref() {
                    inner_err.to_string()
                } else {
                    e.to_string()
                }
            )
        }
    };
}

// draw to the terminal
fn draw(code: &QrCode, safe: bool) {
    // get "bit" array
    let bit_array = code.to_colors();

    // get the terminal output pipe
    let mut t = term::stdout().unwrap();

    // get the code width and add extra space for the safe zone
    let w = code.width();
    let wide = w + 6;

    // draw the first white safe zone
    if safe {
        for a in 1..(wide * 3) + 1 {
            t.bg(color::BRIGHT_WHITE).unwrap();
            write!(t, "  ").unwrap();
            if a % wide == 0 {
                t.reset().unwrap();
                writeln!(t, "").unwrap();
            }
        }
    }

    // main drawing loop
    for (i, item) in bit_array.iter().enumerate() {
        // left safe zone
        if safe && i % w == 0 {
            t.bg(color::BRIGHT_WHITE).unwrap();
            write!(t, "      ").unwrap();
        }

        // draw black or white blocks
        if *item == qrcode::Color::Dark {
            t.bg(color::BLACK).unwrap();
            write!(t, "  ").unwrap();
        } else {
            t.bg(color::BRIGHT_WHITE).unwrap();
            write!(t, "  ").unwrap();
        }

        if (i + 1) % w == 0 {
            if safe {
                // draw right safe zone
                t.bg(color::BRIGHT_WHITE).unwrap();
                write!(t, "      ").unwrap();
            }
            t.reset().unwrap();
            writeln!(t, "").unwrap();
        }
    }

    // draw the last white safe zone
    if safe {
        for a in 1..(wide * 3) + 1 {
            t.bg(color::BRIGHT_WHITE).unwrap();
            write!(t, "  ").unwrap();
            if a % wide == 0 {
                t.reset().unwrap();
                writeln!(t, "").unwrap();
            }
        }
    }

    // reset to normal color and flush write buffer
    t.reset().unwrap();
    t.flush().unwrap();
}

// create the interface for the app with all subcommands, flags and args
fn build_cli() -> App<'static, 'static> {
    App::new(crate_name!())
        .version(crate_version!())
        .author(crate_authors!("\n"))
        .about(crate_description!())
        .global_setting(AppSettings::SubcommandsNegateReqs)
        .arg(
            Arg::with_name("safe_zone")
                .global(true)
                .short("s")
                .long("safe-zone")
                .help(
                    "Sets wether the safe zone around the code should be drawn or not.",
                )
                .takes_value(false),
        )
        .arg(
            Arg::with_name("output")
                .global(true)
                .short("o")
                .long("output")
                .help(
                    "Prints the QR-Code to a file.
            The image format is derived from the file extension.
            Currently only jpeg and png files are supported.",
                )
                .value_name("FILE"),
        )
        .arg(
            Arg::with_name("payload")
                .global(true)
                .short("p")
                .long("payload")
                .help(
                    "If this flag is set, the generated payload will also be printed to the terminal."
                )
                .takes_value(false)
        )
        .arg(
            Arg::with_name("error")
                .global(true)
                .short("e")
                .long("error")
                .help("Set the desired error correction level.")
                .value_name("LEVEL")
                .possible_values(&["L", "M", "Q", "H"])
                .default_value("H"),
        )
        .arg(
            Arg::with_name("INPUT")
                .help("The input string to use")
                .required(true),
        )
        .subcommand(
            SubCommand::with_name("completions")
                .about("Outputs completion files for various shells.")
                .arg(
                    Arg::with_name("comp_dir")
                        .required(true)
                        .help("The directory to write the completion file to.")
                        .value_name("DIR"),
                )
                .arg(
                    Arg::with_name("shell")
                        .long("shell")
                        .help("For which shell the completions should be generated for.")
                        .value_name("SHELL")
                        .possible_values(&["bash", "zsh", "fish", "ps"])
                        .default_value("bash"),
                ),
        )
        .subcommand(
            SubCommand::with_name(WIFI_COMMAND)
                .about("formats to a wifi access string QR-Code")
                .arg(Arg::with_name("ssid").required(true))
                .arg(Arg::with_name("pwd").required(true))
                .arg(
                    Arg::with_name("mode")
                        .value_name("MODE")
                        .possible_values(&["WEP", "WPA", "nopass"])
                        .default_value("WPA"),
                )
                .arg(
                    Arg::with_name("hidden")
                        .value_name("HIDDEN")
                        .possible_values(&["true", "false"])
                        .default_value("false"),
                ),
        )
        .subcommand(
            SubCommand::with_name(MAIL_COMMAND)
                .about("formats to a mail adress string QR-Code")
                .arg(Arg::with_name("receiver").required(true))
                .arg(Arg::with_name("subject"))
                .arg(Arg::with_name("message"))
                .arg(
                    Arg::with_name("encoding")
                        .value_name("ENCODING")
                        .possible_values(&["MAILTO", "MATMSG", "SMTP"])
                        .default_value("MAILTO"),
                ),
        )
        .subcommand(
            SubCommand::with_name(URL_COMMAND)
                .about("formats to an URL QR-Code")
                .arg(Arg::with_name("url").required(true).value_name("URL")),
        )
        .subcommand(
            SubCommand::with_name(PHONE_COMMAND)
                .about("formats to a phone number QR-Code")
                .arg(Arg::with_name("number").required(true).value_name("NUMBER")),
        )
        .subcommand(
            SubCommand::with_name(SKYPE_COMMAND)
                .about("formats to a skype call QR-Code")
                .arg(Arg::with_name("name").required(true).value_name("HANDLE")),
        )
        .subcommand(
            SubCommand::with_name(WHATSAPP_COMMAND)
                .about("formats to a whatsapp message QR-Code")
                .arg(Arg::with_name("message").required(true).value_name(
                    "MESSAGE",
                )),
        )
        .subcommand(
            SubCommand::with_name(SMS_COMMAND)
                .about("formats to a sms message QR-Code")
                .arg(Arg::with_name("number").required(true))
                .arg(Arg::with_name("subject").default_value(""))
                .arg(
                    Arg::with_name("encoding")
                        .possible_values(&["SMS", "SMSTO", "SMS_iOS"])
                        .default_value("SMS"),
                ),
        )
        .subcommand(
            SubCommand::with_name(MMS_COMMAND)
                .about("formats to a mms message QR-Code")
                .arg(Arg::with_name("number").required(true))
                .arg(Arg::with_name("subject").default_value(""))
                .arg(
                    Arg::with_name("encoding")
                        .possible_values(&["MMS", "MMSTO"])
                        .default_value("MMS"),
                ),
        )
        .subcommand(
            SubCommand::with_name(GEO_COMMAND)
                .about("formats to a geospacial location QR-Code")
                .arg(Arg::with_name("latitude").required(true))
                .arg(Arg::with_name("longitude").required(true))
                .arg(
                    Arg::with_name("encoding")
                        .possible_values(&["GEO", "GoogleMaps"])
                        .default_value("GEO"),
                ),
        )
        .subcommand(
            SubCommand::with_name(BOOKMARK_COMMAND)
                .about("formats to a bookmark QR-Code")
                .arg(Arg::with_name("title").required(true))
                .arg(Arg::with_name("url").required(true)),
        )
        .subcommand(
            SubCommand::with_name(BITCOIN_COMMAND)
                .about("outputs a bitcoin adress/transaction")
                .arg(Arg::with_name("address").required(true))
                .arg(Arg::with_name("amount"))
                .arg(Arg::with_name("label"))
                .arg(Arg::with_name("message")),
        )
}
<|endoftext|>


<commit_before>#[macro_use] extern crate conrod;
extern crate gfx_device_gl;
extern crate graphics;
extern crate piston;
extern crate piston_window;
extern crate sdl2_window;
extern crate vecmath as vecmath_lib;

use std::path::Path;

use conrod::{Labelable, Positionable, Sizeable, Widget};
use piston::window::{AdvancedWindow, WindowSettings};
use piston_window::{Context, G2d, OpenGL, PistonWindow};
use piston::event_loop::*;
use piston::input::*;
use sdl2_window::Sdl2Window;

mod map;
mod vecmath;

/// A transition requested by a game state.
enum StateTransition {
    /// Stay on this state.
    Continue,
    /// End this state and pop it from the stack.
    End,
    /// Pop this state and replace it with this new state.
    Replace(Box<GameState>),
    /// Keep this state, but pause it and push the state on top of the stack.
    Push(Box<GameState>),
}

/// A state the game can be in.
///
/// The application consists of a stack of states, that can each push other
/// states on the stack and/or pop themselves.
/// Examples of states are the main menu, the character selection, or the game
/// itself; starting the game finishes the character selection, but the main
/// menu remains accessible.
trait GameState {
    fn handle_event(&mut self, event: &piston::input::Event<piston::input::Input>, resources: &mut Resources) {}
    fn update(&mut self, dt: f64) -> StateTransition;
    fn draw(&mut self, c: Context, g: &mut G2d);
    fn pause(&mut self) {}
    fn resume(&mut self) {}
}

struct Resources {
    window: PistonWindow<Sdl2Window>,
    width: u32,
    height: u32,
}

struct App {
    states: Vec<Box<GameState>>,
    resources: Resources,
}

impl App {
    fn new() -> App {
        let width = 200;
        let height = 200;

        // Change this to OpenGL::V2_1 if not working.
        let opengl = OpenGL::V3_2;

        // Create an SDL2 window.
        let window: PistonWindow<Sdl2Window> = WindowSettings::new(
                "fluffy-fiesta",
                [width, height]
            )
            .opengl(opengl)
            .build()
            .unwrap();

        let mut app = App {
            states: Vec::new(),
            resources: Resources {
                window: window,
            width: width,
            height: height,
            },
        };
        let game = Game::new(&mut app.resources);
        app.states.push(Box::new(game));
        app
    }

    fn run(&mut self) {
        loop {
            let transition: StateTransition = if let Some(state) = self.states.last_mut() {
                Self::handle_state(&mut self.resources, state)
            } else {
                break
            };
            match transition {
                StateTransition::Continue => panic!("App::run() got Transition::Continue"),
                StateTransition::End => {
                    self.states.pop().expect("Transition::End with no states");
                }
                StateTransition::Replace(state) => {
                    self.states.pop().expect("Transition::Replace with no states");
                    self.states.push(state);
                }
                StateTransition::Push(state) => {
                    self.states.push(state);
                }
            }
        }
    }

    fn handle_state(resources: &mut Resources, state: &mut Box<GameState>) -> StateTransition {
        state.resume();

        let mut events = resources.window.events();
        while let Some(event) = events.next(&mut resources.window) {
            // Handle generic event
            state.handle_event(&event, resources);

            // Call update method
            if let Some(u) = event.update_args() {
                let transition = state.update(u.dt);
                match transition {
                    StateTransition::Continue => {},
                    t => return t,
                }
            }

            // Call draw method
            resources.window.draw_2d(&event, |c, g| state.draw(c, g));
        }
        StateTransition::End
    }
}

fn main() {
    let mut app = App::new();
    app.run();
}

widget_ids!(struct GameWidgetIds { canvas, resume, quit });

struct Game {
    rotation: f64,  // Rotation for the square.
    ui: conrod::Ui,
    widget_ids: GameWidgetIds,
    capture: bool,
    ui_on: bool,
    quit: bool,
    // FIXME: Spelling out gfx_device_gl (and direct dep) shouldn't be necessary
    image_map: conrod::image::Map<piston_window::Texture<gfx_device_gl::Resources>>,
    text_texture_cache: conrod::backend::piston_window::GlyphCache,
}

impl Game {
    fn new(resources: &mut Resources) -> Game {
        // Construct our `Ui`.
        let mut ui = conrod::UiBuilder::new().build();

        // Generate the widget identifiers.
        let ids = GameWidgetIds::new(ui.widget_id_generator());

        // Add a `Font` to the `Ui`'s `font::Map` from file.
        let font_path = Path::new("assets/NotoSans-Regular.ttf");
        assert!(font_path.exists());
        ui.fonts.insert_from_file(font_path).unwrap();

        // Create a texture to use for efficiently caching text on the GPU.
        let text_texture_cache =
            conrod::backend::piston_window::GlyphCache::new(&mut resources.window,
                                                            resources.width,
                                                            resources.height);

        // The image map describing each of our widget->image mappings (in our case, none).
        let image_map = conrod::image::Map::new();

        Game {
            rotation: 0.0,
            ui: ui,
            widget_ids: ids,
            capture: false,
            ui_on: false,
            quit: false,
            image_map: image_map,
            text_texture_cache: text_texture_cache,
        }
    }
}

impl GameState for Game {
    fn handle_event(&mut self, event: &piston::input::Event<piston::input::Input>, resources: &mut Resources) {
        // Convert the piston event to a conrod event.
        if let Some(ce) = conrod::backend::piston_window::convert_event(event.clone(), &mut resources.window) {
            self.ui.handle_event(ce);
        }

        if self.ui_on {
            let ui = &mut self.ui.set_widgets();

            // Create a background canvas upon which we'll place the button.
            conrod::widget::Canvas::new().floating(true).w_h(100.0, 70.0).pad(10.0).middle()
                .set(self.widget_ids.canvas, ui);

            // Draw the buttons.
            if conrod::widget::Button::new()
                .mid_top_of(self.widget_ids.canvas)
                .w_h(80.0, 20.0)
                .label("Resume")
                .set(self.widget_ids.resume, ui)
                .was_clicked()
            {
                self.ui_on = false;
            }

            if conrod::widget::Button::new()
                .down(10.0)
                .w_h(80.0, 20.0)
                .label("Quit")
                .set(self.widget_ids.quit, ui)
                .was_clicked()
            {
                self.quit = true;
            }
        }

        if let Some(Button::Mouse(button)) = event.press_args() {
            println!("Pressed mouse button '{:?}'", button);
        }

        if let Some(Button::Keyboard(key)) = event.press_args() {
            println!("Pressed key '{:?}'", key);
            if key == Key::Escape {
                println!("ui on");
                self.ui_on = true;
                if self.capture {
                    self.capture = false;
                    resources.window.set_capture_cursor(false);
                }
            } else if !self.ui_on && key == Key::C {
                self.capture = !self.capture;
                resources.window.set_capture_cursor(self.capture);
                println!("capture {}", if self.capture { "on" } else { "off" });
            }
        }
    }

    fn update(&mut self, dt: f64) -> StateTransition {
        // Rotate 2 radians per second.
        self.rotation += 2.0 * dt;

        if self.quit {
            StateTransition::End
        } else {
            StateTransition::Continue
        }
    }

    fn draw(&mut self, c: Context, g: &mut G2d) {
        use graphics::*;

        const GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0];
        const RED:   [f32; 4] = [1.0, 0.0, 0.0, 1.0];

        let square = rectangle::square(0.0, 0.0, 150.0);
        let rotation = self.rotation;
        let (x, y) = (100.0, 100.0);

        // Clear the screen.
        clear(GREEN, g);

        let transform = c.transform.trans(x, y)
                                   .rot_rad(rotation)
                                   .trans(-75.0, -75.0);

        // Draw a box rotating around the middle of the screen.
        rectangle(RED, square, transform, g);

        if self.ui_on {
            let primitives = self.ui.draw();
            fn texture_from_image<T>(img: &T) -> &T { img };
            conrod::backend::piston_window::draw(c, g, primitives,
                                                 &mut self.text_texture_cache,
                                                 &self.image_map,
                                                 texture_from_image);
        }
    }
}
<commit_msg>Correctly cause pause()<commit_after>#[macro_use] extern crate conrod;
extern crate gfx_device_gl;
extern crate graphics;
extern crate piston;
extern crate piston_window;
extern crate sdl2_window;
extern crate vecmath as vecmath_lib;

use std::path::Path;

use conrod::{Labelable, Positionable, Sizeable, Widget};
use piston::window::{AdvancedWindow, WindowSettings};
use piston_window::{Context, G2d, OpenGL, PistonWindow};
use piston::event_loop::*;
use piston::input::*;
use sdl2_window::Sdl2Window;

mod map;
mod vecmath;

/// A transition requested by a game state.
enum StateTransition {
    /// Stay on this state.
    Continue,
    /// End this state and pop it from the stack.
    End,
    /// Pop this state and replace it with this new state.
    Replace(Box<GameState>),
    /// Keep this state, but pause it and push the state on top of the stack.
    Push(Box<GameState>),
}

/// A state the game can be in.
///
/// The application consists of a stack of states, that can each push other
/// states on the stack and/or pop themselves.
/// Examples of states are the main menu, the character selection, or the game
/// itself; starting the game finishes the character selection, but the main
/// menu remains accessible.
trait GameState {
    fn handle_event(&mut self, event: &piston::input::Event<piston::input::Input>, resources: &mut Resources) {}
    fn update(&mut self, dt: f64) -> StateTransition;
    fn draw(&mut self, c: Context, g: &mut G2d);
    fn pause(&mut self) {}
    fn resume(&mut self) {}
}

struct Resources {
    window: PistonWindow<Sdl2Window>,
    width: u32,
    height: u32,
}

struct App {
    states: Vec<Box<GameState>>,
    resources: Resources,
}

impl App {
    fn new() -> App {
        let width = 200;
        let height = 200;

        // Change this to OpenGL::V2_1 if not working.
        let opengl = OpenGL::V3_2;

        // Create an SDL2 window.
        let window: PistonWindow<Sdl2Window> = WindowSettings::new(
                "fluffy-fiesta",
                [width, height]
            )
            .opengl(opengl)
            .build()
            .unwrap();

        let mut app = App {
            states: Vec::new(),
            resources: Resources {
                window: window,
            width: width,
            height: height,
            },
        };
        let game = Game::new(&mut app.resources);
        app.states.push(Box::new(game));
        app
    }

    fn run(&mut self) {
        loop {
            let transition: StateTransition = if let Some(state) = self.states.last_mut() {
                Self::handle_state(&mut self.resources, state)
            } else {
                break
            };
            match transition {
                StateTransition::Continue => panic!("App::run() got Transition::Continue"),
                StateTransition::End => {
                    self.states.pop().expect("Transition::End with no states");
                }
                StateTransition::Replace(state) => {
                    self.states.pop().expect("Transition::Replace with no states");
                    self.states.push(state);
                }
                StateTransition::Push(state) => {
                    self.states.push(state);
                }
            }
        }
    }

    fn handle_state(resources: &mut Resources, state: &mut Box<GameState>) -> StateTransition {
        state.resume();

        let mut events = resources.window.events();
        while let Some(event) = events.next(&mut resources.window) {
            // Handle generic event
            state.handle_event(&event, resources);

            // Call update method
            if let Some(u) = event.update_args() {
                let transition = state.update(u.dt);
                match transition {
                    StateTransition::Continue => {},
                    t => {
                        state.pause();
                        return t;
                    }
                }
            }

            // Call draw method
            resources.window.draw_2d(&event, |c, g| state.draw(c, g));
        }
        state.pause();
        StateTransition::End
    }
}

fn main() {
    let mut app = App::new();
    app.run();
}

widget_ids!(struct GameWidgetIds { canvas, resume, quit });

struct Game {
    rotation: f64,  // Rotation for the square.
    ui: conrod::Ui,
    widget_ids: GameWidgetIds,
    capture: bool,
    ui_on: bool,
    quit: bool,
    // FIXME: Spelling out gfx_device_gl (and direct dep) shouldn't be necessary
    image_map: conrod::image::Map<piston_window::Texture<gfx_device_gl::Resources>>,
    text_texture_cache: conrod::backend::piston_window::GlyphCache,
}

impl Game {
    fn new(resources: &mut Resources) -> Game {
        // Construct our `Ui`.
        let mut ui = conrod::UiBuilder::new().build();

        // Generate the widget identifiers.
        let ids = GameWidgetIds::new(ui.widget_id_generator());

        // Add a `Font` to the `Ui`'s `font::Map` from file.
        let font_path = Path::new("assets/NotoSans-Regular.ttf");
        assert!(font_path.exists());
        ui.fonts.insert_from_file(font_path).unwrap();

        // Create a texture to use for efficiently caching text on the GPU.
        let text_texture_cache =
            conrod::backend::piston_window::GlyphCache::new(&mut resources.window,
                                                            resources.width,
                                                            resources.height);

        // The image map describing each of our widget->image mappings (in our case, none).
        let image_map = conrod::image::Map::new();

        Game {
            rotation: 0.0,
            ui: ui,
            widget_ids: ids,
            capture: false,
            ui_on: false,
            quit: false,
            image_map: image_map,
            text_texture_cache: text_texture_cache,
        }
    }
}

impl GameState for Game {
    fn handle_event(&mut self, event: &piston::input::Event<piston::input::Input>, resources: &mut Resources) {
        // Convert the piston event to a conrod event.
        if let Some(ce) = conrod::backend::piston_window::convert_event(event.clone(), &mut resources.window) {
            self.ui.handle_event(ce);
        }

        if self.ui_on {
            let ui = &mut self.ui.set_widgets();

            // Create a background canvas upon which we'll place the button.
            conrod::widget::Canvas::new().floating(true).w_h(100.0, 70.0).pad(10.0).middle()
                .set(self.widget_ids.canvas, ui);

            // Draw the buttons.
            if conrod::widget::Button::new()
                .mid_top_of(self.widget_ids.canvas)
                .w_h(80.0, 20.0)
                .label("Resume")
                .set(self.widget_ids.resume, ui)
                .was_clicked()
            {
                self.ui_on = false;
            }

            if conrod::widget::Button::new()
                .down(10.0)
                .w_h(80.0, 20.0)
                .label("Quit")
                .set(self.widget_ids.quit, ui)
                .was_clicked()
            {
                self.quit = true;
            }
        }

        if let Some(Button::Mouse(button)) = event.press_args() {
            println!("Pressed mouse button '{:?}'", button);
        }

        if let Some(Button::Keyboard(key)) = event.press_args() {
            println!("Pressed key '{:?}'", key);
            if key == Key::Escape {
                println!("ui on");
                self.ui_on = true;
                if self.capture {
                    self.capture = false;
                    resources.window.set_capture_cursor(false);
                }
            } else if !self.ui_on && key == Key::C {
                self.capture = !self.capture;
                resources.window.set_capture_cursor(self.capture);
                println!("capture {}", if self.capture { "on" } else { "off" });
            }
        }
    }

    fn update(&mut self, dt: f64) -> StateTransition {
        // Rotate 2 radians per second.
        self.rotation += 2.0 * dt;

        if self.quit {
            StateTransition::End
        } else {
            StateTransition::Continue
        }
    }

    fn draw(&mut self, c: Context, g: &mut G2d) {
        use graphics::*;

        const GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0];
        const RED:   [f32; 4] = [1.0, 0.0, 0.0, 1.0];

        let square = rectangle::square(0.0, 0.0, 150.0);
        let rotation = self.rotation;
        let (x, y) = (100.0, 100.0);

        // Clear the screen.
        clear(GREEN, g);

        let transform = c.transform.trans(x, y)
                                   .rot_rad(rotation)
                                   .trans(-75.0, -75.0);

        // Draw a box rotating around the middle of the screen.
        rectangle(RED, square, transform, g);

        if self.ui_on {
            let primitives = self.ui.draw();
            fn texture_from_image<T>(img: &T) -> &T { img };
            conrod::backend::piston_window::draw(c, g, primitives,
                                                 &mut self.text_texture_cache,
                                                 &self.image_map,
                                                 texture_from_image);
        }
    }
}
<|endoftext|>


<commit_before>#![crate_name = "rboy"]

extern crate clap;
extern crate sdl2;
extern crate rboy;

use rboy::device::Device;
use std::sync::{Arc,RwLock};
use std::sync::mpsc::{Sender,Receiver};
use std::sync::mpsc::TryRecvError::{Disconnected,Empty};
use std::sync::atomic;
use std::sync::atomic::Ordering::Relaxed;

const SCALE : u32 = 2;
const EXITCODE_SUCCESS : isize = 0;
const EXITCODE_CPULOADFAILS : isize = 2;

static EXITCODE : atomic::AtomicIsize = atomic::ATOMIC_ISIZE_INIT;

fn main() {
    set_exit_status(EXITCODE_SUCCESS);
    real_main();
    std::process::exit(EXITCODE.load(Relaxed) as i32);
}

fn set_exit_status(status: isize) {
    EXITCODE.store(status, Relaxed);
}

fn real_main() {
    let matches = clap::App::new("rboy")
        .version("0.1")
        .author("Mathijs van de Nes")
        .about("A Gameboy Colour emulator written in Rust")
        .arg(clap::Arg::with_name("filename")
             .help("Sets the ROM file to load")
             .required(true))
        .arg(clap::Arg::with_name("serial")
             .help("Prints the data from the serial port to stdout")
             .short("s")
             .long("serial"))
        .arg(clap::Arg::with_name("classic")
             .help("Forces the emulator to run in classic Gameboy mode")
             .short("c")
             .long("classic"))
        .get_matches();

    let opt_serial = matches.is_present("serial");
    let opt_classic = matches.is_present("classic");
    let filename = matches.value_of("filename").unwrap();

    let cpu = construct_cpu(filename, opt_classic, opt_serial);
    if cpu.is_none() { return; }
    let cpu = cpu.unwrap();

    let sdl_context = sdl2::init().unwrap();
    let sdl_video = sdl_context.video().unwrap();
    let window = match sdl2::video::WindowBuilder::new(&sdl_video,
                                                "RBoy - A gameboy in Rust",
                                                160*SCALE,
                                                144*SCALE).build() {
        Ok(window) => window,
        Err(err) => panic!("failed to open window: {}", err),
    };
    let mut renderer = match sdl2::render::RendererBuilder::new(window).accelerated().build() {
        Ok(screen) => screen,
        Err(err) => panic!("failed to open screen: {}", err),
    };

    let (sdl_tx, cpu_rx) = std::sync::mpsc::channel();
    let (cpu_tx, sdl_rx) = std::sync::mpsc::channel();
    let rawscreen = ::std::iter::repeat(0u8).take(160*144*3).collect();
    let arc = Arc::new(RwLock::new(rawscreen));
    let arc2 = arc.clone();

    let cpuloop_thread = std::thread::spawn(move|| cpuloop(&cpu_tx, &cpu_rx, arc2, cpu));

    let mut event_queue = sdl_context.event_pump().unwrap();
    'main : loop {
        match sdl_rx.try_recv() {
            Err(Disconnected) => { break 'main },
            Ok(_) => recalculate_screen(&mut renderer, &arc),
            Err(Empty) => {},
        }
        for event in event_queue.wait_timeout_iter(2) {
            match event {
                sdl2::event::Event::Quit { .. } => break 'main,
                sdl2::event::Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::Escape), .. }
                    => break 'main,
                sdl2::event::Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::LShift), .. }
                    => { let _ = sdl_tx.send(GBEvent::SpeedUp); },
                sdl2::event::Event::KeyUp { keycode: Some(sdl2::keyboard::Keycode::LShift), .. }
                    => { let _ = sdl_tx.send(GBEvent::SlowDown); },
                sdl2::event::Event::KeyDown { keycode: Some(sdlkey), .. } => {
                    match sdl_to_keypad(sdlkey) {
                        Some(key) =>  { let _ = sdl_tx.send(GBEvent::KeyDown(key)); },
                        None => {},
                    }
                },
                sdl2::event::Event::KeyUp { keycode: Some(sdlkey), .. } => {
                    match sdl_to_keypad(sdlkey) {
                        Some(key) => { let _ = sdl_tx.send(GBEvent::KeyUp(key)); },
                        None => {},
                    }
                },
                _ => {}
            }
        }
    }

    drop(sdl_tx); // Disconnect such that the cpuloop will exit
    let _ = cpuloop_thread.join();
}

fn sdl_to_keypad(key: sdl2::keyboard::Keycode) -> Option<rboy::KeypadKey> {
    match key {
        sdl2::keyboard::Keycode::Z => Some(rboy::KeypadKey::A),
        sdl2::keyboard::Keycode::X => Some(rboy::KeypadKey::B),
        sdl2::keyboard::Keycode::Up => Some(rboy::KeypadKey::Up),
        sdl2::keyboard::Keycode::Down => Some(rboy::KeypadKey::Down),
        sdl2::keyboard::Keycode::Left => Some(rboy::KeypadKey::Left),
        sdl2::keyboard::Keycode::Right => Some(rboy::KeypadKey::Right),
        sdl2::keyboard::Keycode::Space => Some(rboy::KeypadKey::Select),
        sdl2::keyboard::Keycode::Return => Some(rboy::KeypadKey::Start),
        _ => None,
    }
}

fn recalculate_screen(screen: &mut sdl2::render::Renderer, arc: &Arc<RwLock<Vec<u8>>>) {
    screen.set_draw_color(sdl2::pixels::Color::RGB(0xFF, 0xFF, 0xFF));
    screen.clear();

    let data =  arc.read().unwrap().clone();
    for y in 0..144 {
        for x in 0..160 {
            screen.set_draw_color(sdl2::pixels::Color::RGB(data[y*160*3 + x*3 + 0],
                                                            data[y*160*3 + x*3 + 1],
                                                            data[y*160*3 + x*3 + 2]));
            screen.fill_rect(sdl2::rect::Rect::new(x as i32 * SCALE as i32, y as i32 * SCALE as i32, SCALE, SCALE).unwrap().unwrap());
        }
    }
    screen.present();
}

enum GBEvent {
    KeyUp(rboy::KeypadKey),
    KeyDown(rboy::KeypadKey),
    SpeedUp,
    SlowDown,
}

fn warn(message: &'static str) {
    use std::io::Write;
    let _ = write!(&mut std::io::stderr(), "{}\n", message);
}

fn construct_cpu(filename: &str, classic_mode: bool, output_serial: bool) -> Option<Device> {
    let opt_c = match classic_mode {
        true => Device::new(filename),
        false => Device::new_cgb(filename),
    };
    let mut c = match opt_c
    {
        Ok(cpu) => { cpu },
        Err(message) => { warn(message); set_exit_status(EXITCODE_CPULOADFAILS); return None; },
    };
    c.set_stdout(output_serial);
    Some(c)
}

fn cpuloop(cpu_tx: &Sender<()>, cpu_rx: &Receiver<GBEvent>, arc: Arc<RwLock<Vec<u8>>>, cpu: Device) {
    let mut c = cpu;
    let periodic = timer_periodic(8);
    let mut limit_speed = true;

    let waitticks = (4194304f64 / 1000.0 * 8.0) as u32;

    let mut ticks = 0;
    'cpuloop: loop {
        while ticks < waitticks {
            ticks += c.do_cycle();
            if c.check_and_reset_gpu_updated() {
                let mut data = arc.write().unwrap();
                let gpu_data = c.get_gpu_data();
                for i in 0..data.len() { data[i] = gpu_data[i]; }
                if cpu_tx.send(()).is_err() { break 'cpuloop };
            }
        }
        ticks -= waitticks;
        if limit_speed { let _ = periodic.recv(); }

        match cpu_rx.try_recv() {
            Ok(event) => match event {
                GBEvent::KeyUp(key) => c.keyup(key),
                GBEvent::KeyDown(key) => c.keydown(key),
                GBEvent::SpeedUp => limit_speed = false,
                GBEvent::SlowDown => limit_speed = true,
            },
            Err(Empty) => {},
            Err(Disconnected) => { break },
        };
    }
}

fn timer_periodic(ms: u32) -> Receiver<()> {
    let (tx, rx) = std::sync::mpsc::channel();
    std::thread::spawn(move || {
        loop {
            std::thread::sleep_ms(ms);
            if tx.send(()).is_err() {
                break;
            }
        }
    });
    rx
}
<commit_msg>Simplify setting the programs exit code<commit_after>#![crate_name = "rboy"]

extern crate clap;
extern crate sdl2;
extern crate rboy;

use rboy::device::Device;
use std::sync::{Arc,RwLock};
use std::sync::mpsc::{Sender,Receiver};
use std::sync::mpsc::TryRecvError::{Disconnected,Empty};

const SCALE : u32 = 2;
const EXITCODE_SUCCESS : i32 = 0;
const EXITCODE_CPULOADFAILS : i32 = 2;

fn main() {
    let exit_status = real_main();
    if exit_status != EXITCODE_SUCCESS {
        std::process::exit(exit_status);
    }
}

fn real_main() -> i32 {
    let matches = clap::App::new("rboy")
        .version("0.1")
        .author("Mathijs van de Nes")
        .about("A Gameboy Colour emulator written in Rust")
        .arg(clap::Arg::with_name("filename")
             .help("Sets the ROM file to load")
             .required(true))
        .arg(clap::Arg::with_name("serial")
             .help("Prints the data from the serial port to stdout")
             .short("s")
             .long("serial"))
        .arg(clap::Arg::with_name("classic")
             .help("Forces the emulator to run in classic Gameboy mode")
             .short("c")
             .long("classic"))
        .get_matches();

    let opt_serial = matches.is_present("serial");
    let opt_classic = matches.is_present("classic");
    let filename = matches.value_of("filename").unwrap();

    let cpu = construct_cpu(filename, opt_classic, opt_serial);
    if cpu.is_none() { return EXITCODE_CPULOADFAILS; }
    let cpu = cpu.unwrap();

    let sdl_context = sdl2::init().unwrap();
    let sdl_video = sdl_context.video().unwrap();
    let window = match sdl2::video::WindowBuilder::new(&sdl_video,
                                                "RBoy - A gameboy in Rust",
                                                160*SCALE,
                                                144*SCALE).build() {
        Ok(window) => window,
        Err(err) => panic!("failed to open window: {}", err),
    };
    let mut renderer = match sdl2::render::RendererBuilder::new(window).accelerated().build() {
        Ok(screen) => screen,
        Err(err) => panic!("failed to open screen: {}", err),
    };

    let (sdl_tx, cpu_rx) = std::sync::mpsc::channel();
    let (cpu_tx, sdl_rx) = std::sync::mpsc::channel();
    let rawscreen = ::std::iter::repeat(0u8).take(160*144*3).collect();
    let arc = Arc::new(RwLock::new(rawscreen));
    let arc2 = arc.clone();

    let cpuloop_thread = std::thread::spawn(move|| cpuloop(&cpu_tx, &cpu_rx, arc2, cpu));

    let mut event_queue = sdl_context.event_pump().unwrap();
    'main : loop {
        match sdl_rx.try_recv() {
            Err(Disconnected) => { break 'main },
            Ok(_) => recalculate_screen(&mut renderer, &arc),
            Err(Empty) => {},
        }
        for event in event_queue.wait_timeout_iter(2) {
            match event {
                sdl2::event::Event::Quit { .. } => break 'main,
                sdl2::event::Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::Escape), .. }
                    => break 'main,
                sdl2::event::Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::LShift), .. }
                    => { let _ = sdl_tx.send(GBEvent::SpeedUp); },
                sdl2::event::Event::KeyUp { keycode: Some(sdl2::keyboard::Keycode::LShift), .. }
                    => { let _ = sdl_tx.send(GBEvent::SlowDown); },
                sdl2::event::Event::KeyDown { keycode: Some(sdlkey), .. } => {
                    match sdl_to_keypad(sdlkey) {
                        Some(key) =>  { let _ = sdl_tx.send(GBEvent::KeyDown(key)); },
                        None => {},
                    }
                },
                sdl2::event::Event::KeyUp { keycode: Some(sdlkey), .. } => {
                    match sdl_to_keypad(sdlkey) {
                        Some(key) => { let _ = sdl_tx.send(GBEvent::KeyUp(key)); },
                        None => {},
                    }
                },
                _ => {}
            }
        }
    }

    drop(sdl_tx); // Disconnect such that the cpuloop will exit
    let _ = cpuloop_thread.join();

    EXITCODE_SUCCESS
}

fn sdl_to_keypad(key: sdl2::keyboard::Keycode) -> Option<rboy::KeypadKey> {
    match key {
        sdl2::keyboard::Keycode::Z => Some(rboy::KeypadKey::A),
        sdl2::keyboard::Keycode::X => Some(rboy::KeypadKey::B),
        sdl2::keyboard::Keycode::Up => Some(rboy::KeypadKey::Up),
        sdl2::keyboard::Keycode::Down => Some(rboy::KeypadKey::Down),
        sdl2::keyboard::Keycode::Left => Some(rboy::KeypadKey::Left),
        sdl2::keyboard::Keycode::Right => Some(rboy::KeypadKey::Right),
        sdl2::keyboard::Keycode::Space => Some(rboy::KeypadKey::Select),
        sdl2::keyboard::Keycode::Return => Some(rboy::KeypadKey::Start),
        _ => None,
    }
}

fn recalculate_screen(screen: &mut sdl2::render::Renderer, arc: &Arc<RwLock<Vec<u8>>>) {
    screen.set_draw_color(sdl2::pixels::Color::RGB(0xFF, 0xFF, 0xFF));
    screen.clear();

    let data =  arc.read().unwrap().clone();
    for y in 0..144 {
        for x in 0..160 {
            screen.set_draw_color(sdl2::pixels::Color::RGB(data[y*160*3 + x*3 + 0],
                                                            data[y*160*3 + x*3 + 1],
                                                            data[y*160*3 + x*3 + 2]));
            screen.fill_rect(sdl2::rect::Rect::new(x as i32 * SCALE as i32, y as i32 * SCALE as i32, SCALE, SCALE).unwrap().unwrap());
        }
    }
    screen.present();
}

enum GBEvent {
    KeyUp(rboy::KeypadKey),
    KeyDown(rboy::KeypadKey),
    SpeedUp,
    SlowDown,
}

fn warn(message: &'static str) {
    use std::io::Write;
    let _ = write!(&mut std::io::stderr(), "{}\n", message);
}

fn construct_cpu(filename: &str, classic_mode: bool, output_serial: bool) -> Option<Device> {
    let opt_c = match classic_mode {
        true => Device::new(filename),
        false => Device::new_cgb(filename),
    };
    let mut c = match opt_c
    {
        Ok(cpu) => { cpu },
        Err(message) => { warn(message); return None; },
    };
    c.set_stdout(output_serial);
    Some(c)
}

fn cpuloop(cpu_tx: &Sender<()>, cpu_rx: &Receiver<GBEvent>, arc: Arc<RwLock<Vec<u8>>>, cpu: Device) {
    let mut c = cpu;
    let periodic = timer_periodic(8);
    let mut limit_speed = true;

    let waitticks = (4194304f64 / 1000.0 * 8.0) as u32;

    let mut ticks = 0;
    'cpuloop: loop {
        while ticks < waitticks {
            ticks += c.do_cycle();
            if c.check_and_reset_gpu_updated() {
                let mut data = arc.write().unwrap();
                let gpu_data = c.get_gpu_data();
                for i in 0..data.len() { data[i] = gpu_data[i]; }
                if cpu_tx.send(()).is_err() { break 'cpuloop };
            }
        }
        ticks -= waitticks;
        if limit_speed { let _ = periodic.recv(); }

        match cpu_rx.try_recv() {
            Ok(event) => match event {
                GBEvent::KeyUp(key) => c.keyup(key),
                GBEvent::KeyDown(key) => c.keydown(key),
                GBEvent::SpeedUp => limit_speed = false,
                GBEvent::SlowDown => limit_speed = true,
            },
            Err(Empty) => {},
            Err(Disconnected) => { break },
        };
    }
}

fn timer_periodic(ms: u32) -> Receiver<()> {
    let (tx, rx) = std::sync::mpsc::channel();
    std::thread::spawn(move || {
        loop {
            std::thread::sleep_ms(ms);
            if tx.send(()).is_err() {
                break;
            }
        }
    });
    rx
}
<|endoftext|>


<commit_before>#![deny(bare_trait_objects)]

extern crate docopt;
extern crate futures;
extern crate hyper;
extern crate hyper_native_tls;
extern crate iron;
extern crate itertools;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate lru_time_cache;
extern crate notify_rust;
extern crate regex;
extern crate rlua;
extern crate router;
extern crate rusoto_core;
extern crate rusoto_sqs;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;
extern crate serde_yaml;
extern crate ssh2;
extern crate stderrlog;
extern crate tokio_core;

use futures::{Future, Sink, Stream};
use std::time::Duration;
use std::rc::Rc;

#[macro_use]
mod utils;
mod args;
mod bot;
mod gerrit;
mod spark;
mod sqs;

use spark::SparkClient;

fn spark_client_from_config(spark_config: args::SparkConfig) -> Rc<dyn SparkClient> {
    match spark_config.output_mode {
        args::OutputConfig::Spark => {
            Rc::new(
            spark::WebClient::new(
                spark_config.api_uri,
                spark_config.bot_token,
                spark_config.webhook_url,
            ).unwrap_or_else(|err| {
                error!("Could not create spark client: {}", err);
                std::process::exit(1);
            }))
        },
        args::OutputConfig::Console => {
            warn!("Using console as Spark client due to empty bot_token.");
            Rc::new(spark::ConsoleClient::new())
        },
        args::OutputConfig::Notifications => {
            warn!("Using dbus notification as Spark client");
            Rc::new(spark::NotificationClient::new())
        }
    }
}

fn main() {
    let args = args::parse_args();
    stderrlog::new()
        .module(module_path!())
        .quiet(args.flag_quiet)
        .timestamp(stderrlog::Timestamp::Second)
        .verbosity(if args.flag_verbose { 5 } else { 2 })
        .init()
        .unwrap();
    let config = args::parse_config(args.flag_config);

    // load or create a new bot
    let mut bot = match bot::Bot::load("state.json") {
        Ok(bot) => {
            info!(
                "Loaded bot from 'state.json' with {} user(s).",
                bot.num_users()
            );
            bot
        }
        Err(err) => {
            warn!("Could not load bot from 'state.json': {:?}", err);
            bot::Bot::new()
        }
    };
    if config.bot.msg_expiration != 0 && config.bot.msg_capacity != 0 {
        debug!(
            "Approval LRU cache: capacity - {}, expiration - {} sec",
            config.bot.msg_capacity, config.bot.msg_expiration
        );
        bot.init_msg_cache(
            config.bot.msg_capacity,
            Duration::from_secs(config.bot.msg_expiration),
        );
    };

    // event loop
    let mut core = tokio_core::reactor::Core::new().unwrap();

    // create spark client and event stream listener
    let spark_client = spark_client_from_config(config.spark.clone());
    let spark_stream = match config.spark.mode.clone() {
        args::ModeConfig::Direct { endpoint } => {
            spark::webhook_event_stream(spark_client, &endpoint, core.remote())
        }
        args::ModeConfig::Sqs { uri, region } => spark::sqs_event_stream(spark_client, uri, region),
    };

    let spark_stream = spark_stream.unwrap_or_else(|err| {
        error!("Could not start listening to spark: {}", err);
        std::process::exit(1);
    });

    // create gerrit event stream listener
    let gerrit_config = config.gerrit.clone();
    info!("(Re)connecting to Gerrit over ssh: {}", gerrit_config.host);

    let (gerrit_change_id_sink, gerrit_change_response_stream) = gerrit::change_sink(
        gerrit_config.host.clone(),
        gerrit_config.username.clone(),
        gerrit_config.priv_key_path.clone(),
    ).unwrap_or_else(|err| {
        error!(
            "Could not connect to Gerrit via SSH for sending commands: {}",
            err
        );
        std::process::exit(1);
    });

    let gerrit_stream = gerrit::event_stream(
        gerrit_config.host,
        gerrit_config.username,
        gerrit_config.priv_key_path,
    );

    // join spark and gerrit action streams into one and fold over actions with accumulator `bot`
    let spark_client = spark_client_from_config(config.spark.clone());
    let handle = core.handle();
    let actions = spark_stream
        .select(gerrit_stream)
        .select(gerrit_change_response_stream)
        .filter(|action| match *action {
            bot::Action::NoOp => false,
            _ => true,
        })
        .filter_map(move |action| {
            debug!("Handle action: {:#?}", action);

            // fold over actions
            let old_bot = std::mem::replace(&mut bot, bot::Bot::new());
            let (new_bot, task) = bot::update(action, old_bot);
            std::mem::replace(&mut bot, new_bot);

            // Handle save task and return response.
            // Note: We have to do it here, since the value of `bot` is only
            // available in this function.
            if let Some(task) = task {
                debug!("New task {:#?}", task);
                let response = match task {
                    bot::Task::Reply(response) => Some(response),
                    bot::Task::ReplyAndSave(response) => {
                        let bot_clone = bot.clone();
                        handle.spawn_fn(move || {
                            if let Err(err) = bot_clone.save("state.json") {
                                error!("Could not save state: {:?}", err);
                            }
                            Ok(())
                        });
                        Some(response)
                    }
                    bot::Task::FetchComments(user, change, message) => {
                        handle.spawn(
                            gerrit_change_id_sink
                                .clone()
                                .send((user, change, message))
                                .map_err(|e| {
                                    error!("Could not fetch comments: {}", e);
                                })
                                .then(|_| Ok(())),
                        );
                        None
                    }
                };
                return response;
            }
            None
        })
        .or_else(|err| {
            error!("Exit due to error: {:?}", err);
            Err(())
        })
        .for_each(|response| {
            debug!("Replying with: {}", response.message);
            spark_client.reply(&response.person_id, &response.message);
            Ok(())
        });

    let _ = core.run(actions);
}
<commit_msg>get rid of non-macro extern crate<commit_after>#![deny(bare_trait_objects)]

#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;

use futures::{Future, Sink, Stream};
use std::time::Duration;
use std::rc::Rc;

#[macro_use]
mod utils;
mod args;
mod bot;
mod gerrit;
mod spark;
mod sqs;

use spark::SparkClient;

fn spark_client_from_config(spark_config: args::SparkConfig) -> Rc<dyn SparkClient> {
    match spark_config.output_mode {
        args::OutputConfig::Spark => {
            Rc::new(
            spark::WebClient::new(
                spark_config.api_uri,
                spark_config.bot_token,
                spark_config.webhook_url,
            ).unwrap_or_else(|err| {
                error!("Could not create spark client: {}", err);
                std::process::exit(1);
            }))
        },
        args::OutputConfig::Console => {
            warn!("Using console as Spark client due to empty bot_token.");
            Rc::new(spark::ConsoleClient::new())
        },
        args::OutputConfig::Notifications => {
            warn!("Using dbus notification as Spark client");
            Rc::new(spark::NotificationClient::new())
        }
    }
}

fn main() {
    let args = args::parse_args();
    stderrlog::new()
        .module(module_path!())
        .quiet(args.flag_quiet)
        .timestamp(stderrlog::Timestamp::Second)
        .verbosity(if args.flag_verbose { 5 } else { 2 })
        .init()
        .unwrap();
    let config = args::parse_config(args.flag_config);

    // load or create a new bot
    let mut bot = match bot::Bot::load("state.json") {
        Ok(bot) => {
            info!(
                "Loaded bot from 'state.json' with {} user(s).",
                bot.num_users()
            );
            bot
        }
        Err(err) => {
            warn!("Could not load bot from 'state.json': {:?}", err);
            bot::Bot::new()
        }
    };
    if config.bot.msg_expiration != 0 && config.bot.msg_capacity != 0 {
        debug!(
            "Approval LRU cache: capacity - {}, expiration - {} sec",
            config.bot.msg_capacity, config.bot.msg_expiration
        );
        bot.init_msg_cache(
            config.bot.msg_capacity,
            Duration::from_secs(config.bot.msg_expiration),
        );
    };

    // event loop
    let mut core = tokio_core::reactor::Core::new().unwrap();

    // create spark client and event stream listener
    let spark_client = spark_client_from_config(config.spark.clone());
    let spark_stream = match config.spark.mode.clone() {
        args::ModeConfig::Direct { endpoint } => {
            spark::webhook_event_stream(spark_client, &endpoint, core.remote())
        }
        args::ModeConfig::Sqs { uri, region } => spark::sqs_event_stream(spark_client, uri, region),
    };

    let spark_stream = spark_stream.unwrap_or_else(|err| {
        error!("Could not start listening to spark: {}", err);
        std::process::exit(1);
    });

    // create gerrit event stream listener
    let gerrit_config = config.gerrit.clone();
    info!("(Re)connecting to Gerrit over ssh: {}", gerrit_config.host);

    let (gerrit_change_id_sink, gerrit_change_response_stream) = gerrit::change_sink(
        gerrit_config.host.clone(),
        gerrit_config.username.clone(),
        gerrit_config.priv_key_path.clone(),
    ).unwrap_or_else(|err| {
        error!(
            "Could not connect to Gerrit via SSH for sending commands: {}",
            err
        );
        std::process::exit(1);
    });

    let gerrit_stream = gerrit::event_stream(
        gerrit_config.host,
        gerrit_config.username,
        gerrit_config.priv_key_path,
    );

    // join spark and gerrit action streams into one and fold over actions with accumulator `bot`
    let spark_client = spark_client_from_config(config.spark.clone());
    let handle = core.handle();
    let actions = spark_stream
        .select(gerrit_stream)
        .select(gerrit_change_response_stream)
        .filter(|action| match *action {
            bot::Action::NoOp => false,
            _ => true,
        })
        .filter_map(move |action| {
            debug!("Handle action: {:#?}", action);

            // fold over actions
            let old_bot = std::mem::replace(&mut bot, bot::Bot::new());
            let (new_bot, task) = bot::update(action, old_bot);
            std::mem::replace(&mut bot, new_bot);

            // Handle save task and return response.
            // Note: We have to do it here, since the value of `bot` is only
            // available in this function.
            if let Some(task) = task {
                debug!("New task {:#?}", task);
                let response = match task {
                    bot::Task::Reply(response) => Some(response),
                    bot::Task::ReplyAndSave(response) => {
                        let bot_clone = bot.clone();
                        handle.spawn_fn(move || {
                            if let Err(err) = bot_clone.save("state.json") {
                                error!("Could not save state: {:?}", err);
                            }
                            Ok(())
                        });
                        Some(response)
                    }
                    bot::Task::FetchComments(user, change, message) => {
                        handle.spawn(
                            gerrit_change_id_sink
                                .clone()
                                .send((user, change, message))
                                .map_err(|e| {
                                    error!("Could not fetch comments: {}", e);
                                })
                                .then(|_| Ok(())),
                        );
                        None
                    }
                };
                return response;
            }
            None
        })
        .or_else(|err| {
            error!("Exit due to error: {:?}", err);
            Err(())
        })
        .for_each(|response| {
            debug!("Replying with: {}", response.message);
            spark_client.reply(&response.person_id, &response.message);
            Ok(())
        });

    let _ = core.run(actions);
}
<|endoftext|>


<commit_before>extern crate base64;
extern crate hyper;
extern crate hyper_native_tls;
extern crate pem;
#[macro_use]
extern crate prettytable;
extern crate serde_json;
extern crate url;

extern crate ct_submitter;

use std::{env, process};
use std::fs::File;
use std::io::Read;
use std::time::Duration;

use ct_submitter::{fetch_trusted_ct_logs, submit_cert_to_logs, AddChainRequest};

fn pems_to_chain(data: &str) -> Vec<Vec<u8>> {
    return pem::parse_many(data)
               .into_iter()
               .filter(|p| p.tag == "CERTIFICATE")
               .map(|p| p.contents)
               .collect::<Vec<_>>();
}

fn main() {
    let path = match env::args().skip(1).next() {
        Some(p) => p,
        None => {
            println!("Usage: {} <path/to/chain.pem>", env::args().next().unwrap());
            process::exit(1);
        }
    };

    let mut contents = String::new();
    File::open(path)
        .unwrap()
        .read_to_string(&mut contents)
        .unwrap();

    let mut chain = pems_to_chain(&contents);

    let mut http_client = hyper::Client::with_connector(
        hyper::net::HttpsConnector::new(hyper_native_tls::NativeTlsClient::new().unwrap())
    );
    http_client.set_read_timeout(Some(Duration::from_secs(5)));
    let logs = fetch_trusted_ct_logs(&http_client);

    if chain.len() == 1 {
        // TODO: There's got to be some way to do this ourselves, instead of using crt.sh as a
        // glorified AIA chaser.
        println!("Only one certificate in chain, using crt.sh to build a full chain");
        let body = url::form_urlencoded::Serializer::new(String::new())
            .append_pair("b64cert", &base64::encode(&chain[0]))
            .finish();
        let body_bytes = body.as_bytes();
        let mut response = http_client
            .post("https://crt.sh/gen-add-chain")
            .header(hyper::header::ContentType::form_url_encoded())
            .body(hyper::client::Body::BufBody(body_bytes, body_bytes.len()))
            .send()
            .unwrap();

        let add_chain_request: AddChainRequest = serde_json::from_reader(response).unwrap();
        chain = add_chain_request
            .chain
            .iter()
            .map(|c| base64::decode(c).unwrap())
            .collect();
    }

    let scts = submit_cert_to_logs(&http_client, &logs, chain);

    let mut table = prettytable::Table::new();
    table.add_row(row!["Log", "SCT"]);
    for (log, sct) in scts {
        table.add_row(row![log.description, base64::encode(&sct.to_raw_bytes())]);
    }
    table.printstd();
}
<commit_msg>remove mut<commit_after>extern crate base64;
extern crate hyper;
extern crate hyper_native_tls;
extern crate pem;
#[macro_use]
extern crate prettytable;
extern crate serde_json;
extern crate url;

extern crate ct_submitter;

use std::{env, process};
use std::fs::File;
use std::io::Read;
use std::time::Duration;

use ct_submitter::{fetch_trusted_ct_logs, submit_cert_to_logs, AddChainRequest};

fn pems_to_chain(data: &str) -> Vec<Vec<u8>> {
    return pem::parse_many(data)
               .into_iter()
               .filter(|p| p.tag == "CERTIFICATE")
               .map(|p| p.contents)
               .collect::<Vec<_>>();
}

fn main() {
    let path = match env::args().skip(1).next() {
        Some(p) => p,
        None => {
            println!("Usage: {} <path/to/chain.pem>", env::args().next().unwrap());
            process::exit(1);
        }
    };

    let mut contents = String::new();
    File::open(path)
        .unwrap()
        .read_to_string(&mut contents)
        .unwrap();

    let mut chain = pems_to_chain(&contents);

    let mut http_client = hyper::Client::with_connector(
        hyper::net::HttpsConnector::new(hyper_native_tls::NativeTlsClient::new().unwrap())
    );
    http_client.set_read_timeout(Some(Duration::from_secs(5)));
    let logs = fetch_trusted_ct_logs(&http_client);

    if chain.len() == 1 {
        // TODO: There's got to be some way to do this ourselves, instead of using crt.sh as a
        // glorified AIA chaser.
        println!("Only one certificate in chain, using crt.sh to build a full chain");
        let body = url::form_urlencoded::Serializer::new(String::new())
            .append_pair("b64cert", &base64::encode(&chain[0]))
            .finish();
        let body_bytes = body.as_bytes();
        let response = http_client
            .post("https://crt.sh/gen-add-chain")
            .header(hyper::header::ContentType::form_url_encoded())
            .body(hyper::client::Body::BufBody(body_bytes, body_bytes.len()))
            .send()
            .unwrap();

        let add_chain_request: AddChainRequest = serde_json::from_reader(response).unwrap();
        chain = add_chain_request
            .chain
            .iter()
            .map(|c| base64::decode(c).unwrap())
            .collect();
    }

    let scts = submit_cert_to_logs(&http_client, &logs, chain);

    let mut table = prettytable::Table::new();
    table.add_row(row!["Log", "SCT"]);
    for (log, sct) in scts {
        table.add_row(row![log.description, base64::encode(&sct.to_raw_bytes())]);
    }
    table.printstd();
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>open file<commit_after>use std::env;
use std::fs;
use std::io;
use std::io::Read;

fn main() {
    println!("Hello, world!");

    if env::args().count() > 2 {
        println!("Usage: crb [<file>]");
        std::process::exit(1);
    }

    match env::args().nth(1) {
        Some(path) => {
            println!("opening file: {}", path);
            open_file(path);
        }
        None => {
            println!("no file specified. making my job easy ;)")
        }
    }
}

fn open_file(path: String) {
    match read_file(path) {
        Ok(contents) => println!("{}", contents),
        Err(e) => println!("Could not open file: {}", e),
    }
}

fn read_file(path: String) -> Result<String, io::Error> {
    let mut f = try!(fs::File::open(path));
    let mut contents = String::new();
    try!(f.read_to_string(&mut contents));
    Ok(contents)
}

// fn prompt(p: String) -> Result<String, std::io::Error> {
//     print!("{}", p);
//     try!(io::stdout().flush());
//     let mut s = String::new();
//     try!(io::stdin().read_line(&mut s));
//     Ok(s)
// }
<|endoftext|>


<commit_before>use std::env;
use std::fs::File;
use std::io::Read;
extern crate syn;
use syn::*;

mod rust_lib;

fn has_attribute(target: MetaItem, attrs: &Vec<Attribute>) -> bool {
    return attrs
               .iter()
               .any(|ref attr| attr.style == AttrStyle::Outer && attr.value == target);
}

fn has_no_mangle(attrs: &Vec<Attribute>) -> bool {
    has_attribute(MetaItem::Word(Ident::new("no_mangle")), attrs)
}

fn wr_func_body(attrs: &Vec<Attribute>) -> String {
    if has_attribute(MetaItem::Word(Ident::new("destructor_safe")), attrs) {
        String::from("WR_DESTRUCTOR_SAFE_FUNC")
    } else {
        String::from("WR_FUNC")
    }
}

fn is_repr_c(attrs: &Vec<Attribute>) -> bool {
    let repr_args = vec![NestedMetaItem::MetaItem(MetaItem::Word(Ident::new("C")))];
    has_attribute(MetaItem::List(Ident::new("repr"), repr_args), attrs)
}

fn is_c_abi(abi: &Option<Abi>) -> bool {
    abi == &Some(Abi::Named(String::from("C")))
}

fn map_path(p: &Path) -> String {
    let l = p.segments[0].ident.to_string();
    match l.as_ref() {
        "usize" => "size_t".to_string(),
        "u8" => "uint8_t".to_string(),
        "u32" => "uint32_t".to_string(),
        "f32" => "float".to_string(),
        "c_void" => "void".to_string(),
        _ => l,
    }
}

fn map_mut_ty(mut_ty: &MutTy) -> String {
    map_ty(&mut_ty.ty)
}

fn map_ty(ty: &Ty) -> String {
    match ty {
        &Ty::Path(_, ref p) => map_path(p),
        &Ty::Ptr(ref p) => format!("{}*", map_ty(&p.ty)),
        &Ty::Rptr(_, ref mut_ty) => format!("{}*", map_mut_ty(mut_ty)),
        _ => format!("unknown {:?}", ty),
    }

}

fn map_return_type(ret: &FunctionRetTy) -> String {
    match ret {
        &FunctionRetTy::Default => "void".to_string(),
        &FunctionRetTy::Ty(ref ty) => map_ty(ty),
    }
}

fn map_pat(pat: &Pat) -> String {
    match pat {
        &Pat::Ident(_, ref ident, _) => ident.to_string(),
        _ => format!("unknown {:?}", pat),
    }

}

fn map_arg(f: &FnArg) -> String {
    match f {
        &FnArg::Captured(ref pat, ref ty) => format!("{} {}", map_ty(ty), map_pat(pat)),
        _ => "unknown".to_string(),
    }
}

fn map_field(f: &Field) -> String {
    let mut ret = String::from("  ");
    ret.push_str(&map_ty(&f.ty));
    ret.push(' ');
    ret.push_str(&f.ident.as_ref().expect("Struct fields must have idents").to_string());
    ret.push_str(";\n");
    ret
}

fn main() {
    let p = env::args().nth(1).unwrap();
    let mut s = String::new();
    let mut f = File::open(p).unwrap();
    f.read_to_string(&mut s).unwrap();
    let krate = syn::parse_crate(&s).unwrap();
    for item in krate.items {
        match item.node {
            ItemKind::Fn(decl, _unsafe, _const, abi, _generic, _block) => {
                if has_no_mangle(&item.attrs) && is_c_abi(&abi) {
                    println!("WR_INLINE {}\n{}({})\n{};\n",
                             map_return_type(&decl.output),
                             item.ident,
                             decl.inputs
                                 .iter()
                                 .map(map_arg)
                                 .collect::<Vec<_>>()
                                 .join(", "),
                             wr_func_body(&item.attrs));
                }
            }
            ItemKind::Struct(variant, _generics) => {
                if is_repr_c(&item.attrs) {
                    if let VariantData::Struct(fields) = variant {
                        println!("struct {} {{\n{}}};\n",
                                 item.ident,
                                 fields
                                     .iter()
                                     .map(map_field)
                                     .collect::<String>());
                    }
                }
            }
            _ => {}
        }
    }

}
<commit_msg>Use rust_lib for parsing<commit_after>use std::env;

extern crate syn;
use syn::*;

mod rust_lib;

fn has_attribute(target: MetaItem, attrs: &Vec<Attribute>) -> bool {
    return attrs
               .iter()
               .any(|ref attr| attr.style == AttrStyle::Outer && attr.value == target);
}

fn has_no_mangle(attrs: &Vec<Attribute>) -> bool {
    has_attribute(MetaItem::Word(Ident::new("no_mangle")), attrs)
}

fn wr_func_body(attrs: &Vec<Attribute>) -> String {
    if has_attribute(MetaItem::Word(Ident::new("destructor_safe")), attrs) {
        String::from("WR_DESTRUCTOR_SAFE_FUNC")
    } else {
        String::from("WR_FUNC")
    }
}

fn is_repr_c(attrs: &Vec<Attribute>) -> bool {
    let repr_args = vec![NestedMetaItem::MetaItem(MetaItem::Word(Ident::new("C")))];
    has_attribute(MetaItem::List(Ident::new("repr"), repr_args), attrs)
}

fn is_c_abi(abi: &Option<Abi>) -> bool {
    abi == &Some(Abi::Named(String::from("C")))
}

fn map_path(p: &Path) -> String {
    let l = p.segments[0].ident.to_string();
    match l.as_ref() {
        "usize" => "size_t".to_string(),
        "u8" => "uint8_t".to_string(),
        "u32" => "uint32_t".to_string(),
        "f32" => "float".to_string(),
        "c_void" => "void".to_string(),
        _ => l,
    }
}

fn map_mut_ty(mut_ty: &MutTy) -> String {
    map_ty(&mut_ty.ty)
}

fn map_ty(ty: &Ty) -> String {
    match ty {
        &Ty::Path(_, ref p) => map_path(p),
        &Ty::Ptr(ref p) => format!("{}*", map_ty(&p.ty)),
        &Ty::Rptr(_, ref mut_ty) => format!("{}*", map_mut_ty(mut_ty)),
        _ => format!("unknown {:?}", ty),
    }

}

fn map_return_type(ret: &FunctionRetTy) -> String {
    match ret {
        &FunctionRetTy::Default => "void".to_string(),
        &FunctionRetTy::Ty(ref ty) => map_ty(ty),
    }
}

fn map_pat(pat: &Pat) -> String {
    match pat {
        &Pat::Ident(_, ref ident, _) => ident.to_string(),
        _ => format!("unknown {:?}", pat),
    }

}

fn map_arg(f: &FnArg) -> String {
    match f {
        &FnArg::Captured(ref pat, ref ty) => format!("{} {}", map_ty(ty), map_pat(pat)),
        _ => "unknown".to_string(),
    }
}

fn map_field(f: &Field) -> String {
    let mut ret = String::from("  ");
    ret.push_str(&map_ty(&f.ty));
    ret.push(' ');
    ret.push_str(&f.ident.as_ref().expect("Struct fields must have idents").to_string());
    ret.push_str(";\n");
    ret
}

fn main() {
    let p = env::args().nth(1).unwrap();

    rust_lib::parse(p, &|_, items| {
        for item in items {
            match item.node {
                ItemKind::Fn(ref decl,
                             ref _unsafe,
                             ref _const,
                             ref abi,
                             ref _generic,
                             ref _block) => {
                    if has_no_mangle(&item.attrs) && is_c_abi(&abi) {
                        println!("WR_INLINE {}\n{}({})\n{};\n",
                                 map_return_type(&decl.output),
                                 item.ident,
                                 decl.inputs
                                     .iter()
                                     .map(map_arg)
                                     .collect::<Vec<_>>()
                                     .join(", "),
                                 wr_func_body(&item.attrs));
                    }
                }
                ItemKind::Struct(ref variant,
                                 ref _generics) => {
                    if is_repr_c(&item.attrs) {
                        if let &VariantData::Struct(ref fields) = variant {
                            println!("struct {} {{\n{}}};\n",
                                     item.ident,
                                     fields
                                         .iter()
                                         .map(map_field)
                                         .collect::<String>());
                        }
                    }
                }
                _ => {}
            }
        }
    });
}
<|endoftext|>


<commit_before>#[cfg(not(windows))]
compile_error!("This demo only runs on Windows.");

extern crate directcomposition;
extern crate winit;

use directcomposition::DirectComposition;
use winit::os::windows::WindowExt;

fn main() {
    let mut events_loop = winit::EventsLoop::new();
    let window = winit::WindowBuilder::new()
        .with_title("Hello, world!")
        .with_dimensions(1024, 768)
        .build(&events_loop)
        .unwrap();

    let composition = direct_composition_from_window(&window);

    let visual = composition.create_d3d_visual(300, 200).unwrap();
    visual.set_offset_x(100.).unwrap();
    visual.set_offset_y(50.).unwrap();
    composition.commit().unwrap();

    let green_rgba = [0., 0.5, 0., 1.];
    visual.render_and_present_solid_frame(&composition, &green_rgba).unwrap();

    if std::env::var_os("INIT_ONLY").is_some() {
        return
    }

    events_loop.run_forever(|event| match event {
        winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => {
            winit::ControlFlow::Break
        }
        _ => winit::ControlFlow::Continue,
    });
}

fn direct_composition_from_window(window: &winit::Window) -> DirectComposition {
    unsafe {
        DirectComposition::new(window.get_hwnd() as _).unwrap()
    }
}
<commit_msg>Two D3D things in the same window<commit_after>#[cfg(not(windows))]
compile_error!("This demo only runs on Windows.");

extern crate directcomposition;
extern crate winit;

use directcomposition::DirectComposition;
use winit::os::windows::WindowExt;

fn main() {
    let mut events_loop = winit::EventsLoop::new();
    let window = winit::WindowBuilder::new()
        .with_title("Hello, world!")
        .with_dimensions(1024, 768)
        .build(&events_loop)
        .unwrap();

    let composition = direct_composition_from_window(&window);

    let visual1 = composition.create_d3d_visual(300, 200).unwrap();
    visual1.set_offset_x(100.).unwrap();
    visual1.set_offset_y(50.).unwrap();

    let visual2 = composition.create_d3d_visual(400, 300).unwrap();
    visual2.set_offset_x(200.).unwrap();
    visual2.set_offset_y(100.).unwrap();

    composition.commit().unwrap();

    visual1.render_and_present_solid_frame(&composition, &[0., 0.2, 0.4, 1.]).unwrap();
    visual2.render_and_present_solid_frame(&composition, &[0., 0.5, 0., 0.5]).unwrap();

    events_loop.run_forever(|event| match event {
        winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => {
            winit::ControlFlow::Break
        }
        _ => winit::ControlFlow::Continue,
    });
}

fn direct_composition_from_window(window: &winit::Window) -> DirectComposition {
    unsafe {
        DirectComposition::new(window.get_hwnd() as _).unwrap()
    }
}
<|endoftext|>