<commit_before>// Copyright (c) Björn Edström <be@bjrn.se> 2015.
// See LICENSE for details.

extern crate chrono;
extern crate crypto;
extern crate getopts;
extern crate num;
extern crate rustc_serialize;

mod timmy;

use chrono::datetime::DateTime;
use chrono::offset::utc::UTC;
use crypto::digest::Digest;
use crypto::sha2::Sha256;
use getopts::Options;
use num::bigint::BigUint;
use rustc_serialize::base64::{STANDARD, ToBase64, FromBase64};
use rustc_serialize::json::{self, Json, ToJson};
use std::collections::BTreeMap;
use std::env;
use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::io;
use std::net::TcpStream;

use timmy::rsa::*;
use timmy::util::*;
use timmy::tls::*;
use timmy::x509::*;

macro_rules! println_stderr(
    ($($arg:tt)*) => (
        match writeln!(&mut ::std::io::stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        }
    )
);

#[derive(RustcDecodable, RustcEncodable, Debug)]
struct JsonOutput {
    blob: String,
    certificates: Vec<String>,
    signature: String
}

fn verify(blob: &Vec<u8>, cert0: &Vec<u8>, signature: &Vec<u8>) {

    let cert = X509Certificate::new(cert0.clone());

    let parsed = cert.parse().unwrap(); // XXX unwrap

    let utc_now: DateTime<UTC> = UTC::now();

    let cert_still_valid = utc_now >= parsed.validity.0 && utc_now <= parsed.validity.1;

    if !cert_still_valid {
        println_stderr!("ERROR! Signature verification FAILURE: Certificate has expired.");
        return;
    }

    //println!("{:?}", parsed);

    match parsed.key {
        PublicKey::RSA(rsa_n, rsa_e) => {

            let signature_int = BigUint::from_bytes_be(&signature);
            let sig_op = rsa_encrypt(&signature_int, &rsa_e,  &rsa_n);

            // Account for missing leading 0x00
            let mut raw_pkcs1_ = sig_op.to_bytes_be();
            raw_pkcs1_.insert(0, 0x00);
            let raw_pkcs1 = raw_pkcs1_;

            //println!("{}", estimate_bit_size(&rsa_n));

            // the hash here in the PKCS1 structure is MD5(blob) || SHA1(blob)
            // recall that the first part of blob is the SHA-256 hash
            //println!("{:?}", to_hex_string(&raw_pkcs1));

            // construct our own signature to compare against
            let tls_hash = weird_tls_hash(&blob);
            let constructed_pkcs1 = make_pkcs1_sig_padding(&rsa_n, &tls_hash);

            //println!("{:?}", to_hex_string(&tls_hash));
            //println!("{:?}", to_hex_string(&constructed_pkcs1));

            let valid_signature = crypto_compare(&constructed_pkcs1, &raw_pkcs1);
            //println!("{:?}", valid_signature);

            if valid_signature {
                let mut tls = TLSHandshake::new();
                tls.client_random = blob[0..32].iter().cloned().collect();
                tls.server_random = blob[32..64].iter().cloned().collect();
                let unix_timestamp = tls.get_unix_timestamp();
                let ts = timestamp_to_datetime(unix_timestamp);

                let valid_dates = ts >= parsed.validity.0 && ts <= parsed.validity.1;

                if valid_dates {
                    println!("Signature verification SUCCESS.");
                    println!("Warning! Signature only verified against first X509 certificate.");
                    println!("Please verify yourself that the certificate chain is valid.");
                    println!("");
                    println!("{} Signed SHA-256 {} at {:?} (Unix Timestamp: {})",
                             parsed.subject,
                             to_hex_string(&tls.client_random), ts, unix_timestamp);
                } else {
                    println!("ERROR! Signature verification FAILURE: Invalid timestamp.");
                }

            } else {
                println!("ERROR! Signature verification FAILURE.");
            }
        }
    }

}

fn perform(server: &String, port: &u16, hash_buf: &[u8; 32]) {
    let conn_str = format!("{}:{}", server, port);

    //println!("conn_str {}", conn_str);

    let mut tcpconn = TcpStream::connect(&conn_str[..]).unwrap();

    // Construct our special ClientHello message
    let mut ch = SimpleBinaryWriter::new();
    create_special_client_hello(&mut ch, &hash_buf);

    match tcpconn.write(&ch.buf) {
        Err(_) => {
            panic!("write failure!!!");
        }
        Ok(_) => {}
    }

    let mut pars = BinaryParser::new(&mut tcpconn);
    let mut tls = TLSHandshake::new();

    // HACK
    tls.client_random.extend(hash_buf[0..32].iter());

    // Parse ServerHello
    tls.parse_server_hello(&mut pars);

    // Parse Certificates
    tls.parse_certificates(&mut pars);

    // Parse ServerKeyExchange
    tls.parse_server_key_exchange(&mut pars);

    // Output
    //for cert in &tls.certs {
    //    println!("cert {}", to_hex_string(cert.buf.clone()));
    //}

    let unix_timestamp = tls.get_unix_timestamp();
    let ts = timestamp_to_datetime(unix_timestamp);

    let utc_now: DateTime<UTC> = UTC::now();
    let utc_now_ts = utc_now.timestamp() as u32;

    //println!("{} {}", utc_now_ts, unix_timestamp);

    if unix_timestamp < utc_now_ts - 3600 || unix_timestamp > utc_now_ts + 3600 {
        println_stderr!("ERROR! Server responded with invalid time! Aborting.");
        return;
    }

    println_stderr!("{} signed SHA-256 {} at {:?} (Unix Timestamp: {})",
                    server, to_hex_string(&hash_buf[0..32].iter().cloned().collect()), ts, unix_timestamp);

    //println!("Blob: {}", to_hex_string(tls.signed_blob.clone()));
    //println!("Signature: {}", to_hex_string(tls.signature.clone()));

    let mut obj = BTreeMap::new();
    obj.insert("blob".to_string(), ((&*tls.signed_blob).to_base64(STANDARD)).to_json());
    obj.insert("signature".to_string(), ((&*tls.signature).to_base64(STANDARD)).to_json());

    let mut cert_vec = Vec::new();
    for cert in &tls.certs {
        cert_vec.push(cert.buf.to_base64(STANDARD));
    }
    obj.insert("certificates".to_string(), cert_vec.to_json());

    println!("{}", json::encode(&Json::Object(obj)).ok().expect("json"));

    /*
    {
        let mut f = File::create("data.blob").ok().expect("fail.");
        f.write_all(&*tls.signed_blob);
    }

    {
        let mut f = File::create("data.signature").ok().expect("fail.");
        f.write_all(&*tls.signature);
    }

    {
        let mut f = File::create("data.certificate.der").ok().expect("fail.");
        f.write_all(&*tls.certs[0].buf);
    }
    */

    /*
    let mut derparser = DerParser::new(&tls.certs[0].buf);

    let asn1tree = derparser.parse_entry();
    parse_x509(asn1tree.expect("..."));
     */

}

fn hash_content<R: Read, D: Digest>(file_handle: &mut R, hasher: &mut D) {
    let mut buf: [u8; 4096] = [0; 4096];

    loop {
        match file_handle.read(&mut buf) {
            Ok(0) => { break }
            Ok(size) => {
                hasher.input(&mut buf[0..size]);
            }
            // Makes sense?
            Err(_) => { break }
        };
    }
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();
    let mut opts = Options::new();

    opts.optopt("v", "verify", "verify signature object", "PATH");
    opts.optopt("f", "file", "input file to sign [-]", "PATH");
    opts.optopt("s", "server", "set server for signing [www.google.com]", "HOSTNAME");
    opts.optopt("p", "port", "set port for --server [443]", "PORT");
    //opts.optopt("o", "output", "ouput file [data]", "PATH");

    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") {
        print_usage(&program, opts);
        return;
    }

    // parse "output"
    /*let output = if matches.opt_present("o") {
        matches.opt_str("o").unwrap()
    } else {
        "data".to_string()
    };*/

    // parse "server"
    let server = if matches.opt_present("s") {
        matches.opt_str("s").unwrap()
    } else {
        "www.google.com".to_string()
    };

    // parse "port"
    let port: u16 = if matches.opt_present("p") {
        let port_str = matches.opt_str("p").unwrap();
        match port_str.parse() {
            Ok(p) => p,
            Err(_) => {
                print_usage(&program, opts);
                return;
            }
        }
    } else {
        443
    };

    if !matches.opt_present("v") {
        // sign

        // parse "file" and hash it
        let mut hasher = Sha256::new();

        if matches.opt_present("f") {
            let path = matches.opt_str("f").unwrap();
            let mut file_handle = match File::open(path) {
                Ok(f) => f,
                Err(s) => {
                    println!("Reading file failed: {}", s);
                    //print_usage(&program, opts);
                    return;
                }
            };

            hash_content(&mut file_handle, &mut hasher);
        } else {
            hash_content(&mut io::stdin(), &mut hasher);
        };

        //println!("Hello, world! {} {} {:?}", server, port, hasher.result_str());

        let mut hash_buf: [u8; 32] = [0; 32];
        hasher.result(&mut hash_buf);

        perform(&server, &port, &hash_buf);
    } else {
        // verify

        let path = matches.opt_str("v").unwrap();
        let mut contents: Vec<u8> = Vec::new();
        let file_handle = File::open(path) ;
        file_handle.unwrap().read_to_end(&mut contents).unwrap();

        let filestr = String::from_utf8(contents).unwrap();

        let json_blob: JsonOutput = json::decode(&filestr).unwrap();

        //println!("{:?}", json_blob);

        let blob = json_blob.blob.from_base64().unwrap();
        let cert0 = json_blob.certificates[0].from_base64().unwrap();
        let signature = json_blob.signature.from_base64().unwrap();

        verify(&blob, &cert0, &signature);
    }
}
<commit_msg>Simplify JSON serialization.<commit_after>// Copyright (c) Björn Edström <be@bjrn.se> 2015.
// See LICENSE for details.

extern crate chrono;
extern crate crypto;
extern crate getopts;
extern crate num;
extern crate rustc_serialize;

mod timmy;

use chrono::datetime::DateTime;
use chrono::offset::utc::UTC;
use crypto::digest::Digest;
use crypto::sha2::Sha256;
use getopts::Options;
use num::bigint::BigUint;
use rustc_serialize::base64::{STANDARD, ToBase64, FromBase64};
use rustc_serialize::json::{self};
use std::env;
use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::io;
use std::net::TcpStream;

use timmy::rsa::*;
use timmy::util::*;
use timmy::tls::*;
use timmy::x509::*;

macro_rules! println_stderr(
    ($($arg:tt)*) => (
        match writeln!(&mut ::std::io::stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        }
    )
);

#[derive(RustcDecodable, RustcEncodable, Debug)]
struct JsonOutput {
    blob: String,
    certificates: Vec<String>,
    signature: String
}

fn verify(blob: &Vec<u8>, cert0: &Vec<u8>, signature: &Vec<u8>) {

    let cert = X509Certificate::new(cert0.clone());

    let parsed = cert.parse().unwrap(); // XXX unwrap

    let utc_now: DateTime<UTC> = UTC::now();

    let cert_still_valid = utc_now >= parsed.validity.0 && utc_now <= parsed.validity.1;

    if !cert_still_valid {
        println_stderr!("ERROR! Signature verification FAILURE: Certificate has expired.");
        return;
    }

    //println!("{:?}", parsed);

    match parsed.key {
        PublicKey::RSA(rsa_n, rsa_e) => {

            let signature_int = BigUint::from_bytes_be(&signature);
            let sig_op = rsa_encrypt(&signature_int, &rsa_e,  &rsa_n);

            // Account for missing leading 0x00
            let mut raw_pkcs1_ = sig_op.to_bytes_be();
            raw_pkcs1_.insert(0, 0x00);
            let raw_pkcs1 = raw_pkcs1_;

            //println!("{}", estimate_bit_size(&rsa_n));

            // the hash here in the PKCS1 structure is MD5(blob) || SHA1(blob)
            // recall that the first part of blob is the SHA-256 hash
            //println!("{:?}", to_hex_string(&raw_pkcs1));

            // construct our own signature to compare against
            let tls_hash = weird_tls_hash(&blob);
            let constructed_pkcs1 = make_pkcs1_sig_padding(&rsa_n, &tls_hash);

            //println!("{:?}", to_hex_string(&tls_hash));
            //println!("{:?}", to_hex_string(&constructed_pkcs1));

            let valid_signature = crypto_compare(&constructed_pkcs1, &raw_pkcs1);
            //println!("{:?}", valid_signature);

            if valid_signature {
                let mut tls = TLSHandshake::new();
                tls.client_random = blob[0..32].iter().cloned().collect();
                tls.server_random = blob[32..64].iter().cloned().collect();
                let unix_timestamp = tls.get_unix_timestamp();
                let ts = timestamp_to_datetime(unix_timestamp);

                let valid_dates = ts >= parsed.validity.0 && ts <= parsed.validity.1;

                if valid_dates {
                    println!("Signature verification SUCCESS.");
                    println!("Warning! Signature only verified against first X509 certificate.");
                    println!("Please verify yourself that the certificate chain is valid.");
                    println!("");
                    println!("{} Signed SHA-256 {} at {:?} (Unix Timestamp: {})",
                             parsed.subject,
                             to_hex_string(&tls.client_random), ts, unix_timestamp);
                } else {
                    println!("ERROR! Signature verification FAILURE: Invalid timestamp.");
                }

            } else {
                println!("ERROR! Signature verification FAILURE.");
            }
        }
    }

}

fn perform(server: &String, port: &u16, hash_buf: &[u8; 32]) {
    let conn_str = format!("{}:{}", server, port);

    //println!("conn_str {}", conn_str);

    let mut tcpconn = TcpStream::connect(&conn_str[..]).unwrap();

    // Construct our special ClientHello message
    let mut ch = SimpleBinaryWriter::new();
    create_special_client_hello(&mut ch, &hash_buf);

    match tcpconn.write(&ch.buf) {
        Err(_) => {
            panic!("write failure!!!");
        }
        Ok(_) => {}
    }

    let mut pars = BinaryParser::new(&mut tcpconn);
    let mut tls = TLSHandshake::new();

    // HACK
    tls.client_random.extend(hash_buf[0..32].iter());

    // Parse ServerHello
    tls.parse_server_hello(&mut pars);

    // Parse Certificates
    tls.parse_certificates(&mut pars);

    // Parse ServerKeyExchange
    tls.parse_server_key_exchange(&mut pars);

    // Output
    //for cert in &tls.certs {
    //    println!("cert {}", to_hex_string(cert.buf.clone()));
    //}

    let unix_timestamp = tls.get_unix_timestamp();
    let ts = timestamp_to_datetime(unix_timestamp);

    let utc_now: DateTime<UTC> = UTC::now();
    let utc_now_ts = utc_now.timestamp() as u32;

    //println!("{} {}", utc_now_ts, unix_timestamp);

    if unix_timestamp < utc_now_ts - 3600 || unix_timestamp > utc_now_ts + 3600 {
        println_stderr!("ERROR! Server responded with invalid time! Aborting.");
        return;
    }

    println_stderr!("{} signed SHA-256 {} at {:?} (Unix Timestamp: {})",
                    server, to_hex_string(&hash_buf[0..32].iter().cloned().collect()), ts, unix_timestamp);

    //println!("Blob: {}", to_hex_string(tls.signed_blob.clone()));
    //println!("Signature: {}", to_hex_string(tls.signature.clone()));

    let json_output = JsonOutput {
        blob: tls.signed_blob.to_base64(STANDARD),
        signature: tls.signature.to_base64(STANDARD),
        certificates: tls.certs.iter().map(
            |c| c.buf.to_base64(STANDARD)
            ).collect(),
    };

    println!("{}", json::encode(&json_output).unwrap());
}

fn hash_content<R: Read, D: Digest>(file_handle: &mut R, hasher: &mut D) {
    let mut buf: [u8; 4096] = [0; 4096];

    loop {
        match file_handle.read(&mut buf) {
            Ok(0) => { break }
            Ok(size) => {
                hasher.input(&mut buf[0..size]);
            }
            // Makes sense?
            Err(_) => { break }
        };
    }
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();
    let mut opts = Options::new();

    opts.optopt("v", "verify", "verify signature object", "PATH");
    opts.optopt("f", "file", "input file to sign [-]", "PATH");
    opts.optopt("s", "server", "set server for signing [www.google.com]", "HOSTNAME");
    opts.optopt("p", "port", "set port for --server [443]", "PORT");
    //opts.optopt("o", "output", "ouput file [data]", "PATH");

    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") {
        print_usage(&program, opts);
        return;
    }

    // parse "output"
    /*let output = if matches.opt_present("o") {
        matches.opt_str("o").unwrap()
    } else {
        "data".to_string()
    };*/

    // parse "server"
    let server = if matches.opt_present("s") {
        matches.opt_str("s").unwrap()
    } else {
        "www.google.com".to_string()
    };

    // parse "port"
    let port: u16 = if matches.opt_present("p") {
        let port_str = matches.opt_str("p").unwrap();
        match port_str.parse() {
            Ok(p) => p,
            Err(_) => {
                print_usage(&program, opts);
                return;
            }
        }
    } else {
        443
    };

    if !matches.opt_present("v") {
        // sign

        // parse "file" and hash it
        let mut hasher = Sha256::new();

        if matches.opt_present("f") {
            let path = matches.opt_str("f").unwrap();
            let mut file_handle = match File::open(path) {
                Ok(f) => f,
                Err(s) => {
                    println!("Reading file failed: {}", s);
                    //print_usage(&program, opts);
                    return;
                }
            };

            hash_content(&mut file_handle, &mut hasher);
        } else {
            hash_content(&mut io::stdin(), &mut hasher);
        };

        //println!("Hello, world! {} {} {:?}", server, port, hasher.result_str());

        let mut hash_buf: [u8; 32] = [0; 32];
        hasher.result(&mut hash_buf);

        perform(&server, &port, &hash_buf);
    } else {
        // verify

        let path = matches.opt_str("v").unwrap();
        let mut contents: Vec<u8> = Vec::new();
        let file_handle = File::open(path) ;
        file_handle.unwrap().read_to_end(&mut contents).unwrap();

        let filestr = String::from_utf8(contents).unwrap();

        let json_blob: JsonOutput = json::decode(&filestr).unwrap();

        //println!("{:?}", json_blob);

        let blob = json_blob.blob.from_base64().unwrap();
        let cert0 = json_blob.certificates[0].from_base64().unwrap();
        let signature = json_blob.signature.from_base64().unwrap();

        verify(&blob, &cert0, &signature);
    }
}
<|endoftext|>


<commit_before>#![allow(non_upper_case_globals)]
//#![allow(dead_code)]

#[macro_use] extern crate lazy_static;

use std::ffi::OsStr;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::{ Path, PathBuf };

lazy_static! {
    static ref HOME: PathBuf = std::env::home_dir().unwrap();

    static ref build_props: PathBuf = PathBuf::from("project/build.properties");

    static ref sbt_launch_dir: PathBuf = { let mut p = PathBuf::from(&*HOME); p.push(".sbt/launchers"); p };
}

const sbt_launch_ivy_release_repo: &'static str = "http://repo.typesafe.com/typesafe/ivy-releases";
const sbt_launch_mvn_release_repo: &'static str = "http://repo.scala-sbt.org/scalasbt/maven-releases";

macro_rules! echoerr(($($arg:tt)*) => (writeln!(&mut ::std::io::stderr(), $($arg)*).unwrap();));

fn build_props_sbt() -> String {
    if let Ok(f) = File::open(&*build_props) {
        let f = BufReader::new(f);
        for line in f.lines() {
            let line = line.unwrap();
            if line.starts_with("sbt.version") {
                let line = line.replace("=", " ");
                let line = line.replace("\r", " ");
                return line.split_whitespace().nth(1).unwrap().to_owned();
            }
        }
    }
    "".to_owned()
}

fn jar_file(version: &str) -> PathBuf {
    let mut p = PathBuf::from(&*sbt_launch_dir);
    p.push(version);
    p.push("sbt-launch.jar");
    p
}

fn url_base(version: &str) -> &'static str { match version {
    s if s.starts_with("0.7.")  => "http://simple-build-tool.googlecode.com",
    s if s.starts_with("0.10.") => sbt_launch_ivy_release_repo,
    "0.11.1" | "0.11.2"         => sbt_launch_ivy_release_repo,
 // "0.*-yyyymmdd-hhMMss"       => sbt_launch_ivy_snapshot_repo, // https://repo.scala-sbt.org/scalasbt/ivy-snapshots
    s if s.starts_with("0.")    => sbt_launch_ivy_release_repo,
 // "*-yyyymmdd-hhMMss"         => sbt_launch_mvn_snapshot_repo, // http://repo.scala-sbt.org/scalasbt/maven-snapshots
    _                           => sbt_launch_mvn_release_repo,
} }

fn make_url(version: &str) -> String {
    let base = url_base(version);
    match version {
        s if s.starts_with("0.7.")  => format!("{}/files/sbt-launch-0.7.7.jar", base),
        s if s.starts_with("0.10.") => format!("{}/org.scala-tools.sbt/sbt-launch/{}/sbt-launch.jar", base, version),
        "0.11.1" | "0.11.2"         => format!("{}/org.scala-tools.sbt/sbt-launch/{}/sbt-launch.jar", base, version),
        s if s.starts_with("0.")    => format!("{}/org.scala-sbt/sbt-launch/{}/sbt-launch.jar", base, version),
        _                           => format!("{}/org/scala-sbt/sbt-launch/{}/sbt-launch.jar", base, version),
    }
}

fn download_url(sbt_version: &str, url: &str, jar: &Path) {
    echoerr!("Downloading sbt launcher for {}:", sbt_version);
    echoerr!("  From  {}", url);
    echoerr!("    To  {}", jar.display());

    std::fs::create_dir_all(jar.parent().unwrap()).unwrap();

    extern crate hyper;
    let mut r = BufReader::new(hyper::client::Client::new().get(url).send().unwrap());
    let mut buf = [0; 16384];
    let mut jar = std::io::BufWriter::new(File::create(jar).unwrap());
    while {
        let bc = r.read(&mut buf).unwrap();
        jar.write(&buf[0..bc]).unwrap();
        bc > 0
    } {}
    jar.flush().unwrap();
}

fn exec_runner<S: AsRef<OsStr>>(args: &[S]) {
    use std::os::unix::process::CommandExt;
    let err = std::process::Command::new(&args[0]).args(&args[1..]).exec();
    println!("error: {}", err);
    if let Some(err) = err.raw_os_error() {
        std::process::exit(err);
    }
    std::process::exit(-1)
}

fn main() {
    let sbt_version = build_props_sbt();
    let mut sbt_jar = jar_file(&sbt_version);
    if !sbt_jar.exists() {
        sbt_jar = PathBuf::from(&*HOME);
        sbt_jar.push(format!(".ivy2/local/org.scala-sbt/sbt-launch/{}/jars/sbt-launch.jar", sbt_version));
    }
    if !sbt_jar.exists() {
        sbt_jar = jar_file(&sbt_version);
        download_url(&sbt_version, &make_url(&sbt_version), &sbt_jar);
    }
    let sbt_jar = sbt_jar.as_path();

    let java_cmd = "java";
    let extra_jvm_opts = ["-Xms512m", "-Xmx1536m", "-Xss2m"];
    let java_args: [&str; 0] = [];
    let sbt_commands: [&str; 0] = [];
    let residual_args = ["shell"];

    let mut exec_args: Vec<&OsStr> = Vec::new();
    exec_args.push(java_cmd.as_ref());
    exec_args.extend_from_slice(&extra_jvm_opts.iter().map(|x| x.as_ref()).collect::<Vec<_>>());
    exec_args.extend_from_slice(&java_args.iter().map(|x| x.as_ref()).collect::<Vec<_>>());
    exec_args.extend_from_slice(&["-jar".as_ref(), sbt_jar.as_ref()]);
    exec_args.extend_from_slice(&sbt_commands.iter().map(|x| x.as_ref()).collect::<Vec<_>>());
    exec_args.extend_from_slice(&residual_args.iter().map(|x| x.as_ref()).collect::<Vec<_>>());
    let exec_args = &exec_args;

    exec_runner(exec_args)
}
<commit_msg>Start implementing -v<commit_after>#![allow(non_upper_case_globals)]

#![allow(dead_code)]
#![allow(unused_assignments)]
#![allow(unused_variables)]

#[macro_use] extern crate lazy_static;

use std::ffi::OsStr;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::{ Path, PathBuf };

lazy_static! {
    static ref HOME: PathBuf = std::env::home_dir().unwrap();

    static ref build_props: PathBuf = PathBuf::from("project/build.properties");

    static ref sbt_launch_dir: PathBuf = { let mut p = PathBuf::from(&*HOME); p.push(".sbt/launchers"); p };
}

const sbt_launch_ivy_release_repo: &'static str = "http://repo.typesafe.com/typesafe/ivy-releases";
const sbt_launch_mvn_release_repo: &'static str = "http://repo.scala-sbt.org/scalasbt/maven-releases";

macro_rules! echoerr(($($arg:tt)*) => (writeln!(&mut ::std::io::stderr(), $($arg)*).unwrap();));

fn build_props_sbt() -> String {
    if let Ok(f) = File::open(&*build_props) {
        let f = BufReader::new(f);
        for line in f.lines() {
            let line = line.unwrap();
            if line.starts_with("sbt.version") {
                let line = line.replace("=", " ");
                let line = line.replace("\r", " ");
                return line.split_whitespace().nth(1).unwrap().to_owned();
            }
        }
    }
    "".to_owned()
}

fn jar_file(version: &str) -> PathBuf {
    let mut p = PathBuf::from(&*sbt_launch_dir);
    p.push(version);
    p.push("sbt-launch.jar");
    p
}

fn url_base(version: &str) -> &'static str { match version {
    s if s.starts_with("0.7.")  => "http://simple-build-tool.googlecode.com",
    s if s.starts_with("0.10.") => sbt_launch_ivy_release_repo,
    "0.11.1" | "0.11.2"         => sbt_launch_ivy_release_repo,
 // "0.*-yyyymmdd-hhMMss"       => sbt_launch_ivy_snapshot_repo, // https://repo.scala-sbt.org/scalasbt/ivy-snapshots
    s if s.starts_with("0.")    => sbt_launch_ivy_release_repo,
 // "*-yyyymmdd-hhMMss"         => sbt_launch_mvn_snapshot_repo, // http://repo.scala-sbt.org/scalasbt/maven-snapshots
    _                           => sbt_launch_mvn_release_repo,
} }

fn make_url(version: &str) -> String {
    let base = url_base(version);
    match version {
        s if s.starts_with("0.7.")  => format!("{}/files/sbt-launch-0.7.7.jar", base),
        s if s.starts_with("0.10.") => format!("{}/org.scala-tools.sbt/sbt-launch/{}/sbt-launch.jar", base, version),
        "0.11.1" | "0.11.2"         => format!("{}/org.scala-tools.sbt/sbt-launch/{}/sbt-launch.jar", base, version),
        s if s.starts_with("0.")    => format!("{}/org.scala-sbt/sbt-launch/{}/sbt-launch.jar", base, version),
        _                           => format!("{}/org/scala-sbt/sbt-launch/{}/sbt-launch.jar", base, version),
    }
}

fn download_url(sbt_version: &str, url: &str, jar: &Path) {
    echoerr!("Downloading sbt launcher for {}:", sbt_version);
    echoerr!("  From  {}", url);
    echoerr!("    To  {}", jar.display());

    std::fs::create_dir_all(jar.parent().unwrap()).unwrap();

    extern crate hyper;
    let mut r = BufReader::new(hyper::client::Client::new().get(url).send().unwrap());
    let mut buf = [0; 16384];
    let mut jar = std::io::BufWriter::new(File::create(jar).unwrap());
    while {
        let bc = r.read(&mut buf).unwrap();
        jar.write(&buf[0..bc]).unwrap();
        bc > 0
    } {}
    jar.flush().unwrap();
}

fn exec_runner<S: AsRef<OsStr>>(args: &[S]) {
    use std::os::unix::process::CommandExt;
    let err = std::process::Command::new(&args[0]).args(&args[1..]).exec();
    println!("error: {}", err);
    if let Some(err) = err.raw_os_error() {
        std::process::exit(err);
    }
    std::process::exit(-1)
}

fn main() {
    // declare -r script_path="$(get_script_path "$BASH_SOURCE")"
    // declare -r script_name="${script_path##*/}"
    let script_name = "sbtl";

    let mut verbose = false;

    fn vlog(s: &str) { /* if verbose { echoerr!("{}", s); } */ }

    let java_cmd = "java";
    let extra_jvm_opts = ["-Xms512m", "-Xmx1536m", "-Xss2m"];
    let java_args: [&str; 0] = [];
    let sbt_commands: [&str; 0] = [];
    let mut residual_args: Vec<&OsStr> = Vec::new();

    // addResidual() { vlog "[residual] arg = '$1'"  ; residual_args+=("$1"); }
    fn add_residual(s: &str) { vlog(&format!("[residual] arg = {}", s)); /* residual_args.push(s); */ }

    for arg in std::env::args() {
        match arg.as_ref() {
            "-v" => verbose = true,
            s    => add_residual(s),
        }
    }

    let argument_count = std::env::args().len();
    if argument_count > 0 {
        vlog(&format!("Starting {}: invoke with -help for other options", script_name));
        residual_args = vec!["shell".as_ref()];
    }

    let sbt_version = build_props_sbt();
    let mut sbt_jar = jar_file(&sbt_version);
    if !sbt_jar.exists() {
        sbt_jar = PathBuf::from(&*HOME);
        sbt_jar.push(format!(".ivy2/local/org.scala-sbt/sbt-launch/{}/jars/sbt-launch.jar", sbt_version));
    }
    if !sbt_jar.exists() {
        sbt_jar = jar_file(&sbt_version);
        download_url(&sbt_version, &make_url(&sbt_version), &sbt_jar);
    }
    let sbt_jar = sbt_jar.as_path();

    let mut exec_args: Vec<&OsStr> = Vec::new();
    exec_args.push(java_cmd.as_ref());
    exec_args.append(&mut extra_jvm_opts.iter().map(AsRef::as_ref).collect());
    exec_args.append(&mut java_args.iter().map(AsRef::as_ref).collect());
    exec_args.append(&mut vec!["-jar".as_ref(), sbt_jar.as_ref()]);
    exec_args.append(&mut sbt_commands.iter().map(AsRef::as_ref).collect());
    exec_args.append(&mut residual_args.iter().map(AsRef::as_ref).collect());

    exec_runner(&exec_args)
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate lazy_static;
extern crate regex;
extern crate rand;

pub mod basetypes;
pub mod chess_move;
pub mod position;
pub mod search;
pub mod uci;

use std::process::exit;
use std::sync::Arc;
use std::time::SystemTime;
use std::collections::VecDeque;
use basetypes::*;
use position::Position;
use uci::{UciEngine, UciEngineFactory, EngineReply, OptionName, OptionDescription};
use search::{TimeManagement, SearchStatus, MultipvSearch};
use search::tt::*;

// The version of the program.
const VERSION: &'static str = "0.1";

// The name of the program.
const NAME: &'static str = "Alcibiades";

// The author of the program.
const AUTHOR: &'static str = "Evgeni Pandurski";

// The starting position in Forsyth–Edwards notation (FEN).
const STARTING_POSITION: &'static str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QKqk - 0 1";

// Represents a condition for terminating the search.
enum PlayWhen {
    TimeManagement(TimeManagement), // Stop when `TimeManagement` says.
    MoveTime(u64), // Stop after the given number of milliseconds.
    Nodes(NodeCount), // Stop when the given number of nodes has been searched.
    Depth(u8), // Stop when the given search depth has been reached.
    Never, // An infinite search.
}

/// Implements `UciEngine` trait.
pub struct Engine {
    tt: Arc<TranspositionTable>,
    position: Position,
    current_depth: u8,
    current_value: Value,

    // `Engine` will hand over the real work to `MultipvSearch`.
    search: MultipvSearch,

    // Tells the engine when it must stop thinking and play the best
    // move it has found.
    play_when: PlayWhen,

    // Tells the engine if it will be allowed to ponder. This option
    // is needed because the engine might change its time management
    // algorithm when pondering is allowed.
    pondering_is_allowed: bool,

    // `true` if the engine is thinking in pondering mode.
    is_pondering: bool,

    // Marks the last time when a message was sent by the engine to
    // the GUI, or if no message has been sent yet -- the time when
    // the search stared.
    silent_since: SystemTime,

    // A queue for the messages send by the engine to the GUI.
    queue: VecDeque<EngineReply>,
}

impl Engine {
    /// Creates a new instance.
    ///
    /// `tt_size_mb` is the preferred size of the transposition
    /// table in Mbytes.
    pub fn new(tt_size_mb: usize) -> Engine {
        let mut tt = TranspositionTable::new();
        tt.resize(tt_size_mb);
        let tt = Arc::new(tt);

        Engine {
            tt: tt.clone(),
            position: Position::from_fen(STARTING_POSITION).ok().unwrap(),
            current_depth: 0,
            current_value: VALUE_UNKNOWN,
            search: MultipvSearch::new(tt),
            play_when: PlayWhen::Never,
            pondering_is_allowed: false,
            is_pondering: false,
            silent_since: SystemTime::now(),
            queue: VecDeque::new(),
        }
    }

    // A helper method. It it adds a progress report message to
    // `self.queue`.
    fn queue_progress_report(&mut self) {
        let SearchStatus { depth, searched_nodes, nps, .. } = *self.search.status();
        self.queue.push_back(EngineReply::Info(vec![
            ("depth".to_string(), format!("{}", depth)),
            ("nodes".to_string(), format!("{}", searched_nodes)),
            ("nps".to_string(), format!("{}", nps)),
        ]));
        self.silent_since = SystemTime::now();
    }

    // A helper method. It it adds a message containing the current PV
    // to `self.queue`.
    fn queue_pv(&mut self) {
        let SearchStatus { depth, value, bound, ref pv, searched_time, searched_nodes, nps, .. } =
            *self.search.status();
        let score_suffix = match bound {
            BOUND_EXACT => "",
            BOUND_UPPER => " upperbound",
            BOUND_LOWER => " lowerbound",
            _ => panic!("unexpected bound type"),
        };
        let mut pv_string = String::new();
        for m in pv {
            pv_string.push_str(&m.notation());
            pv_string.push(' ');
        }
        self.queue.push_back(EngineReply::Info(vec![
            ("depth".to_string(), format!("{}", depth)),
            ("score".to_string(), format!("cp {}{}", value, score_suffix)),
            ("time".to_string(), format!("{}", searched_time)),
            ("nodes".to_string(), format!("{}", searched_nodes)),
            ("nps".to_string(), format!("{}", nps)),
            ("pv".to_string(), pv_string),
        ]));
        self.silent_since = SystemTime::now();
    }

    // A helper method. It it adds a message containing the current
    // best move to `self.queue`.
    fn queue_best_move(&mut self) {
        let SearchStatus { ref pv, .. } = *self.search.status();
        self.queue.push_back(EngineReply::BestMove {
            best_move: pv.get(0).map_or("0000".to_string(), |m| m.notation()),
            ponder_move: pv.get(1).map(|m| m.notation()),
        });
        self.silent_since = SystemTime::now();
    }
}

impl UciEngine for Engine {
    fn set_option(&mut self, name: &str, value: &str) {
        match name {
            "Ponder" => {
                self.pondering_is_allowed = value == "true";
            }

            // An invalid option. Notice that we do not support
            // re-sizing of the transposition table once the engine
            // had started.
            _ => (),
        }
    }

    fn new_game(&mut self) {
        self.tt.clear();
    }

    fn position(&mut self, fen: &str, moves: &mut Iterator<Item = &str>) {
        if let Ok(p) = Position::from_history(fen, moves) {
            self.position = p;
        }
    }

    #[allow(unused_variables)]
    fn go(&mut self,
          searchmoves: Option<Vec<String>>,
          ponder: bool,
          wtime: Option<u64>,
          btime: Option<u64>,
          winc: Option<u64>,
          binc: Option<u64>,
          movestogo: Option<u64>,
          depth: Option<u64>,
          nodes: Option<u64>,
          mate: Option<u64>,
          movetime: Option<u64>,
          infinite: bool) {
        if self.search.status().done {
            // NOTE: We ignore the "mate" parameter.

            self.tt.new_search();
            self.current_depth = 0;
            self.current_value = VALUE_UNKNOWN;
            self.is_pondering = ponder;
            self.play_when = if infinite {
                PlayWhen::Never
            } else if movetime.is_some() {
                PlayWhen::MoveTime(movetime.unwrap())
            } else if nodes.is_some() {
                PlayWhen::Nodes(nodes.unwrap())
            } else if depth.is_some() {
                PlayWhen::Depth(depth.unwrap() as u8)
            } else {
                PlayWhen::TimeManagement(TimeManagement::new(self.position.board().to_move(),
                                                             self.pondering_is_allowed,
                                                             wtime,
                                                             btime,
                                                             winc,
                                                             binc,
                                                             movestogo))
            };
            self.silent_since = SystemTime::now();
            self.search.start(&self.position, searchmoves);
        }
    }

    fn ponder_hit(&mut self) {
        if self.search.status().done {
            self.queue_best_move();
        } else {
            self.is_pondering = false;
        }
    }

    fn stop(&mut self) {
        self.search.stop();
        self.queue_best_move();
    }

    fn get_reply(&mut self) -> Option<EngineReply> {
        if !self.search.status().done {
            let SearchStatus { done, depth, value, searched_nodes, searched_time, .. } =
                *self.search.update_status();

            // Send the PV when changed.
            if depth > 0 && (depth > self.current_depth || value != self.current_value) {
                self.current_depth = depth;
                self.current_value = value;
                self.queue_pv();
            }

            // Send periodic progress reports.
            if self.silent_since.elapsed().unwrap().as_secs() > 10 {
                self.queue_progress_report();
            }

            // Check if we must play now.
            if !self.is_pondering &&
               match self.play_when {
                PlayWhen::TimeManagement(ref tm) => done || tm.must_play(self.search.status()),
                PlayWhen::MoveTime(t) => done || searched_time >= t,
                PlayWhen::Nodes(n) => done || searched_nodes >= n,
                PlayWhen::Depth(d) => done || depth >= d,
                PlayWhen::Never => false,
            } {
                self.stop();
            }
        }

        self.queue.pop_front()
    }

    fn exit(&mut self) {
        self.search.exit();
    }
}

/// Implements `UciEngineFactory` trait.
pub struct EngineFactory;

impl UciEngineFactory<Engine> for EngineFactory {
    fn name(&self) -> String {
        format!("{} {}", NAME, VERSION)
    }

    fn author(&self) -> String {
        AUTHOR.to_string()
    }

    fn options(&self) -> Vec<(OptionName, OptionDescription)> {
        vec![
            // TODO: Calculate a sane limit for the hash size.
            ("Hash".to_string(), OptionDescription::Spin { min: 1, max: 2048, default: 16 }),
            ("Ponder".to_string(), OptionDescription::Check { default: false }),
        ]
    }

    fn create(&self, hash_size_mb: Option<usize>) -> Engine {
        Engine::new(hash_size_mb.unwrap_or(16))
    }
}

fn main() {
    if let Ok(mut uci_loop) = uci::Server::wait_for_hanshake(EngineFactory) {
        match uci_loop.serve() {
            Ok(_) => {
                exit(0);
            }
            Err(_) => {
                exit(1);
            }
        }
    }
    exit(2);
}
<commit_msg>search.stop() in go()<commit_after>#[macro_use]
extern crate lazy_static;
extern crate regex;
extern crate rand;

pub mod basetypes;
pub mod chess_move;
pub mod position;
pub mod search;
pub mod uci;

use std::process::exit;
use std::sync::Arc;
use std::time::SystemTime;
use std::collections::VecDeque;
use basetypes::*;
use position::Position;
use uci::{UciEngine, UciEngineFactory, EngineReply, OptionName, OptionDescription};
use search::{TimeManagement, SearchStatus, MultipvSearch};
use search::tt::*;

// The version of the program.
const VERSION: &'static str = "0.1";

// The name of the program.
const NAME: &'static str = "Alcibiades";

// The author of the program.
const AUTHOR: &'static str = "Evgeni Pandurski";

// The starting position in Forsyth–Edwards notation (FEN).
const STARTING_POSITION: &'static str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QKqk - 0 1";

// Represents a condition for terminating the search.
enum PlayWhen {
    TimeManagement(TimeManagement), // Stop when `TimeManagement` says.
    MoveTime(u64), // Stop after the given number of milliseconds.
    Nodes(NodeCount), // Stop when the given number of nodes has been searched.
    Depth(u8), // Stop when the given search depth has been reached.
    Never, // An infinite search.
}

/// Implements `UciEngine` trait.
pub struct Engine {
    tt: Arc<TranspositionTable>,
    position: Position,
    current_depth: u8,
    current_value: Value,

    // `Engine` will hand over the real work to `MultipvSearch`.
    search: MultipvSearch,

    // Tells the engine when it must stop thinking and play the best
    // move it has found.
    play_when: PlayWhen,

    // Tells the engine if it will be allowed to ponder. This option
    // is needed because the engine might change its time management
    // algorithm when pondering is allowed.
    pondering_is_allowed: bool,

    // `true` if the engine is thinking in pondering mode.
    is_pondering: bool,

    // Marks the last time when a message was sent by the engine to
    // the GUI, or if no message has been sent yet -- the time when
    // the search stared.
    silent_since: SystemTime,

    // A queue for the messages send by the engine to the GUI.
    queue: VecDeque<EngineReply>,
}

impl Engine {
    /// Creates a new instance.
    ///
    /// `tt_size_mb` is the preferred size of the transposition
    /// table in Mbytes.
    pub fn new(tt_size_mb: usize) -> Engine {
        let mut tt = TranspositionTable::new();
        tt.resize(tt_size_mb);
        let tt = Arc::new(tt);

        Engine {
            tt: tt.clone(),
            position: Position::from_fen(STARTING_POSITION).ok().unwrap(),
            current_depth: 0,
            current_value: VALUE_UNKNOWN,
            search: MultipvSearch::new(tt),
            play_when: PlayWhen::Never,
            pondering_is_allowed: false,
            is_pondering: false,
            silent_since: SystemTime::now(),
            queue: VecDeque::new(),
        }
    }

    // A helper method. It it adds a progress report message to
    // `self.queue`.
    fn queue_progress_report(&mut self) {
        let SearchStatus { depth, searched_nodes, nps, .. } = *self.search.status();
        self.queue.push_back(EngineReply::Info(vec![
            ("depth".to_string(), format!("{}", depth)),
            ("nodes".to_string(), format!("{}", searched_nodes)),
            ("nps".to_string(), format!("{}", nps)),
        ]));
        self.silent_since = SystemTime::now();
    }

    // A helper method. It it adds a message containing the current PV
    // to `self.queue`.
    fn queue_pv(&mut self) {
        let SearchStatus { depth, value, bound, ref pv, searched_time, searched_nodes, nps, .. } =
            *self.search.status();
        let score_suffix = match bound {
            BOUND_EXACT => "",
            BOUND_UPPER => " upperbound",
            BOUND_LOWER => " lowerbound",
            _ => panic!("unexpected bound type"),
        };
        let mut pv_string = String::new();
        for m in pv {
            pv_string.push_str(&m.notation());
            pv_string.push(' ');
        }
        self.queue.push_back(EngineReply::Info(vec![
            ("depth".to_string(), format!("{}", depth)),
            ("score".to_string(), format!("cp {}{}", value, score_suffix)),
            ("time".to_string(), format!("{}", searched_time)),
            ("nodes".to_string(), format!("{}", searched_nodes)),
            ("nps".to_string(), format!("{}", nps)),
            ("pv".to_string(), pv_string),
        ]));
        self.silent_since = SystemTime::now();
    }

    // A helper method. It it adds a message containing the current
    // best move to `self.queue`.
    fn queue_best_move(&mut self) {
        let SearchStatus { ref pv, .. } = *self.search.status();
        self.queue.push_back(EngineReply::BestMove {
            best_move: pv.get(0).map_or("0000".to_string(), |m| m.notation()),
            ponder_move: pv.get(1).map(|m| m.notation()),
        });
        self.silent_since = SystemTime::now();
    }
}

impl UciEngine for Engine {
    fn set_option(&mut self, name: &str, value: &str) {
        match name {
            "Ponder" => {
                self.pondering_is_allowed = value == "true";
            }

            // An invalid option. Notice that we do not support
            // re-sizing of the transposition table once the engine
            // had started.
            _ => (),
        }
    }

    fn new_game(&mut self) {
        self.tt.clear();
    }

    fn position(&mut self, fen: &str, moves: &mut Iterator<Item = &str>) {
        if let Ok(p) = Position::from_history(fen, moves) {
            self.position = p;
        }
    }

    #[allow(unused_variables)]
    fn go(&mut self,
          searchmoves: Option<Vec<String>>,
          ponder: bool,
          wtime: Option<u64>,
          btime: Option<u64>,
          winc: Option<u64>,
          binc: Option<u64>,
          movestogo: Option<u64>,
          depth: Option<u64>,
          nodes: Option<u64>,
          mate: Option<u64>,
          movetime: Option<u64>,
          infinite: bool) {
        // NOTE: We ignore the "mate" parameter.

        self.search.stop();
        self.tt.new_search();
        self.current_depth = 0;
        self.current_value = VALUE_UNKNOWN;
        self.is_pondering = ponder;
        self.play_when = if infinite {
            PlayWhen::Never
        } else if movetime.is_some() {
            PlayWhen::MoveTime(movetime.unwrap())
        } else if nodes.is_some() {
            PlayWhen::Nodes(nodes.unwrap())
        } else if depth.is_some() {
            PlayWhen::Depth(depth.unwrap() as u8)
        } else {
            PlayWhen::TimeManagement(TimeManagement::new(self.position.board().to_move(),
                                                         self.pondering_is_allowed,
                                                         wtime,
                                                         btime,
                                                         winc,
                                                         binc,
                                                         movestogo))
        };
        self.silent_since = SystemTime::now();
        self.search.start(&self.position, searchmoves);
    }

    fn ponder_hit(&mut self) {
        if self.search.status().done {
            self.queue_best_move();
        } else {
            self.is_pondering = false;
        }
    }

    fn stop(&mut self) {
        self.search.stop();
        self.queue_best_move();
    }

    fn get_reply(&mut self) -> Option<EngineReply> {
        if !self.search.status().done {
            let SearchStatus { done, depth, value, searched_nodes, searched_time, .. } =
                *self.search.update_status();

            // Send the PV when changed.
            if depth > 0 && (depth > self.current_depth || value != self.current_value) {
                self.current_depth = depth;
                self.current_value = value;
                self.queue_pv();
            }

            // Send periodic progress reports.
            if self.silent_since.elapsed().unwrap().as_secs() > 10 {
                self.queue_progress_report();
            }

            // Check if we must play now.
            if !self.is_pondering &&
               match self.play_when {
                PlayWhen::TimeManagement(ref tm) => done || tm.must_play(self.search.status()),
                PlayWhen::MoveTime(t) => done || searched_time >= t,
                PlayWhen::Nodes(n) => done || searched_nodes >= n,
                PlayWhen::Depth(d) => done || depth >= d,
                PlayWhen::Never => false,
            } {
                self.stop();
            }
        }

        self.queue.pop_front()
    }

    fn exit(&mut self) {
        self.search.exit();
    }
}

/// Implements `UciEngineFactory` trait.
pub struct EngineFactory;

impl UciEngineFactory<Engine> for EngineFactory {
    fn name(&self) -> String {
        format!("{} {}", NAME, VERSION)
    }

    fn author(&self) -> String {
        AUTHOR.to_string()
    }

    fn options(&self) -> Vec<(OptionName, OptionDescription)> {
        vec![
            // TODO: Calculate a sane limit for the hash size.
            ("Hash".to_string(), OptionDescription::Spin { min: 1, max: 2048, default: 16 }),
            ("Ponder".to_string(), OptionDescription::Check { default: false }),
        ]
    }

    fn create(&self, hash_size_mb: Option<usize>) -> Engine {
        Engine::new(hash_size_mb.unwrap_or(16))
    }
}

fn main() {
    if let Ok(mut uci_loop) = uci::Server::wait_for_hanshake(EngineFactory) {
        match uci_loop.serve() {
            Ok(_) => {
                exit(0);
            }
            Err(_) => {
                exit(1);
            }
        }
    }
    exit(2);
}
<|endoftext|>


<commit_before>extern crate core;
extern crate collections;
extern crate png;
extern crate getopts;

use core::mem;

use std::os;
use std::rand::{task_rng, Rng};

use collections::RingBuf;
use collections::String;

use getopts::{optopt, optflag, getopts, OptGroup, Matches, usage};

use image::{Image, Color, Point};
mod image;

struct Cell {
    color: Color,
    neighbors: Vec<uint>,
    pixels: Vec<Point>,
}

fn print_usage(program: &str, opts: &[OptGroup]) {
    let short_message = format!("Usage: {} [options] <input_file>", program);
    println!("{}", usage(short_message.as_slice(), opts));
}

fn get_uint_opt(matches: &Matches, opt_name: &str) -> Option<uint> {
    match matches.opt_str(opt_name) {
        Some(string) => match from_str(string.as_slice().trim()) {
            Some(value) => Some(value),
            None => panic!("Bad uint arg"),
        },
        None => None,
    }
}

fn main() {
    // Parse program arguments.
    let args: Vec<String> = os::args();
    let program = args[0].clone();
    let opts = [
        optopt("", "smin", "minimum neighbors for existing cell to survive", "UINT"),
        optopt("", "smax", "maximum neighbors for existing cell to survive", "UINT"),
        optopt("", "rmin", "minimum neighbors for new cell to be born", "UINT"),
        optopt("", "rmax", "maximum neighbors for new cell to be born", "UINT"),
        optopt("f", "frames", "number of frames to render", "UINT"),
        optflag("w", "wrap", "treat image space as toroidal"),
        optflag("p", "proportional", "weight neighbors by how many neighbors they have"),
        optopt("o", "output-prefix", "prefix for output frame files", "STRING"),
        optflag("h", "help", "print usage information"),
    ];
    let matches = match getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };
    if matches.opt_present("h") {
        print_usage(program.as_slice(), opts);
        return;
    }
    let input = if matches.free.len() == 1 {
        matches.free[0].clone()
    } else {
        print_usage(program.as_slice(), opts);
        return;
    };
    let output_prefix = matches.opt_str("output-prefix").unwrap_or(String::from_str("frame_"));

    let frames = get_uint_opt(&matches, "frames").unwrap_or(100);
    let wrap = matches.opt_present("w");
    let proportional = matches.opt_present("p");

    let smin = get_uint_opt(&matches, "smin").unwrap_or(2);
    let smax = get_uint_opt(&matches, "smax").unwrap_or(3);
    let rmin = get_uint_opt(&matches, "rmin").unwrap_or(3);
    let rmax = get_uint_opt(&matches, "rmax").unwrap_or(3);

    // Load example PNG image.
    // let file = "examples/hex_square_tri_large.png";
    // let file = "examples/cartesian_grid.png";
    // let file = "examples/hex_grid.png";
    println!("Loading '{}'.", input);
    let image = Image::load_png(&Path::new(input));

    // Draw discovered cell boundaries into a new image.
    let mut cell_boundaries = Image::white(image.width, image.height);

    // Explore image breadth-first to break it
    // into cells of the same color.
    println!("Finding cells in image...");
    let pixels = (image.width * image.height) as uint;
    // TODO: reinstate separate `visited` map, too, for faster checking?
    let mut cell_map: Vec<Option<uint>> = Vec::from_elem(pixels, None);
    let mut cells: Vec<Cell> = Vec::with_capacity(100);
    let mut point_queue: RingBuf<Point> = RingBuf::with_capacity(pixels);
    // Create per-cell scratch space here so we don't need to allocate
    // again for every cell we visit.
    let mut cell_point_queue: RingBuf<Point> = RingBuf::with_capacity(pixels);
    point_queue.push_back(Point{ x: 0, y: 0 });
    while !point_queue.is_empty() {
        let point = match point_queue.pop_front() {
            None => panic!(),
            Some(p) => p,
        };
        // It might have already been consumed by another cell.
        if cell_map[image.linear_index(point)] == None {
            cells.push(Cell{
                color: image.color_at(point),
                neighbors: Vec::with_capacity(8),
                pixels: Vec::with_capacity(100),
            });
            let cell_index = cells.len() - 1;
            cell_map[image.linear_index(point)] = Some(cell_index);

            // Need to explore a single cell exhaustively before moving on;
            // otherwise we might interpret a strangely shaped cell as two
            // different cells and then have to join them up somehow later.
            flood_cell(
                &mut cells,
                &mut cell_map,
                &mut point_queue,
                &mut cell_point_queue,
                point,
                cell_index,
                &image,
                &mut cell_boundaries,
                wrap,
            );
        }
    }
    println!("Found {} cells.", cells.len());

    // Write out discovered cell boundaries.
    // cell_boundaries.save_png(&Path::new("image_out/cell_boundaries.png"));

    // Randomise initial world state.
    let mut rng = task_rng();
    let rng_iter = rng.gen_iter::<bool>();
    let mut front: &mut Vec<bool> = &mut rng_iter.take(cells.len()).collect::<Vec<bool>>();

    // Make back buffer for world.
    let mut back: &mut Vec<bool> = &mut Vec::from_elem(cells.len(), false);

    // Step world, writing out an image of the current state
    // at the start of each frame.
    let mut world_image = Image::white(image.width, image.height);
    for frame in range(0, frames) {
        // Write out current state.
        for (i, cell) in cells.iter().enumerate() {
            for p in cell.pixels.iter() {
                let color = if (*front)[i] {
                    Color{ red: 63, green: 63, blue: 63 }
                } else {
                    Color{ red: 255, green: 255, blue: 255 }
                };
                world_image.set_color_at(*p, color);
            }
        }
        // Overlay cell boundaries.
        for y in range(0, image.height as i32) {
            for x in range(0, image.width as i32) {
                let p = Point{ x: x, y: y };
                let color_in_boundary_image = cell_boundaries.color_at(p);
                let white = Color{ red: 255, green: 255, blue: 255 };
                if color_in_boundary_image != white {
                    world_image.set_color_at(p, color_in_boundary_image);
                }
            }
        }

        let frame_file = format!("image_out/{}{:0>8}.png", output_prefix, frame);
        println!("Writing frame to '{}'.", frame_file);
        world_image.save_png(&Path::new(frame_file));

        // Calculate next frame.
        for i in range(0, cells.len()) {
            let alive = (*front)[i];
            let mut living_neighbors = 0u;
            for neighbor in cells[i].neighbors.iter() {
                if (*front)[*neighbor] {
                    if proportional {
                        living_neighbors += cells[*neighbor].neighbors.len();
                    } else {
                        living_neighbors += 1;
                    }
                }
            }
            if proportional {
                living_neighbors = living_neighbors * 4 / cells[i].neighbors.len();
            }

            // Apply life rules.
            back[i] = if alive {
                living_neighbors >= smin && // Sufficient neighbors to sustain.
                living_neighbors <= smax // Not so many we're overcrowded.
            } else {
                living_neighbors >= rmin && // Sufficient neighbors to reproduce.
                living_neighbors <= rmax // Not so many we're overcrowded;
                                         // possible to make higher than smax to
                                         // give unfair advantage to newborns.
            }
        }

        mem::swap(&mut front, &mut back);
    }
}

fn flood_cell(
    cells: &mut Vec<Cell>,
    cell_map: &mut Vec<Option<uint>>,
    point_queue: &mut RingBuf<Point>,
    cell_point_queue: &mut RingBuf<Point>,
    starting_point: Point,
    cell_index: uint,
    image: &Image,
    cell_boundaries: &mut Image,
    wrap: bool,
) {
    let cell_color = (*cells)[cell_index].color;
    cell_point_queue.clear();
    cell_point_queue.push_back(starting_point);
    while !cell_point_queue.is_empty() {
        let point = match cell_point_queue.pop_front() {
            None => panic!(),
            Some(p) => p,
        };
        cells[cell_index].pixels.push(point);
        let neighbors = point_neighbors(point);
        for neighbor in neighbors.iter() {
            let mut neighbor = *neighbor;

            // Wrap coordinates if requested.
            // Note that the result of % depends on the sign of the divisor,
            // so transpose everything north to avoid negative numbers entirely.
            if wrap {
                neighbor = Point{
                    x: (neighbor.x + image.width as i32) % image.width as i32,
                    y: (neighbor.y + image.height as i32) % image.height as i32,
                };
            }

            // Ignore if outside the image bounds.
            let oob = !wrap && (
                neighbor.x < 0 ||
                neighbor.x >= image.width as i32 ||
                neighbor.y < 0 ||
                neighbor.y >= image.height as i32
            );
            if oob {
                // Mark the current pixel (not the neighbor) as the edge of a cell.
                mark_cell_border(point, cell_boundaries);
                continue;
            }

            let neighbor_cell = &mut cell_map[image.linear_index(neighbor)];
            match *neighbor_cell {
                None => {
                    if image.color_at(neighbor) == cell_color {
                        // Same color as this cell; add it to the cell and queue it
                        // up as a starting point for further explanation.
                        *neighbor_cell = Some(cell_index);
                        cell_point_queue.push_back(neighbor);
                    } else {
                        // Doesn't belong to this cell; queue it up to maybe
                        // be the start of another cell.
                        point_queue.push_back(neighbor);

                        // Neighbor is another color, so will eventually be part of another cell.
                        // Mark the current pixel (not the neighbor) as the edge of a cell.
                        mark_cell_border(point, cell_boundaries);
                    }
                },
                Some(neighbor_cell) => {
                    if image.color_at(neighbor) != cell_color {
                        // Neighbor is already part of another cell.
                        // Mark the current pixel (not the neighbor) as the edge of a cell.
                        mark_cell_border(point, cell_boundaries);

                        // Mark the cells as neighbors if they're not already.
                        if !(*cells)[cell_index].neighbors.contains(&neighbor_cell) {
                            cells[cell_index].neighbors.push(neighbor_cell);
                            cells[neighbor_cell].neighbors.push(cell_index);
                        }
                    }
                }
            }
        }
    }
}

fn mark_cell_border(point: Point, cell_boundaries: &mut Image) {
    cell_boundaries.set_color_at(point, Color{red: 127, green: 127, blue: 127});
}

fn point_neighbors(point: Point) -> [Point, ..8] {
    [
        Point{ x: point.x - 1, y: point.y - 1 },
        Point{ x: point.x,     y: point.y - 1 },
        Point{ x: point.x + 1, y: point.y - 1 },
        Point{ x: point.x - 1, y: point.y     },
        Point{ x: point.x + 1, y: point.y     },
        Point{ x: point.x - 1, y: point.y + 1 },
        Point{ x: point.x,     y: point.y + 1 },
        Point{ x: point.x + 1, y: point.y + 1 },
    ]
}<commit_msg>Create image output directory.<commit_after>extern crate core;
extern crate collections;
extern crate png;
extern crate getopts;

use core::mem;

use std::io;
use std::io::fs::mkdir;
use std::os;
use std::rand::{task_rng, Rng};

use collections::RingBuf;
use collections::String;

use getopts::{optopt, optflag, getopts, OptGroup, Matches, usage};

use image::{Image, Color, Point};
mod image;

struct Cell {
    color: Color,
    neighbors: Vec<uint>,
    pixels: Vec<Point>,
}

fn print_usage(program: &str, opts: &[OptGroup]) {
    let short_message = format!("Usage: {} [options] <input_file>", program);
    println!("{}", usage(short_message.as_slice(), opts));
}

fn get_uint_opt(matches: &Matches, opt_name: &str) -> Option<uint> {
    match matches.opt_str(opt_name) {
        Some(string) => match from_str(string.as_slice().trim()) {
            Some(value) => Some(value),
            None => panic!("Bad uint arg"),
        },
        None => None,
    }
}

fn main() {
    // Parse program arguments.
    let args: Vec<String> = os::args();
    let program = args[0].clone();
    let opts = [
        optopt("", "smin", "minimum neighbors for existing cell to survive", "UINT"),
        optopt("", "smax", "maximum neighbors for existing cell to survive", "UINT"),
        optopt("", "rmin", "minimum neighbors for new cell to be born", "UINT"),
        optopt("", "rmax", "maximum neighbors for new cell to be born", "UINT"),
        optopt("f", "frames", "number of frames to render", "UINT"),
        optflag("w", "wrap", "treat image space as toroidal"),
        optflag("p", "proportional", "weight neighbors by how many neighbors they have"),
        optopt("o", "output-prefix", "prefix for output frame files", "STRING"),
        optflag("h", "help", "print usage information"),
    ];
    let matches = match getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };
    if matches.opt_present("h") {
        print_usage(program.as_slice(), opts);
        return;
    }
    let input = if matches.free.len() == 1 {
        matches.free[0].clone()
    } else {
        print_usage(program.as_slice(), opts);
        return;
    };
    let output_prefix = matches.opt_str("output-prefix").unwrap_or(String::from_str("frame_"));

    let frames = get_uint_opt(&matches, "frames").unwrap_or(100);
    let wrap = matches.opt_present("w");
    let proportional = matches.opt_present("p");

    let smin = get_uint_opt(&matches, "smin").unwrap_or(2);
    let smax = get_uint_opt(&matches, "smax").unwrap_or(3);
    let rmin = get_uint_opt(&matches, "rmin").unwrap_or(3);
    let rmax = get_uint_opt(&matches, "rmax").unwrap_or(3);

    // Load example PNG image.
    // let file = "examples/hex_square_tri_large.png";
    // let file = "examples/cartesian_grid.png";
    // let file = "examples/hex_grid.png";
    println!("Loading '{}'.", input);
    let image = Image::load_png(&Path::new(input));

    // Draw discovered cell boundaries into a new image.
    let mut cell_boundaries = Image::white(image.width, image.height);

    // Explore image breadth-first to break it
    // into cells of the same color.
    println!("Finding cells in image...");
    let pixels = (image.width * image.height) as uint;
    // TODO: reinstate separate `visited` map, too, for faster checking?
    let mut cell_map: Vec<Option<uint>> = Vec::from_elem(pixels, None);
    let mut cells: Vec<Cell> = Vec::with_capacity(100);
    let mut point_queue: RingBuf<Point> = RingBuf::with_capacity(pixels);
    // Create per-cell scratch space here so we don't need to allocate
    // again for every cell we visit.
    let mut cell_point_queue: RingBuf<Point> = RingBuf::with_capacity(pixels);
    point_queue.push_back(Point{ x: 0, y: 0 });
    while !point_queue.is_empty() {
        let point = match point_queue.pop_front() {
            None => panic!(),
            Some(p) => p,
        };
        // It might have already been consumed by another cell.
        if cell_map[image.linear_index(point)] == None {
            cells.push(Cell{
                color: image.color_at(point),
                neighbors: Vec::with_capacity(8),
                pixels: Vec::with_capacity(100),
            });
            let cell_index = cells.len() - 1;
            cell_map[image.linear_index(point)] = Some(cell_index);

            // Need to explore a single cell exhaustively before moving on;
            // otherwise we might interpret a strangely shaped cell as two
            // different cells and then have to join them up somehow later.
            flood_cell(
                &mut cells,
                &mut cell_map,
                &mut point_queue,
                &mut cell_point_queue,
                point,
                cell_index,
                &image,
                &mut cell_boundaries,
                wrap,
            );
        }
    }
    println!("Found {} cells.", cells.len());

    // Ensure output directory exists.
    let res = mkdir(&Path::new("./image_out"), io::USER_DIR);
    match res {
        Err(e) => {
            match e.kind {
                io::IoErrorKind::OtherIoError => {}, // For some reason not PathAlreadyExists...
                _ => panic!("Couldn't create output directory! {}", e.kind),
            }
        },
        _ => {},
    }

    // Write out discovered cell boundaries.
    // cell_boundaries.save_png(&Path::new("image_out/cell_boundaries.png"));

    // Randomise initial world state.
    let mut rng = task_rng();
    let rng_iter = rng.gen_iter::<bool>();
    let mut front: &mut Vec<bool> = &mut rng_iter.take(cells.len()).collect::<Vec<bool>>();

    // Make back buffer for world.
    let mut back: &mut Vec<bool> = &mut Vec::from_elem(cells.len(), false);

    // Step world, writing out an image of the current state
    // at the start of each frame.
    let mut world_image = Image::white(image.width, image.height);
    for frame in range(0, frames) {
        // Write out current state.
        for (i, cell) in cells.iter().enumerate() {
            for p in cell.pixels.iter() {
                let color = if (*front)[i] {
                    Color{ red: 63, green: 63, blue: 63 }
                } else {
                    Color{ red: 255, green: 255, blue: 255 }
                };
                world_image.set_color_at(*p, color);
            }
        }
        // Overlay cell boundaries.
        for y in range(0, image.height as i32) {
            for x in range(0, image.width as i32) {
                let p = Point{ x: x, y: y };
                let color_in_boundary_image = cell_boundaries.color_at(p);
                let white = Color{ red: 255, green: 255, blue: 255 };
                if color_in_boundary_image != white {
                    world_image.set_color_at(p, color_in_boundary_image);
                }
            }
        }

        let frame_file = format!("image_out/{}{:0>8}.png", output_prefix, frame);
        println!("Writing frame to '{}'.", frame_file);
        world_image.save_png(&Path::new(frame_file));

        // Calculate next frame.
        for i in range(0, cells.len()) {
            let alive = (*front)[i];
            let mut living_neighbors = 0u;
            for neighbor in cells[i].neighbors.iter() {
                if (*front)[*neighbor] {
                    if proportional {
                        living_neighbors += cells[*neighbor].neighbors.len();
                    } else {
                        living_neighbors += 1;
                    }
                }
            }
            if proportional {
                living_neighbors = living_neighbors * 4 / cells[i].neighbors.len();
            }

            // Apply life rules.
            back[i] = if alive {
                living_neighbors >= smin && // Sufficient neighbors to sustain.
                living_neighbors <= smax // Not so many we're overcrowded.
            } else {
                living_neighbors >= rmin && // Sufficient neighbors to reproduce.
                living_neighbors <= rmax // Not so many we're overcrowded;
                                         // possible to make higher than smax to
                                         // give unfair advantage to newborns.
            }
        }

        mem::swap(&mut front, &mut back);
    }
}

fn flood_cell(
    cells: &mut Vec<Cell>,
    cell_map: &mut Vec<Option<uint>>,
    point_queue: &mut RingBuf<Point>,
    cell_point_queue: &mut RingBuf<Point>,
    starting_point: Point,
    cell_index: uint,
    image: &Image,
    cell_boundaries: &mut Image,
    wrap: bool,
) {
    let cell_color = (*cells)[cell_index].color;
    cell_point_queue.clear();
    cell_point_queue.push_back(starting_point);
    while !cell_point_queue.is_empty() {
        let point = match cell_point_queue.pop_front() {
            None => panic!(),
            Some(p) => p,
        };
        cells[cell_index].pixels.push(point);
        let neighbors = point_neighbors(point);
        for neighbor in neighbors.iter() {
            let mut neighbor = *neighbor;

            // Wrap coordinates if requested.
            // Note that the result of % depends on the sign of the divisor,
            // so transpose everything north to avoid negative numbers entirely.
            if wrap {
                neighbor = Point{
                    x: (neighbor.x + image.width as i32) % image.width as i32,
                    y: (neighbor.y + image.height as i32) % image.height as i32,
                };
            }

            // Ignore if outside the image bounds.
            let oob = !wrap && (
                neighbor.x < 0 ||
                neighbor.x >= image.width as i32 ||
                neighbor.y < 0 ||
                neighbor.y >= image.height as i32
            );
            if oob {
                // Mark the current pixel (not the neighbor) as the edge of a cell.
                mark_cell_border(point, cell_boundaries);
                continue;
            }

            let neighbor_cell = &mut cell_map[image.linear_index(neighbor)];
            match *neighbor_cell {
                None => {
                    if image.color_at(neighbor) == cell_color {
                        // Same color as this cell; add it to the cell and queue it
                        // up as a starting point for further explanation.
                        *neighbor_cell = Some(cell_index);
                        cell_point_queue.push_back(neighbor);
                    } else {
                        // Doesn't belong to this cell; queue it up to maybe
                        // be the start of another cell.
                        point_queue.push_back(neighbor);

                        // Neighbor is another color, so will eventually be part of another cell.
                        // Mark the current pixel (not the neighbor) as the edge of a cell.
                        mark_cell_border(point, cell_boundaries);
                    }
                },
                Some(neighbor_cell) => {
                    if image.color_at(neighbor) != cell_color {
                        // Neighbor is already part of another cell.
                        // Mark the current pixel (not the neighbor) as the edge of a cell.
                        mark_cell_border(point, cell_boundaries);

                        // Mark the cells as neighbors if they're not already.
                        if !(*cells)[cell_index].neighbors.contains(&neighbor_cell) {
                            cells[cell_index].neighbors.push(neighbor_cell);
                            cells[neighbor_cell].neighbors.push(cell_index);
                        }
                    }
                }
            }
        }
    }
}

fn mark_cell_border(point: Point, cell_boundaries: &mut Image) {
    cell_boundaries.set_color_at(point, Color{red: 127, green: 127, blue: 127});
}

fn point_neighbors(point: Point) -> [Point, ..8] {
    [
        Point{ x: point.x - 1, y: point.y - 1 },
        Point{ x: point.x,     y: point.y - 1 },
        Point{ x: point.x + 1, y: point.y - 1 },
        Point{ x: point.x - 1, y: point.y     },
        Point{ x: point.x + 1, y: point.y     },
        Point{ x: point.x - 1, y: point.y + 1 },
        Point{ x: point.x,     y: point.y + 1 },
        Point{ x: point.x + 1, y: point.y + 1 },
    ]
}<|endoftext|>


<commit_before>#![cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
#![cfg_attr(feature = "cargo-clippy", allow(let_and_return))]
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]

extern crate case;
extern crate docopt;
extern crate env_logger;
#[macro_use]
extern crate error_chain;
extern crate git2;
extern crate hprof;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate regex;
extern crate stripper_lib;
extern crate toml;
extern crate xml;

use std::cell::RefCell;

use config::WorkMode;
use env::Env;
use library::Library;
use hprof::Profiler;

//generated by build.rs
mod gir_version;

mod analysis;
mod chunk;
mod codegen;
mod config;
mod consts;
mod env;
mod file_saver;
mod git;
mod library;
mod library_postprocessing;
mod nameutil;
mod parser;
mod traits;
mod update_version;
mod version;
mod writer;
mod xmlparser;

use self::config::error::*;

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

        for e in e.iter().skip(1) {
            println!("caused by: {}", e);
        }

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

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

    let mut cfg = match config::Config::new() {
        Ok(cfg) => cfg,
        Err(Error(ErrorKind::CommandLine(ref err), _)) => {
            // Fatal errors processed in same branch
            // to prevent repeat message in "caused by:"
            if err.fatal() {
                println!("error: {}", err);
            } else {
                println!("{}", err);
            }
            return Ok(());
        }
        Err(err) => return Err(err),
    };

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

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

    let mut library;

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

        library = Library::new(&cfg.library_name);
        try!(library.read_file(&cfg.girs_dir, &cfg.library_full_name()));
    }

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

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

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

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

    let mut env;

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

        let namespaces = analysis::namespaces::run(&library);
        let symbols = analysis::symbols::run(&library, &namespaces);
        let class_hierarchy = analysis::class_hierarchy::run(&library);

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

    {
        let _watcher = statistics.enter("Analysing");
        analysis::run(&mut env);
    }

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

    drop(watcher_total);
    statistics.end_frame();

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

    Ok(())
}
<commit_msg>Don't call analysis::run in sys mode<commit_after>#![cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
#![cfg_attr(feature = "cargo-clippy", allow(let_and_return))]
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]

extern crate case;
extern crate docopt;
extern crate env_logger;
#[macro_use]
extern crate error_chain;
extern crate git2;
extern crate hprof;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate regex;
extern crate stripper_lib;
extern crate toml;
extern crate xml;

use std::cell::RefCell;

use config::WorkMode;
use env::Env;
use library::Library;
use hprof::Profiler;

//generated by build.rs
mod gir_version;

mod analysis;
mod chunk;
mod codegen;
mod config;
mod consts;
mod env;
mod file_saver;
mod git;
mod library;
mod library_postprocessing;
mod nameutil;
mod parser;
mod traits;
mod update_version;
mod version;
mod writer;
mod xmlparser;

use self::config::error::*;

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

        for e in e.iter().skip(1) {
            println!("caused by: {}", e);
        }

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

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

    let mut cfg = match config::Config::new() {
        Ok(cfg) => cfg,
        Err(Error(ErrorKind::CommandLine(ref err), _)) => {
            // Fatal errors processed in same branch
            // to prevent repeat message in "caused by:"
            if err.fatal() {
                println!("error: {}", err);
            } else {
                println!("{}", err);
            }
            return Ok(());
        }
        Err(err) => return Err(err),
    };

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

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

    let mut library;

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

        library = Library::new(&cfg.library_name);
        try!(library.read_file(&cfg.girs_dir, &cfg.library_full_name()));
    }

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

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

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

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

    let mut env;

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

        let namespaces = analysis::namespaces::run(&library);
        let symbols = analysis::symbols::run(&library, &namespaces);
        let class_hierarchy = analysis::class_hierarchy::run(&library);

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

    if env.config.work_mode != WorkMode::Sys {
        let _watcher = statistics.enter("Analysing");
        analysis::run(&mut env);
    }

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

    drop(watcher_total);
    statistics.end_frame();

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

    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2015 Jan Likar.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate cargo;
extern crate docopt;
extern crate rustc_serialize;
extern crate cargo_clone;

use cargo::core::SourceId;
use cargo::util::{Config, CliResult};

use docopt::Docopt;

#[derive(RustcDecodable, Debug)]
pub struct Options {
    flag_verbose: bool,
    flag_quiet: bool,
    flag_color: Option<String>,

    arg_crate: Option<String>,
    flag_vers: Option<String>,

    flag_path: Option<String>,
}

pub const USAGE: &'static str = "
Clone source code of a Rust crate
Usage:
    cargo-clone [options] [<crate>]

Options:
    --vers VERS               Specify a version to clone from crates.io

    -h, --help                Print this message
    -v, --verbose             Use verbose output
    -q, --quiet               Less output printed to stdout
    --color WHEN              Coloring: auto, always, never
";

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

    let config = Config::default().expect("Unable to get config");

    if let Err(e) = execute(options, config) {
        println!("{}", e.to_string())
    }
}

pub fn execute(options: Options, config: Config) -> CliResult<Option<()>> {
    try!(config.shell().set_verbosity(options.flag_verbose, options.flag_quiet));
    try!(config.shell().set_color_config(options.flag_color.as_ref().map(|s| &s[..])));

    // Make a SourceId for the default Registry (usually crates.io)
    let source_id = try!(SourceId::for_central(&config));

    try!(cargo_clone::ops::clone(&options.arg_crate, &source_id, options.flag_vers, config));

    Ok(None)
}
<commit_msg>Fix incorect arg parsing<commit_after>// Copyright 2015 Jan Likar.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate cargo;
extern crate docopt;
extern crate rustc_serialize;
extern crate cargo_clone;

use cargo::core::SourceId;
use cargo::util::{Config, CliResult};

use docopt::Docopt;

#[derive(RustcDecodable, Debug)]
pub struct Options {
    flag_verbose: bool,
    flag_quiet: bool,
    flag_color: Option<String>,

    arg_crate: Option<String>,
    flag_vers: Option<String>,

    flag_path: Option<String>,
}

pub const USAGE: &'static str = "
Clone source code of a Rust crate
Usage:
    cargo clone [options] [<crate>]

Options:
    --vers VERS               Specify a version to clone from crates.io

    -h, --help                Print this message
    -v, --verbose             Use verbose output
    -q, --quiet               Less output printed to stdout
    --color WHEN              Coloring: auto, always, never
";

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

    let config = Config::default().expect("Unable to get config");

    if let Err(e) = execute(options, config) {
        println!("{}", e.to_string())
    }
}

pub fn execute(options: Options, config: Config) -> CliResult<Option<()>> {
    try!(config.shell().set_verbosity(options.flag_verbose, options.flag_quiet));
    try!(config.shell().set_color_config(options.flag_color.as_ref().map(|s| &s[..])));

    // Make a SourceId for the default Registry (usually crates.io)
    let source_id = try!(SourceId::for_central(&config));

    try!(cargo_clone::ops::clone(&options.arg_crate, &source_id, options.flag_vers, config));

    Ok(None)
}
<|endoftext|>


<commit_before>extern crate yaml_rust;
extern crate csv;
extern crate tina;

mod config;

use std::env;

use tina::*;
use config::*;

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

	let conf_path = match args.len() >= 2 {
		true => args[1].as_str(),
		false => "tina.yaml",
	};

	let conf = match Config::load_config(conf_path) {
		Err(err) => {
			println!("Error while loading config ({:?})", err);
			return;
		},
		Ok(c) => c
	};

	let tw_func = |eews: &[EEW], latest: &EEW| {
		match ja_format_eew_short(latest, eews.iter().rev().nth(1)) {
			Some(v) => Some(Box::new(v)),
			None => None
		}
	};

	let stdout_func = |_: &[EEW], latest: &EEW| {
		Some(Box::new(format_eew_full(latest)))
	};

	let wni_client = WNIClient::new(conf.wni_id.clone(), conf.wni_password.clone());
	let mut dests: Vec<Box<Emit>> = Vec::new();

	if conf.twitter.is_some() {
		let t = &conf.twitter.unwrap();
		let tc = Box::new(TwitterClient::new(
			t.consumer_token.clone(), t.consumer_secret.clone(),
			t.access_token.clone(), t.access_secret.clone()));
		let te = Box::new(Emitter::new(tc, &tw_func));
		dests.push(te);
		println!("Use: Twitter");
	}

	let sl = Box::new(StdoutLogger::new());
	let se = Box::new(Emitter::new(sl, &stdout_func));
	dests.push(se);
	println!("Use: Stdout");

	let mut buffer = EEWBuffer::new();

	loop {

		let mut connection = match wni_client.connect() {
			Ok(v) => v,
			Err(e) => {
				println!("ConnectionError: {:?}", e);
				continue;
			}
		};

		loop {

			let eew = match connection.wait_for_telegram(&conf.epicenter_dict, &conf.area_dict) {
				Err(e) => {
					println!("StreamingError: {:?}", e);
					break;
				},
				Ok(eew) => eew
			};

			if let Some(eews) = buffer.append(&eew) {
				for d in dests.iter() {
					d.emit(&eews, &eew);
				}
			}
		}
	}
}
<commit_msg>Refactor<commit_after>extern crate yaml_rust;
extern crate csv;
extern crate tina;

mod config;

use std::env;

use tina::*;
use config::*;

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

	let conf_path = args.get(1).map(|s| s.as_str()).unwrap_or("tina.yaml");

	let conf = match Config::load_config(conf_path) {
		Err(err) => {
			println!("Error while loading config ({:?})", err);
			return;
		},
		Ok(c) => c
	};

	let tw_func = |eews: &[EEW], latest: &EEW| {
		match ja_format_eew_short(latest, eews.iter().rev().nth(1)) {
			Some(v) => Some(Box::new(v)),
			None => None
		}
	};

	let stdout_func = |_: &[EEW], latest: &EEW| {
		Some(Box::new(format_eew_full(latest)))
	};

	let wni_client = WNIClient::new(conf.wni_id.clone(), conf.wni_password.clone());
	let mut dests: Vec<Box<Emit>> = Vec::new();

	if conf.twitter.is_some() {
		let t = &conf.twitter.unwrap();
		let tc = Box::new(TwitterClient::new(
			t.consumer_token.clone(), t.consumer_secret.clone(),
			t.access_token.clone(), t.access_secret.clone()));
		let te = Box::new(Emitter::new(tc, &tw_func));
		dests.push(te);
		println!("Use: Twitter");
	}

	let sl = Box::new(StdoutLogger::new());
	let se = Box::new(Emitter::new(sl, &stdout_func));
	dests.push(se);
	println!("Use: Stdout");

	let mut buffer = EEWBuffer::new();

	loop {

		let mut connection = match wni_client.connect() {
			Ok(v) => v,
			Err(e) => {
				println!("ConnectionError: {:?}", e);
				continue;
			}
		};

		loop {

			let eew = match connection.wait_for_telegram(&conf.epicenter_dict, &conf.area_dict) {
				Err(e) => {
					println!("StreamingError: {:?}", e);
					break;
				},
				Ok(eew) => eew
			};

			if let Some(eews) = buffer.append(&eew) {
				for d in dests.iter() {
					d.emit(&eews, &eew);
				}
			}
		}
	}
}
<|endoftext|>