<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";

/*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();

        let mut app = build_cli();
        app.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: bool = match matches.occurrences_of("safe_zone") {
        0 => true,
        _ => false,
    };

    // what error level can we expect? always 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),
    }
}

// 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 {
        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(term::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(term::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(term::color::BRIGHT_WHITE).unwrap();
            write!(t, "  ").unwrap();
        }

        if (i + 1) % w == 0 {
            if safe {
                // draw right safe zone
                t.bg(term::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(term::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("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)),
        )
}
<commit_msg>some minor formatting changes<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: &'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";

/*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();

        let mut app = build_cli();
        app.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? always 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),
    }
}

// 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 {
        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("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)),
        )
}
<|endoftext|>


<commit_before>extern crate cargo_update;
extern crate tabwriter;
extern crate lazysort;
extern crate regex;
extern crate git2;

use std::process::{Command, exit};
use std::io::{Write, stdout};
use tabwriter::TabWriter;
use lazysort::SortedBy;
use std::fmt::Display;
use git2::Repository;
#[cfg(target_os="windows")]
use std::fs::File;
use regex::Regex;
use std::env;
use std::fs;

fn main() {
    let result = actual_main().err().unwrap_or(0);
    exit(result);
}

fn actual_main() -> Result<(), i32> {
    let opts = cargo_update::Options::parse();

    if cfg!(target_os = "windows") {
        let old_version_r = Regex::new(r"cargo-install-update\.exe-v.+").unwrap();
        for old_version in fs::read_dir(env::current_exe().unwrap().parent().unwrap().canonicalize().unwrap())
            .unwrap()
            .map(Result::unwrap)
            .filter(|f| old_version_r.is_match(&f.file_name().into_string().unwrap())) {
            fs::remove_file(old_version.path()).unwrap();
        }
    }

    let crates_file = cargo_update::ops::resolve_crates_file(opts.crates_file.1.clone());
    let configuration = try!(cargo_update::ops::PackageConfig::read(&crates_file.with_file_name(".install_config.toml")));
    let mut packages = cargo_update::ops::installed_main_repo_packages(&crates_file);

    if !opts.to_update.is_empty() {
        packages = cargo_update::ops::intersect_packages(&packages, &opts.to_update, opts.install);
    }

    {
        // Searching for "" will just update the registry
        let search_res = Command::new("cargo").arg("search").arg("").status().unwrap();
        if !search_res.success() {
            return Err(search_res.code().unwrap_or(-1));
        }
        println!("");
    }

    let registry = cargo_update::ops::get_index_path(&opts.cargo_dir.1);
    let registry_repo = try!(Repository::open(&registry).map_err(|_| {
        println!("Failed to open registry repository at {}.", registry.display());
        2
    }));
    let latest_registry = try!(registry_repo.revparse_single("origin/master").map_err(|_| {
        println!("Failed to read master branch of registry repository at {}.", registry.display());
        2
    }));

    for package in &mut packages {
        package.pull_version(&latest_registry.as_commit().unwrap().tree().unwrap(), &registry_repo);
    }

    {
        let mut out = TabWriter::new(stdout());
        writeln!(out, "Package\tInstalled\tLatest\tNeeds update").unwrap();
        for (package, package_target_version) in
            packages.iter()
                .map(|p| (p, configuration.get(&p.name).and_then(|c| c.target_version.as_ref())))
                .sorted_by(|&(ref lhs, lhstv), &(ref rhs, rhstv)| (!lhs.needs_update(lhstv), &lhs.name).cmp(&(!rhs.needs_update(rhstv), &rhs.name))) {
            write!(out, "{}\t", package.name).unwrap();
            if let Some(ref v) = package.version {
                write!(out, "v{}", v).unwrap();
            }
            if let Some(tv) = package_target_version {
                write!(out, "\t{}", tv).unwrap();
            } else if let Some(upd_v) = package.update_to_version() {
                write!(out, "\tv{}", upd_v).unwrap();
            } else {
                write!(out, "\tN/A").unwrap();
            }
            writeln!(out,
                     "\t{}",
                     if package.needs_update(package_target_version) {
                         "Yes"
                     } else {
                         "No"
                     })
                .unwrap();
        }
        writeln!(out, "").unwrap();
        out.flush().unwrap();
    }

    if opts.update {
        if !opts.force {
            packages.retain(|p| p.needs_update(configuration.get(&p.name).and_then(|c| c.target_version.as_ref())));
        }

        packages.retain(|pkg| pkg.update_to_version().is_some());

        if !packages.is_empty() {
            let (success_n, errored, result): (usize, Vec<String>, Option<i32>) = packages.into_iter()
                .map(|package| -> Result<(), (i32, String)> {
                    println!("{} {}",
                             if package.version.is_some() {
                                 "Updating"
                             } else {
                                 "Installing"
                             },
                             package.name);

                    if cfg!(target_os = "windows") && package.version.is_some() && package.name == "cargo-update" {
                        save_cargo_update_exec(package.version.as_ref().unwrap());
                    }

                    let install_res = if let Some(cfg) = configuration.get(&package.name) {
                            Command::new("cargo")
                                .args(&cfg.cargo_args()[..])
                                .arg(&package.name)
                                .arg("--vers")
                                .arg(if let Some(tv) = cfg.target_version.as_ref() {
                                    tv.to_string()
                                } else {
                                    package.update_to_version().unwrap().to_string()
                                })
                                .status()
                        } else {
                            Command::new("cargo")
                                .arg("install")
                                .arg("-f")
                                .arg(&package.name)
                                .arg("--vers")
                                .arg(package.update_to_version().unwrap().to_string())
                                .status()
                        }
                        .unwrap();

                    println!("");
                    if !install_res.success() {
                        if cfg!(target_os = "windows") && package.version.is_some() && package.name == "cargo-update" {
                            restore_cargo_update_exec(package.version.as_ref().unwrap());
                        }

                        Err((install_res.code().unwrap_or(-1), package.name))
                    } else {
                        Ok(())
                    }
                })
                .fold((0, vec![], None), |(s, mut e, r), p| match p {
                    Ok(()) => (s + 1, e, r),
                    Err((pr, pn)) => {
                        e.push(pn);
                        (s, e, r.or_else(|| Some(pr)))
                    }
                });

            println!("");
            println!("Updated {} package{}.", success_n, if success_n == 1 { "" } else { "s" });
            if !errored.is_empty() && result.is_some() {
                println!("Failed to update {}.", &errored.iter().fold("".to_string(), |s, e| s + ", " + e)[2..]);
                return Err(result.unwrap());
            }
        } else {
            println!("No packages need updating.");
        }
    }

    if opts.update_git {
        let mut packages = cargo_update::ops::installed_git_repo_packages(&crates_file);

        if !opts.to_update.is_empty() {
            packages.retain(|p| opts.to_update.iter().any(|u| p.name == u.0));
        }

        for package in &mut packages {
            package.pull_version(&opts.temp_dir.1);
        }

        {
            let mut out = TabWriter::new(stdout());
            writeln!(out, "Package\tInstalled\tLatest\tNeeds update").unwrap();
            for package in packages.iter()
                .sorted_by(|lhs, rhs| (!lhs.needs_update(), &lhs.name).cmp(&(!rhs.needs_update(), &rhs.name))) {
                writeln!(out,
                         "{}\t{}\t{}\t{}",
                         package.name,
                         package.id,
                         package.newest_id.as_ref().unwrap(),
                         if package.needs_update() { "Yes" } else { "No" })
                    .unwrap();
            }
            writeln!(out, "").unwrap();
            out.flush().unwrap();
        }

        if opts.update {
            if !opts.force {
                packages.retain(cargo_update::ops::GitRepoPackage::needs_update);
            }

            if !packages.is_empty() {
                let (success_n, errored, result): (usize, Vec<String>, Option<i32>) = packages.into_iter()
                    .map(|package| -> Result<(), (i32, String)> {
                        println!("Updating {} from {}", package.name, package.url);

                        if cfg!(target_os = "windows") && package.name == "cargo-update" {
                            save_cargo_update_exec(&package.id.to_string());
                        }

                        let install_res = if let Some(cfg) = configuration.get(&package.name) {
                                let mut cmd = Command::new("cargo");
                                cmd.args(&cfg.cargo_args()[..])
                                    .arg("--git")
                                    .arg(&package.url);
                                if let Some(ref b) = package.branch.as_ref() {
                                    cmd.arg("--branch").arg(b);
                                }
                                cmd.status()
                            } else {
                                let mut cmd = Command::new("cargo");
                                cmd.arg("install")
                                    .arg("-f")
                                    .arg("--git")
                                    .arg(&package.url);
                                if let Some(ref b) = package.branch.as_ref() {
                                    cmd.arg("--branch").arg(b);
                                }
                                cmd.status()
                            }
                            .unwrap();

                        println!("");
                        if !install_res.success() {
                            if cfg!(target_os = "windows") && package.name == "cargo-update" {
                                restore_cargo_update_exec(&package.id.to_string());
                            }

                            Err((install_res.code().unwrap_or(-1), package.name))
                        } else {
                            Ok(())
                        }
                    })
                    .fold((0, vec![], None), |(s, mut e, r), p| match p {
                        Ok(()) => (s + 1, e, r),
                        Err((pr, pn)) => {
                            e.push(pn);
                            (s, e, r.or_else(|| Some(pr)))
                        }
                    });

                println!("");
                println!("Updated {} git package{}.", success_n, if success_n == 1 { "" } else { "s" });
                if !errored.is_empty() && result.is_some() {
                    println!("Failed to update {}.", &errored.iter().fold("".to_string(), |s, e| s + ", " + e)[2..]);
                    return Err(result.unwrap());
                }
            } else {
                println!("No git packages need updating.");
            }
        }
    }

    Ok(())
}

/// This way the past-current exec will be "replaced" and we'll get no dupes in .cargo.toml
#[cfg(target_os="windows")]
fn save_cargo_update_exec<D: Display>(version: &D) {
    let cur_exe = env::current_exe().unwrap();
    fs::rename(&cur_exe, cur_exe.with_extension(format!("exe-v{}", version))).unwrap();
    File::create(cur_exe).unwrap();
}

#[cfg(target_os="windows")]
fn restore_cargo_update_exec<D: Display>(version: &D) {
    let cur_exe = env::current_exe().unwrap();
    fs::remove_file(&cur_exe).unwrap();
    fs::rename(cur_exe.with_extension(format!("exe-v{}", version)), cur_exe).unwrap();
}

#[cfg(not(target_os="windows"))]
fn save_cargo_update_exec<D: Display>(_: &D) {}

#[cfg(not(target_os="windows"))]
fn restore_cargo_update_exec<D: Display>(_: &D) {}
<commit_msg>Specify which package to install from git repo<commit_after>extern crate cargo_update;
extern crate tabwriter;
extern crate lazysort;
extern crate regex;
extern crate git2;

use std::process::{Command, exit};
use std::io::{Write, stdout};
use tabwriter::TabWriter;
use lazysort::SortedBy;
use std::fmt::Display;
use git2::Repository;
#[cfg(target_os="windows")]
use std::fs::File;
use regex::Regex;
use std::env;
use std::fs;

fn main() {
    let result = actual_main().err().unwrap_or(0);
    exit(result);
}

fn actual_main() -> Result<(), i32> {
    let opts = cargo_update::Options::parse();

    if cfg!(target_os = "windows") {
        let old_version_r = Regex::new(r"cargo-install-update\.exe-v.+").unwrap();
        for old_version in fs::read_dir(env::current_exe().unwrap().parent().unwrap().canonicalize().unwrap())
            .unwrap()
            .map(Result::unwrap)
            .filter(|f| old_version_r.is_match(&f.file_name().into_string().unwrap())) {
            fs::remove_file(old_version.path()).unwrap();
        }
    }

    let crates_file = cargo_update::ops::resolve_crates_file(opts.crates_file.1.clone());
    let configuration = try!(cargo_update::ops::PackageConfig::read(&crates_file.with_file_name(".install_config.toml")));
    let mut packages = cargo_update::ops::installed_main_repo_packages(&crates_file);

    if !opts.to_update.is_empty() {
        packages = cargo_update::ops::intersect_packages(&packages, &opts.to_update, opts.install);
    }

    {
        // Searching for "" will just update the registry
        let search_res = Command::new("cargo").arg("search").arg("").status().unwrap();
        if !search_res.success() {
            return Err(search_res.code().unwrap_or(-1));
        }
        println!("");
    }

    let registry = cargo_update::ops::get_index_path(&opts.cargo_dir.1);
    let registry_repo = try!(Repository::open(&registry).map_err(|_| {
        println!("Failed to open registry repository at {}.", registry.display());
        2
    }));
    let latest_registry = try!(registry_repo.revparse_single("origin/master").map_err(|_| {
        println!("Failed to read master branch of registry repository at {}.", registry.display());
        2
    }));

    for package in &mut packages {
        package.pull_version(&latest_registry.as_commit().unwrap().tree().unwrap(), &registry_repo);
    }

    {
        let mut out = TabWriter::new(stdout());
        writeln!(out, "Package\tInstalled\tLatest\tNeeds update").unwrap();
        for (package, package_target_version) in
            packages.iter()
                .map(|p| (p, configuration.get(&p.name).and_then(|c| c.target_version.as_ref())))
                .sorted_by(|&(ref lhs, lhstv), &(ref rhs, rhstv)| (!lhs.needs_update(lhstv), &lhs.name).cmp(&(!rhs.needs_update(rhstv), &rhs.name))) {
            write!(out, "{}\t", package.name).unwrap();
            if let Some(ref v) = package.version {
                write!(out, "v{}", v).unwrap();
            }
            if let Some(tv) = package_target_version {
                write!(out, "\t{}", tv).unwrap();
            } else if let Some(upd_v) = package.update_to_version() {
                write!(out, "\tv{}", upd_v).unwrap();
            } else {
                write!(out, "\tN/A").unwrap();
            }
            writeln!(out,
                     "\t{}",
                     if package.needs_update(package_target_version) {
                         "Yes"
                     } else {
                         "No"
                     })
                .unwrap();
        }
        writeln!(out, "").unwrap();
        out.flush().unwrap();
    }

    if opts.update {
        if !opts.force {
            packages.retain(|p| p.needs_update(configuration.get(&p.name).and_then(|c| c.target_version.as_ref())));
        }

        packages.retain(|pkg| pkg.update_to_version().is_some());

        if !packages.is_empty() {
            let (success_n, errored, result): (usize, Vec<String>, Option<i32>) = packages.into_iter()
                .map(|package| -> Result<(), (i32, String)> {
                    println!("{} {}",
                             if package.version.is_some() {
                                 "Updating"
                             } else {
                                 "Installing"
                             },
                             package.name);

                    if cfg!(target_os = "windows") && package.version.is_some() && package.name == "cargo-update" {
                        save_cargo_update_exec(package.version.as_ref().unwrap());
                    }

                    let install_res = if let Some(cfg) = configuration.get(&package.name) {
                            Command::new("cargo")
                                .args(&cfg.cargo_args()[..])
                                .arg(&package.name)
                                .arg("--vers")
                                .arg(if let Some(tv) = cfg.target_version.as_ref() {
                                    tv.to_string()
                                } else {
                                    package.update_to_version().unwrap().to_string()
                                })
                                .status()
                        } else {
                            Command::new("cargo")
                                .arg("install")
                                .arg("-f")
                                .arg(&package.name)
                                .arg("--vers")
                                .arg(package.update_to_version().unwrap().to_string())
                                .status()
                        }
                        .unwrap();

                    println!("");
                    if !install_res.success() {
                        if cfg!(target_os = "windows") && package.version.is_some() && package.name == "cargo-update" {
                            restore_cargo_update_exec(package.version.as_ref().unwrap());
                        }

                        Err((install_res.code().unwrap_or(-1), package.name))
                    } else {
                        Ok(())
                    }
                })
                .fold((0, vec![], None), |(s, mut e, r), p| match p {
                    Ok(()) => (s + 1, e, r),
                    Err((pr, pn)) => {
                        e.push(pn);
                        (s, e, r.or_else(|| Some(pr)))
                    }
                });

            println!("");
            println!("Updated {} package{}.", success_n, if success_n == 1 { "" } else { "s" });
            if !errored.is_empty() && result.is_some() {
                println!("Failed to update {}.", &errored.iter().fold("".to_string(), |s, e| s + ", " + e)[2..]);
                return Err(result.unwrap());
            }
        } else {
            println!("No packages need updating.");
        }
    }

    if opts.update_git {
        let mut packages = cargo_update::ops::installed_git_repo_packages(&crates_file);

        if !opts.to_update.is_empty() {
            packages.retain(|p| opts.to_update.iter().any(|u| p.name == u.0));
        }

        for package in &mut packages {
            package.pull_version(&opts.temp_dir.1);
        }

        {
            let mut out = TabWriter::new(stdout());
            writeln!(out, "Package\tInstalled\tLatest\tNeeds update").unwrap();
            for package in packages.iter()
                .sorted_by(|lhs, rhs| (!lhs.needs_update(), &lhs.name).cmp(&(!rhs.needs_update(), &rhs.name))) {
                writeln!(out,
                         "{}\t{}\t{}\t{}",
                         package.name,
                         package.id,
                         package.newest_id.as_ref().unwrap(),
                         if package.needs_update() { "Yes" } else { "No" })
                    .unwrap();
            }
            writeln!(out, "").unwrap();
            out.flush().unwrap();
        }

        if opts.update {
            if !opts.force {
                packages.retain(cargo_update::ops::GitRepoPackage::needs_update);
            }

            if !packages.is_empty() {
                let (success_n, errored, result): (usize, Vec<String>, Option<i32>) = packages.into_iter()
                    .map(|package| -> Result<(), (i32, String)> {
                        println!("Updating {} from {}", package.name, package.url);

                        if cfg!(target_os = "windows") && package.name == "cargo-update" {
                            save_cargo_update_exec(&package.id.to_string());
                        }

                        let install_res = if let Some(cfg) = configuration.get(&package.name) {
                                let mut cmd = Command::new("cargo");
                                cmd.args(&cfg.cargo_args()[..])
                                    .arg("--git")
                                    .arg(&package.url)
                                    .arg(&package.name);
                                if let Some(ref b) = package.branch.as_ref() {
                                    cmd.arg("--branch").arg(b);
                                }
                                cmd.status()
                            } else {
                                let mut cmd = Command::new("cargo");
                                cmd.arg("install")
                                    .arg("-f")
                                    .arg("--git")
                                    .arg(&package.url)
                                    .arg(&package.name);
                                if let Some(ref b) = package.branch.as_ref() {
                                    cmd.arg("--branch").arg(b);
                                }
                                cmd.status()
                            }
                            .unwrap();

                        println!("");
                        if !install_res.success() {
                            if cfg!(target_os = "windows") && package.name == "cargo-update" {
                                restore_cargo_update_exec(&package.id.to_string());
                            }

                            Err((install_res.code().unwrap_or(-1), package.name))
                        } else {
                            Ok(())
                        }
                    })
                    .fold((0, vec![], None), |(s, mut e, r), p| match p {
                        Ok(()) => (s + 1, e, r),
                        Err((pr, pn)) => {
                            e.push(pn);
                            (s, e, r.or_else(|| Some(pr)))
                        }
                    });

                println!("");
                println!("Updated {} git package{}.", success_n, if success_n == 1 { "" } else { "s" });
                if !errored.is_empty() && result.is_some() {
                    println!("Failed to update {}.", &errored.iter().fold("".to_string(), |s, e| s + ", " + e)[2..]);
                    return Err(result.unwrap());
                }
            } else {
                println!("No git packages need updating.");
            }
        }
    }

    Ok(())
}

/// This way the past-current exec will be "replaced" and we'll get no dupes in .cargo.toml
#[cfg(target_os="windows")]
fn save_cargo_update_exec<D: Display>(version: &D) {
    let cur_exe = env::current_exe().unwrap();
    fs::rename(&cur_exe, cur_exe.with_extension(format!("exe-v{}", version))).unwrap();
    File::create(cur_exe).unwrap();
}

#[cfg(target_os="windows")]
fn restore_cargo_update_exec<D: Display>(version: &D) {
    let cur_exe = env::current_exe().unwrap();
    fs::remove_file(&cur_exe).unwrap();
    fs::rename(cur_exe.with_extension(format!("exe-v{}", version)), cur_exe).unwrap();
}

#[cfg(not(target_os="windows"))]
fn save_cargo_update_exec<D: Display>(_: &D) {}

#[cfg(not(target_os="windows"))]
fn restore_cargo_update_exec<D: Display>(_: &D) {}
<|endoftext|>


<commit_before>//! # Hexdino
//!
//! A hex editor with vim like keybindings written in Rust.

#![doc(html_logo_url = "https://raw.githubusercontent.com/Luz/hexdino/master/logo.png")]

use std::io::prelude::*;
use std::fs::OpenOptions;
use std::io::SeekFrom;
use std::path::Path;
use std::error::Error;
use std::env;

mod draw;
mod find;
use draw::draw;
use find::FindSubset;

extern crate ncurses;
use ncurses::*;

//extern crate getopts;
//use getopts::Options;

#[derive(PartialEq, Copy, Clone)]
pub enum Mode {
    Command,
    Replace,
    TypeCommand,
    Insert,
    TypeSearch,
    SearchIt
}

fn main() {
    let mut buf = vec![];
    let mut cursorpos:usize = 0;
    //0 is left nibble, 1 is right nibble, 2 is ascii
    let mut cursorstate:usize = 0;
    // 0 = display data from first line of file
    let mut screenoffset:usize = 0;
    const SPALTEN:usize = 16;
    let mut command = String::new();

    //start ncursesw
    initscr();
    let screenheight : usize = getmaxy(stdscr) as usize;
    //ctrl+z and fg works with this
    cbreak();
    noecho();
    start_color();
    init_pair(1, COLOR_GREEN, COLOR_BLACK);

    printw("Welcome to Hexdino.\nPlease find the any-key on your keyboard and press it.\n");

    let args: Vec<_> = env::args().collect();
    /*
    let program = args[0].clone();
    let mut opts = Options::new();
    opts.optopt("f", "", "set file name", "NAME");
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };
    if matches.opt_present("h") {
        let brief = format!("Usage: {} FILE [options]", program);
            print!("{}", opts.usage(&brief));
        return;
    }
    let path = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        let brief = format!("Usage: {} FILE [options]", program);
            print!("{}", opts.usage(&brief));
        return;
    };*/

    let path = if args.len() > 1 {
        printw(&format!("Opening file {}", args[1]));
        args[1].clone()
    } else {
        printw(&format!("No file specified. Trying to open foo.txt"));
        "foo.txt".into()
    };

    let path = Path::new(&path);
    let display = path.display();

    getch();
    clear();

    if !has_colors() {
        endwin();
        println!("Your terminal does not support color!\n");
        return;
    }

//TODO in this order: 1)disp files 2) hjkl movement 3) edit file by 'r' 4) save file 5) edit file by 'x, i' 6) search by '/'

    let mut file = match OpenOptions::new().read(true).write(true).create(true).open(&path) {
        Err(why) => panic!("couldn't open {}: {}", display,
            Error::description(&why)),
        Ok(file) => file,
    };

    file.read_to_end(&mut buf).ok().expect("File could not be read.");

    let mut mode = Mode::Command;

    draw(&buf, cursorpos, SPALTEN, mode, &command, cursorstate, screenoffset);

    let mut key;
//    key = getch() as u8;
//    printw(&format!("{:?}", key));

    let mut quitnow = 0;
    while quitnow == 0 {
        key = getch() as u8;
        if mode == Mode::Command {
            match key as char {
                'h' => {
                    if cursorstate == 2 { // ascii mode
                        if cursorpos > 0 { // not at start
                            cursorpos-=1; // go left
                        }
                    }
                    else if cursorstate == 1 { // hex mode, right nibble
                        cursorstate = 0; // left nibble
                    }
                    else if cursorstate == 0 { // hex mode, left nibble
                        if cursorpos > 0 { // not at start
                            cursorstate = 1; // right nibble
                            cursorpos-=1; // go left
                        }
                    }
                },
                'j' => {
                    if cursorpos+SPALTEN < buf.len() { // not at end
                        cursorpos+=SPALTEN; // go down
                    }
                    else { // when at end
                        if buf.len() != 0 { // Suppress underflow
                            cursorpos=buf.len()-1; // go to end
                        }
                    }
                },
                'k' => {
                    if cursorpos >= SPALTEN {
                        cursorpos-=SPALTEN;
                    }
                },
                'l' => {
                    if cursorstate == 2 { // ascii mode
                        if cursorpos < buf.len()-1 { // not at end
                            cursorpos+=1; // go right
                        }
                    }
                    else if cursorstate == 0 { // hex mode, left nibble
                        cursorstate = 1; // right nibble
                    }
                    else if cursorstate == 1 { // hex mode, right nibble
                        if cursorpos < buf.len()-1 { // not at end
                            cursorstate = 0; // left nibble
                            cursorpos+=1; // go right
                        }
                    }
                },
                 '0' => {
                    cursorpos -= cursorpos%SPALTEN; // jump to start of line
                    if cursorstate == 1 { // hex mode, right nibble
                        cursorstate = 0; // left nibble
                    }
                },
                 '$' => {
                    if cursorpos-(cursorpos%SPALTEN)+(SPALTEN-1) < buf.len() { // check if no overflow
                        cursorpos = cursorpos-(cursorpos%SPALTEN)+(SPALTEN-1); // jump to end of line
                    }
                    else {
                        cursorpos = buf.len()-1 // jump to end of line
                    }
                    if cursorstate == 0 { // hex mode, left nibble
                        cursorstate = 1; // right nibble
                    }
                },
                'r' => {
                    mode = Mode::Replace;
                },
                'x' => {
                    if buf.len() > 0 { // remove the current char
                        buf.remove(cursorpos);
                        if cursorpos >= buf.len() {
                            cursorpos = buf.len()-1;
                        }
                    }
                },
                'i' => {
                    mode = Mode::Insert;
                },
                 ':' => {
                     command.clear(); // delete old command
                     mode = Mode::TypeCommand;
                 },
                 'J' => {
                     if cursorstate == 2 { // ascii mode
                         cursorstate = 0; // hex mode, left nibble
                     }
                     else {
                         cursorstate = 2; // jump to ascii
                     }
                 },
                 '?' => { //TODO
                     command.push_str("No helpfile yet");
                 },
                 '/' => { //TODO
                     command.clear();
                     mode = Mode::TypeSearch;
                 },
                _ => (),
            }

            //Always move screen when cursor leaves screen
            if cursorpos > (screenheight+screenoffset-1)*SPALTEN -1 {
                screenoffset+=1; // move screen
            }
            if cursorpos < screenoffset*SPALTEN {
                screenoffset-=1; // move screen
            }

        } else if mode == Mode::Replace && cursorstate == 2 {
            // r was pressed so replace next char in ascii mode
            match key {
                c @ 32...126 => { buf[cursorpos] = c },
                _ => (),
            }
            mode = Mode::Command;
        } else if mode == Mode::Replace {
            let mask = if cursorstate == 0 { 0x0F } else { 0xF0 };
            let shift = if cursorstate == 0 { 4 } else { 0 };
            // Change the selected nibble
            match key as char {
                c @ 'A'...'F' =>
                    { buf[cursorpos] = buf[cursorpos]&mask | (c as u8 - 55)<<shift },
                c @ 'a'...'f' =>
                    { buf[cursorpos] = buf[cursorpos]&mask | (c as u8 - 87)<<shift },
                c @ '0'...'9' =>
                    { buf[cursorpos] = buf[cursorpos]&mask | (c as u8 - 48)<<shift },
                _ => ()
            }
            mode = Mode::Command;
        } else if mode == Mode::TypeCommand {
            match key {
                c @ 32...126 => { command.push(c as char); },
                27 => {command.clear();mode = Mode::Command;},
                10 => { // Enter pressed, compute command!
                        if (command == "w".to_string()) || (command == "wq".to_string()) {
                            file.seek(SeekFrom::Start(0)).ok().expect("Filepointer could not be set to 0");
                            file.write_all(&mut buf).ok().expect("File could not be written.");
                            if command == "wq".to_string() {
                                quitnow = 1;
                            }
                            command.clear();mode = Mode::Command;
                        }
                        else if command == "q".to_string() {
                            quitnow = 1;
                        }
                        else {
                            command.clear();
                            command.push_str("Bad_command!");
                            mode = Mode::Command;
                        }
                    },
                _ => (),
            }
        } else if mode == Mode::Insert {
            if cursorstate == 0 { // Left nibble
                match key {
                    c @ 65... 70 => // A-F
                        {buf.insert(cursorpos, (c-55)<<4 ); cursorstate = 1;},
                    c @ 97...102 => // a-f
                        {buf.insert(cursorpos, (c-87)<<4 ); cursorstate = 1;},
                    c @ 48... 57 => // 0-9
                        {buf.insert(cursorpos, (c-48)<<4 ); cursorstate = 1;},
                    27 => {mode = Mode::Command;},
                    _ => ()
                }
            } else if cursorstate == 1 { // Right nibble
                match key {
                    c @ 65...70 => // A-F
                        { buf[cursorpos] = buf[cursorpos]&0xF0 | (c-55); cursorstate = 0; cursorpos+=1; },
                    c @ 97...102 => // a-f
                        { buf[cursorpos] = buf[cursorpos]&0xF0 | (c-87); cursorstate = 0; cursorpos+=1; },
                    c @ 48...57 => // 0-9
                        { buf[cursorpos] = buf[cursorpos]&0xF0 | (c-48); cursorstate = 0; cursorpos+=1; },
                    27 => {mode = Mode::Command;},
                    _ => ()
                }
            } else if cursorstate == 2 { // Ascii
                match key {
                    c @ 32...126 => { buf.insert(cursorpos, c); cursorpos+=1; },
                    27 => {mode = Mode::Command;},
                    _ => (),
                }
            }
        } else if mode == Mode::TypeSearch {
//            if cursorstate == 2 { // Ascii search
                match key {
                    c @ 32...126 => { command.push(c as char); },
                    27 => {command.clear();mode = Mode::Command;},
                    10 => { // Enter pressed, compute command!
                        mode = Mode::SearchIt;
                    }
                    _ => (),
                }
//            }

            if mode == Mode::SearchIt {
                let search = command.as_bytes();
                cursorpos = buf.find_subset(&search).unwrap_or(cursorpos);
                mode = Mode::Command;
                    //command.push_str("Bad_command!");
            }
        }
        draw(&buf, cursorpos, SPALTEN, mode, &command, cursorstate, screenoffset);
    }

    refresh();
    endwin();
}

<commit_msg>Use to_digit instead of match with ranges<commit_after>//! # Hexdino
//!
//! A hex editor with vim like keybindings written in Rust.

#![doc(html_logo_url = "https://raw.githubusercontent.com/Luz/hexdino/master/logo.png")]

use std::io::prelude::*;
use std::fs::OpenOptions;
use std::io::SeekFrom;
use std::path::Path;
use std::error::Error;
use std::env;

mod draw;
mod find;
use draw::draw;
use find::FindSubset;

extern crate ncurses;
use ncurses::*;

//extern crate getopts;
//use getopts::Options;

#[derive(PartialEq, Copy, Clone)]
pub enum Mode {
    Command,
    Replace,
    TypeCommand,
    Insert,
    TypeSearch,
    SearchIt
}

fn main() {
    let mut buf = vec![];
    let mut cursorpos:usize = 0;
    //0 is left nibble, 1 is right nibble, 2 is ascii
    let mut cursorstate:usize = 0;
    // 0 = display data from first line of file
    let mut screenoffset:usize = 0;
    const SPALTEN:usize = 16;
    let mut command = String::new();

    //start ncursesw
    initscr();
    let screenheight : usize = getmaxy(stdscr) as usize;
    //ctrl+z and fg works with this
    cbreak();
    noecho();
    start_color();
    init_pair(1, COLOR_GREEN, COLOR_BLACK);

    printw("Welcome to Hexdino.\nPlease find the any-key on your keyboard and press it.\n");

    let args: Vec<_> = env::args().collect();
    /*
    let program = args[0].clone();
    let mut opts = Options::new();
    opts.optopt("f", "", "set file name", "NAME");
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };
    if matches.opt_present("h") {
        let brief = format!("Usage: {} FILE [options]", program);
            print!("{}", opts.usage(&brief));
        return;
    }
    let path = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        let brief = format!("Usage: {} FILE [options]", program);
            print!("{}", opts.usage(&brief));
        return;
    };*/

    let path = if args.len() > 1 {
        printw(&format!("Opening file {}", args[1]));
        args[1].clone()
    } else {
        printw(&format!("No file specified. Trying to open foo.txt"));
        "foo.txt".into()
    };

    let path = Path::new(&path);
    let display = path.display();

    getch();
    clear();

    if !has_colors() {
        endwin();
        println!("Your terminal does not support color!\n");
        return;
    }

//TODO in this order: 1)disp files 2) hjkl movement 3) edit file by 'r' 4) save file 5) edit file by 'x, i' 6) search by '/'

    let mut file = match OpenOptions::new().read(true).write(true).create(true).open(&path) {
        Err(why) => panic!("couldn't open {}: {}", display,
            Error::description(&why)),
        Ok(file) => file,
    };

    file.read_to_end(&mut buf).ok().expect("File could not be read.");

    let mut mode = Mode::Command;

    draw(&buf, cursorpos, SPALTEN, mode, &command, cursorstate, screenoffset);

    let mut key;
//    key = getch() as u8;
//    printw(&format!("{:?}", key));

    let mut quitnow = 0;
    while quitnow == 0 {
        key = getch() as u8;
        if mode == Mode::Command {
            match key as char {
                'h' => {
                    if cursorstate == 2 { // ascii mode
                        if cursorpos > 0 { // not at start
                            cursorpos-=1; // go left
                        }
                    }
                    else if cursorstate == 1 { // hex mode, right nibble
                        cursorstate = 0; // left nibble
                    }
                    else if cursorstate == 0 { // hex mode, left nibble
                        if cursorpos > 0 { // not at start
                            cursorstate = 1; // right nibble
                            cursorpos-=1; // go left
                        }
                    }
                },
                'j' => {
                    if cursorpos+SPALTEN < buf.len() { // not at end
                        cursorpos+=SPALTEN; // go down
                    }
                    else { // when at end
                        if buf.len() != 0 { // Suppress underflow
                            cursorpos=buf.len()-1; // go to end
                        }
                    }
                },
                'k' => {
                    if cursorpos >= SPALTEN {
                        cursorpos-=SPALTEN;
                    }
                },
                'l' => {
                    if cursorstate == 2 { // ascii mode
                        if cursorpos < buf.len()-1 { // not at end
                            cursorpos+=1; // go right
                        }
                    }
                    else if cursorstate == 0 { // hex mode, left nibble
                        cursorstate = 1; // right nibble
                    }
                    else if cursorstate == 1 { // hex mode, right nibble
                        if cursorpos < buf.len()-1 { // not at end
                            cursorstate = 0; // left nibble
                            cursorpos+=1; // go right
                        }
                    }
                },
                 '0' => {
                    cursorpos -= cursorpos%SPALTEN; // jump to start of line
                    if cursorstate == 1 { // hex mode, right nibble
                        cursorstate = 0; // left nibble
                    }
                },
                 '$' => {
                    if cursorpos-(cursorpos%SPALTEN)+(SPALTEN-1) < buf.len() { // check if no overflow
                        cursorpos = cursorpos-(cursorpos%SPALTEN)+(SPALTEN-1); // jump to end of line
                    }
                    else {
                        cursorpos = buf.len()-1 // jump to end of line
                    }
                    if cursorstate == 0 { // hex mode, left nibble
                        cursorstate = 1; // right nibble
                    }
                },
                'r' => {
                    mode = Mode::Replace;
                },
                'x' => {
                    if buf.len() > 0 { // remove the current char
                        buf.remove(cursorpos);
                        if cursorpos >= buf.len() {
                            cursorpos = buf.len()-1;
                        }
                    }
                },
                'i' => {
                    mode = Mode::Insert;
                },
                 ':' => {
                     command.clear(); // delete old command
                     mode = Mode::TypeCommand;
                 },
                 'J' => {
                     if cursorstate == 2 { // ascii mode
                         cursorstate = 0; // hex mode, left nibble
                     }
                     else {
                         cursorstate = 2; // jump to ascii
                     }
                 },
                 '?' => { //TODO
                     command.push_str("No helpfile yet");
                 },
                 '/' => { //TODO
                     command.clear();
                     mode = Mode::TypeSearch;
                 },
                _ => (),
            }

            //Always move screen when cursor leaves screen
            if cursorpos > (screenheight+screenoffset-1)*SPALTEN -1 {
                screenoffset+=1; // move screen
            }
            if cursorpos < screenoffset*SPALTEN {
                screenoffset-=1; // move screen
            }

        } else if mode == Mode::Replace && cursorstate == 2 {
            // r was pressed so replace next char in ascii mode
            match key {
                c @ 32...126 => { buf[cursorpos] = c },
                _ => (),
            }
            mode = Mode::Command;
        } else if mode == Mode::Replace {
            let mask = if cursorstate == 0 { 0x0F } else { 0xF0 };
            let shift = if cursorstate == 0 { 4 } else { 0 };
            // Change the selected nibble
            if let Some(c) = (key as char).to_digit(16) {
                buf[cursorpos] = buf[cursorpos] & mask | (c as u8) << shift;
            }
            mode = Mode::Command;
        } else if mode == Mode::TypeCommand {
            match key {
                c @ 32...126 => { command.push(c as char); },
                27 => {command.clear();mode = Mode::Command;},
                10 => { // Enter pressed, compute command!
                        if (command == "w".to_string()) || (command == "wq".to_string()) {
                            file.seek(SeekFrom::Start(0)).ok().expect("Filepointer could not be set to 0");
                            file.write_all(&mut buf).ok().expect("File could not be written.");
                            if command == "wq".to_string() {
                                quitnow = 1;
                            }
                            command.clear();mode = Mode::Command;
                        }
                        else if command == "q".to_string() {
                            quitnow = 1;
                        }
                        else {
                            command.clear();
                            command.push_str("Bad_command!");
                            mode = Mode::Command;
                        }
                    },
                _ => (),
            }
        } else if mode == Mode::Insert {
            if cursorstate == 0 { // Left nibble
                match key {
                    c @ 65... 70 => // A-F
                        {buf.insert(cursorpos, (c-55)<<4 ); cursorstate = 1;},
                    c @ 97...102 => // a-f
                        {buf.insert(cursorpos, (c-87)<<4 ); cursorstate = 1;},
                    c @ 48... 57 => // 0-9
                        {buf.insert(cursorpos, (c-48)<<4 ); cursorstate = 1;},
                    27 => {mode = Mode::Command;},
                    _ => ()
                }
            } else if cursorstate == 1 { // Right nibble
                match key {
                    c @ 65...70 => // A-F
                        { buf[cursorpos] = buf[cursorpos]&0xF0 | (c-55); cursorstate = 0; cursorpos+=1; },
                    c @ 97...102 => // a-f
                        { buf[cursorpos] = buf[cursorpos]&0xF0 | (c-87); cursorstate = 0; cursorpos+=1; },
                    c @ 48...57 => // 0-9
                        { buf[cursorpos] = buf[cursorpos]&0xF0 | (c-48); cursorstate = 0; cursorpos+=1; },
                    27 => {mode = Mode::Command;},
                    _ => ()
                }
            } else if cursorstate == 2 { // Ascii
                match key {
                    c @ 32...126 => { buf.insert(cursorpos, c); cursorpos+=1; },
                    27 => {mode = Mode::Command;},
                    _ => (),
                }
            }
        } else if mode == Mode::TypeSearch {
//            if cursorstate == 2 { // Ascii search
                match key {
                    c @ 32...126 => { command.push(c as char); },
                    27 => {command.clear();mode = Mode::Command;},
                    10 => { // Enter pressed, compute command!
                        mode = Mode::SearchIt;
                    }
                    _ => (),
                }
//            }

            if mode == Mode::SearchIt {
                let search = command.as_bytes();
                cursorpos = buf.find_subset(&search).unwrap_or(cursorpos);
                mode = Mode::Command;
                    //command.push_str("Bad_command!");
            }
        }
        draw(&buf, cursorpos, SPALTEN, mode, &command, cursorstate, screenoffset);
    }

    refresh();
    endwin();
}

<|endoftext|>


<commit_before>extern crate argparse;
extern crate base64;
extern crate env_logger;
extern crate hyper;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serialport;
extern crate websocket;

mod serial_support;

use std::thread;
use std::io::Write;
use std::collections::HashMap;

use argparse::{ArgumentParser, Store};
use websocket::{Server, Message};
use websocket::message::Type;
use hyper::Server as HttpServer;
use hyper::net::Fresh;
use hyper::server::request::Request;
use hyper::server::response::Response;

use serial_support::messages::*;
use serial_support::manage::*;

fn main() {

  // Init logger
  env_logger::init().unwrap();

  // let sr = SerialResponse::Response {
  //     data: "HEY YOU".to_string(),
  //     base64: None,
  // };
  // info!("serialized = {}", serde_json::to_string(&sr).unwrap());

  // Default port number
  let mut port = 8080;
  // Parse cmdline args
  {
    let mut ap = ArgumentParser::new();
    ap.set_description("Provide access to serial ports over JSON Websockets");
    ap.refer(&mut port)
      .add_option(&["-p", "--port"], Store, "Http Port");
    ap.parse_args_or_exit();
  }

  // The HTTP server handler
  let http_handler = move |_: Request, response: Response<Fresh>| {
    let mut response = response.start().unwrap();
    // Send a client webpage
    response
      .write_all(format!(include_str!("websockets.html"), wsPort = port + 1).as_bytes())
      .unwrap();
    response.end().unwrap();
  };

  info!("Using ports {} {}", port, port + 1);

  // Start listening for http connections
  thread::spawn(move || {
                  let http_server = HttpServer::http(format!("127.0.0.1:{}", port)).unwrap();
                  http_server.handle(http_handler).unwrap();
                });

  // Start listening for WebSocket connections
  let ws_server = Server::bind(format!("127.0.0.1:{}", port + 1)).unwrap();

  for connection in ws_server.filter_map(Result::ok) {
    // Spawn a new thread for each connection.
    thread::spawn(move || {
      if !connection
            .protocols()
            .contains(&"rust-websocket".to_string()) {
        connection.reject().unwrap();
        return;
      }

      let client = connection
        .use_protocol("rust-websocket")
        .accept()
        .unwrap();

      let ip = client.peer_addr().unwrap();

      info!("Connection from {}", ip);

      //   let message = Message::text("Hello".to_string());
      //   client.send_message(&message).unwrap();

      let (mut receiver, mut sender) = client.split().unwrap();

      for message in receiver.incoming_messages() {
        let message: Message = message.unwrap();

        match message.opcode {

          Type::Close => {
            let message = Message::close();
            sender
              .send_message(&message)
              .unwrap_or_else(|_| info!("Client {} hung up!", ip));
            info!("Client {} disconnected", ip);
            return;
          }

          Type::Ping => {
            let message = Message::pong(message.payload);
            sender
              .send_message(&message)
              .unwrap_or_else(|_| info!("Could not ping client {}!", ip));
          }

          _ => {

            // Get the payload, in a lossy manner
            let msg = String::from_utf8_lossy(&message.payload);

            // Function to remap Json Deserizilation error
            // to a SerialResponse:Error
            let remap_error = |_| -> SerialResponse {
              SerialResponse::Error {
                kind: ErrorType::JsonParseFailure,
                msg: "Unable to parse json".to_string(),
                detail: Some(msg.to_string()),
                port: None,
                handle: None,
              }
            };

            // So we will get a result <SerialRequest::*,SerialResponse::Error> back
            let res: Result<SerialRequest, SerialResponse> = serde_json::from_str(&msg)
              .map_err(remap_error);

            let reply = match res {
              Ok(req) => Message::text(serde_json::to_string(&req).unwrap()),
              Err(err) => Message::text(serde_json::to_string(&err).unwrap()),
            };

            sender
              .send_message(&reply)
              .unwrap_or_else(|_| {
                                info!("Could send message {} to client {}",
                                      String::from_utf8_lossy(&message.payload),
                                      ip)
                              });
          }
        }
      }
    });
  }
}

fn handle_serial_req(req: SerialRequest) {
  match req {
    SerialRequest::Open { port } => {}
    SerialRequest::Write {
      handle,
      port,
      data,
      base64,
    } => {}
    SerialRequest::WriteLock { handle, port } => {}
    SerialRequest::ReleaseWriteLock { handle, port } => {}
    SerialRequest::Close { port } => {}
  }
}
<commit_msg>Remove unecessary imports<commit_after>extern crate argparse;
extern crate base64;
extern crate env_logger;
extern crate hyper;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serialport;
extern crate websocket;

mod serial_support;

use std::thread;
use std::io::Write;

use argparse::{ArgumentParser, Store};
use websocket::{Server, Message};
use websocket::message::Type;
use hyper::Server as HttpServer;
use hyper::net::Fresh;
use hyper::server::request::Request;
use hyper::server::response::Response;

use serial_support::messages::*;

fn main() {

  // Init logger
  env_logger::init().unwrap();

  // let sr = SerialResponse::Response {
  //     data: "HEY YOU".to_string(),
  //     base64: None,
  // };
  // info!("serialized = {}", serde_json::to_string(&sr).unwrap());

  // Default port number
  let mut port = 8080;
  // Parse cmdline args
  {
    let mut ap = ArgumentParser::new();
    ap.set_description("Provide access to serial ports over JSON Websockets");
    ap.refer(&mut port)
      .add_option(&["-p", "--port"], Store, "Http Port");
    ap.parse_args_or_exit();
  }

  // The HTTP server handler
  let http_handler = move |_: Request, response: Response<Fresh>| {
    let mut response = response.start().unwrap();
    // Send a client webpage
    response
      .write_all(format!(include_str!("websockets.html"), wsPort = port + 1).as_bytes())
      .unwrap();
    response.end().unwrap();
  };

  info!("Using ports {} {}", port, port + 1);

  // Start listening for http connections
  thread::spawn(move || {
                  let http_server = HttpServer::http(format!("127.0.0.1:{}", port)).unwrap();
                  http_server.handle(http_handler).unwrap();
                });

  // Start listening for WebSocket connections
  let ws_server = Server::bind(format!("127.0.0.1:{}", port + 1)).unwrap();

  for connection in ws_server.filter_map(Result::ok) {
    // Spawn a new thread for each connection.
    thread::spawn(move || {
      if !connection
            .protocols()
            .contains(&"rust-websocket".to_string()) {
        connection.reject().unwrap();
        return;
      }

      let client = connection
        .use_protocol("rust-websocket")
        .accept()
        .unwrap();

      let ip = client.peer_addr().unwrap();

      info!("Connection from {}", ip);

      //   let message = Message::text("Hello".to_string());
      //   client.send_message(&message).unwrap();

      let (mut receiver, mut sender) = client.split().unwrap();

      for message in receiver.incoming_messages() {
        let message: Message = message.unwrap();

        match message.opcode {

          Type::Close => {
            let message = Message::close();
            sender
              .send_message(&message)
              .unwrap_or_else(|_| info!("Client {} hung up!", ip));
            info!("Client {} disconnected", ip);
            return;
          }

          Type::Ping => {
            let message = Message::pong(message.payload);
            sender
              .send_message(&message)
              .unwrap_or_else(|_| info!("Could not ping client {}!", ip));
          }

          _ => {

            // Get the payload, in a lossy manner
            let msg = String::from_utf8_lossy(&message.payload);

            // Function to remap Json Deserizilation error
            // to a SerialResponse:Error
            let remap_error = |_| -> SerialResponse {
              SerialResponse::Error {
                kind: ErrorType::JsonParseFailure,
                msg: "Unable to parse json".to_string(),
                detail: Some(msg.to_string()),
                port: None,
                handle: None,
              }
            };

            // So we will get a result <SerialRequest::*,SerialResponse::Error> back
            let res: Result<SerialRequest, SerialResponse> = serde_json::from_str(&msg)
              .map_err(remap_error);

            let reply = match res {
              Ok(req) => Message::text(serde_json::to_string(&req).unwrap()),
              Err(err) => Message::text(serde_json::to_string(&err).unwrap()),
            };

            sender
              .send_message(&reply)
              .unwrap_or_else(|_| {
                                info!("Could send message {} to client {}",
                                      String::from_utf8_lossy(&message.payload),
                                      ip)
                              });
          }
        }
      }
    });
  }
}

fn handle_serial_req(req: SerialRequest) {
  match req {
    SerialRequest::Open { port } => {}
    SerialRequest::Write {
      handle,
      port,
      data,
      base64,
    } => {}
    SerialRequest::WriteLock { handle, port } => {}
    SerialRequest::ReleaseWriteLock { handle, port } => {}
    SerialRequest::Close { port } => {}
  }
}
<|endoftext|>


<commit_before>extern crate case;
extern crate docopt;
extern crate env_logger;
extern crate git2;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate xml;
extern crate toml;

use std::error::Error;
use std::process;

use env::Env;
use library::Library;

//generated by build.rs
mod gir_version;

mod analysis;
mod codegen;
mod config;
mod env;
mod file_saver;
mod git;
mod gobjects;
mod library;
mod nameutil;
mod parser;
mod traits;
mod version;

#[cfg_attr(test, allow(dead_code))]
fn main() {
    if let Err(err) = do_main() {
        println!("{}", err);
        process::exit(1);
    }
}

fn do_main() -> Result<(), Box<Error>> {
    try!(env_logger::init());

    let cfg = match config::Config::new() {
        Ok(cfg) => cfg,
        Err(config::Error::CommandLine(ref err)) if !err.fatal() => return Ok(()),
        Err(err) => return Err(Box::new(err)),
    };

    let mut library = Library::new(&cfg.library_name);
    library.read_file(&cfg.girs_dir, &cfg.library_full_name());
    library.fill_in();

    let env = Env{ library: library, config: cfg };
    codegen::generate(&env);

    Ok(())
}
<commit_msg>Set RUST_LOG to warn by default<commit_after>extern crate case;
extern crate docopt;
extern crate env_logger;
extern crate git2;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate xml;
extern crate toml;

use std::error::Error;
use std::process;

use env::Env;
use library::Library;

//generated by build.rs
mod gir_version;

mod analysis;
mod codegen;
mod config;
mod env;
mod file_saver;
mod git;
mod gobjects;
mod library;
mod nameutil;
mod parser;
mod traits;
mod version;

#[cfg_attr(test, allow(dead_code))]
fn main() {
    if let Err(err) = do_main() {
        println!("{}", err);
        process::exit(1);
    }
}

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

    let cfg = match config::Config::new() {
        Ok(cfg) => cfg,
        Err(config::Error::CommandLine(ref err)) if !err.fatal() => return Ok(()),
        Err(err) => return Err(Box::new(err)),
    };

    let mut library = Library::new(&cfg.library_name);
    library.read_file(&cfg.girs_dir, &cfg.library_full_name());
    library.fill_in();

    let env = Env{ library: library, config: cfg };
    codegen::generate(&env);

    Ok(())
}
<|endoftext|>


<commit_before>use std::collections::hash_map::HashMap;
use std::collections::hash_set::HashSet;
use std::fmt::{Display, Formatter, Error};
use std::string::String;
use std::vec::Vec;

use super::allocator::Allocator;
use super::binding::UniqueBinding;
use super::js_var::{JsVar, JsKey, JsType, JsPtrEnum};

#[derive(Clone, Debug)]
pub struct JsObjStruct {
    pub proto: JsProto,
    pub name: String,
    pub dict: HashMap<JsKey, JsVar>,
}

impl JsObjStruct {
    #[allow(unused_variables)]
    pub fn new<T: Allocator>(proto: JsProto, name: &str,
                             kv_tuples: Vec<(JsKey, JsVar, Option<JsPtrEnum>)>,
                             allocator: &mut T) -> JsObjStruct {
        JsObjStruct {
            proto: None,
            name: String::from(name),
            dict: kv_tuples.into_iter().map(|(k, v, ptr)| {
                if let Some(ptr) = ptr {
                    allocator.alloc(v.unique.clone(), ptr).expect("Unable to allocate!"); // TODO better error handling
                }
                (k, v)
            }).collect()
        }
    }

    pub fn add_key<T: Allocator>(&mut self, k: JsKey, v: JsVar, ptr: Option<JsPtrEnum>, allocator: &mut T) {
        // If the key already exists, potentially condemn its pointer, which is being overwritten.
        if let Some(var) = self.dict.get(&k) {
            match var.t {
                JsType::JsPtr(_) => allocator.condemn(var.unique.clone()).expect("Unable to whiten!"),
                _ => {}
            }
        }
        // Then, allocate the new pointer if necessary...
        if let Some(ptr) = ptr {
            allocator.alloc(v.unique.clone(), ptr).expect("Unable to allocate!"); // TODO better error handling
        }
        // ...and insert the key & value into the dictionary blindly.
        self.dict.insert(k, v);
    }

    pub fn get_children(&self) -> HashSet<UniqueBinding> {
        let mut bindings = HashSet::new();
        for v in self.dict.values() {
            match v.t {
                JsType::JsPtr(_) => { bindings.insert(v.unique.clone()); },
                _ => (),
            }
        }
        bindings
    }
}

impl Display for JsObjStruct {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        try!(write!(fmt, "{{ "));

        for (i, (ref key, ref val)) in self.dict.iter().enumerate() {
            if i != 0 {
                try!(write!(fmt, ", "));
            }

            try!(write!(fmt, "{}: {}", key, val));
        }

        write!(fmt, " }}")
    }
}

pub type JsProto = Option<Box<JsObjStruct>>;

// TODO nice JS object creation macro
//macro_rules! js_obj {
//    ( $kt:ty : $ke:expr => $vt:ty : $ve:expr ),* {
//        {
//
//        }
//    };
//}

#[cfg(test)]
mod tests {
    // TODO tests for objs
}
<commit_msg>Add debugging for objects temporarily<commit_after>use std::collections::hash_map::HashMap;
use std::collections::hash_set::HashSet;
use std::fmt::{Display, Formatter, Error};
use std::string::String;
use std::vec::Vec;

use super::allocator::Allocator;
use super::binding::UniqueBinding;
use super::js_var::{JsVar, JsKey, JsType, JsPtrEnum};

#[derive(Clone, Debug)]
pub struct JsObjStruct {
    pub proto: JsProto,
    pub name: String,
    pub dict: HashMap<JsKey, JsVar>,
}

impl JsObjStruct {
    #[allow(unused_variables)]
    pub fn new<T: Allocator>(proto: JsProto, name: &str,
                             kv_tuples: Vec<(JsKey, JsVar, Option<JsPtrEnum>)>,
                             allocator: &mut T) -> JsObjStruct {
        JsObjStruct {
            proto: None,
            name: String::from(name),
            dict: kv_tuples.into_iter().map(|(k, v, ptr)| {
                if let Some(ptr) = ptr {
                    allocator.alloc(v.unique.clone(), ptr).expect("Unable to allocate!"); // TODO better error handling
                }
                (k, v)
            }).collect()
        }
    }

    pub fn add_key<T: Allocator>(&mut self, k: JsKey, v: JsVar, ptr: Option<JsPtrEnum>, allocator: &mut T) {
        // If the key already exists, potentially condemn its pointer, which is being overwritten.
        if let Some(var) = self.dict.get(&k) {
            println!("VAR");
            match var.t {
                JsType::JsPtr(_) => { println!("CONDEMN"); allocator.condemn(var.unique.clone()).expect("Unable to whiten!") },
                _ => {}
            }
        }
        // Then, allocate the new pointer if necessary...
        if let Some(ptr) = ptr {
            println!("POINTER");
            allocator.alloc(v.unique.clone(), ptr).expect("Unable to allocate!"); // TODO better error handling
        }
        // ...and insert the key & value into the dictionary blindly.
        self.dict.insert(k, v);
        println!("DONE");
    }

    pub fn get_children(&self) -> HashSet<UniqueBinding> {
        let mut bindings = HashSet::new();
        for v in self.dict.values() {
            match v.t {
                JsType::JsPtr(_) => { bindings.insert(v.unique.clone()); },
                _ => (),
            }
        }
        bindings
    }
}

impl Display for JsObjStruct {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        try!(write!(fmt, "{{ "));

        for (i, (ref key, ref val)) in self.dict.iter().enumerate() {
            if i != 0 {
                try!(write!(fmt, ", "));
            }

            try!(write!(fmt, "{}: {}", key, val));
        }

        write!(fmt, " }}")
    }
}

pub type JsProto = Option<Box<JsObjStruct>>;

// TODO nice JS object creation macro
//macro_rules! js_obj {
//    ( $kt:ty : $ke:expr => $vt:ty : $ve:expr ),* {
//        {
//
//        }
//    };
//}

<|endoftext|>