<commit_before>//! Implementation of a simple uTP client and server.
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate getopts;
extern crate daemonize;
extern crate udt;
extern crate crypto;
extern crate byteorder;

use daemonize::{Daemonize};
use std::process;
use std::process::Command;
use std::thread;
use std::net::{SocketAddr, SocketAddrV4, Ipv4Addr};
use std::net;
use std::str;
use std::env;
use std::fs::File;
use std::str::FromStr;
use std::path::Path;
use std::io;
use std::io::{Cursor, Error, Seek, SeekFrom, ErrorKind, stdin, stdout, stderr, Read, Write};
use getopts::Options;
use crypto::{blake2b};
use udt::*;
use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian};

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

fn send_file(stream: UdtSocket, filename: &str) -> Result<(), Error> {
    let mut f = File::open(filename).unwrap();

    let mut filesize = 0u64;
    let mut buf = vec![0; 1024 * 1024];
    loop {
        match try!(f.read(&mut buf)) {
            0    => { break },
            read => { filesize += read as u64 },
        }
    }

    let mut wtr = vec![];
    wtr.write_u64::<LittleEndian>(filesize).unwrap();
    match stream.sendmsg(&wtr[..]) {
        Ok(0) => {
            return Err(Error::new(ErrorKind::WriteZero, "failed to write filesize header before timeout"))
        },
        Err(e) => {
            return Err(Error::new(ErrorKind::Other, format!("{:?}", e)))
        }
        _ => {
            println!("wrote filesize of {}.", filesize);
        }
    }
    let mut total = 0;
    let mut payload = vec![0; 1300];
    f.seek(SeekFrom::Start(0));
    loop {
        match f.read(&mut payload) {
            Ok(0) => {
                println!("\nEOF.");
                stream.sendmsg(&vec![0;0]);
                break;
            }
            Ok(read) => {
                match stream.sendmsg(&payload[0..read]) {
                    Ok(written) => {
                        total += written;
                        print!("\rwritten {} / {}", total, filesize);
                    },
                    Err(e) => {
                        stream.close().expect("Error closing stream");
                        panic!("{:?}", e);
                    }
                }
            },
            Err(e) => {
                stream.close().expect("Error closing stream");
                panic!("{}", e);
            }
        }
    }

    stream.close().expect("Error closing stream.");
    println!("all done!");
    Ok(())
}

fn recv_file(sock: UdtSocket, filesize: u64, filename: &str) -> Result<(), Error> {
    let mut f = File::create(filename).unwrap();
    let mut total = 0u64;
    loop {
        let buf = try!(sock.recvmsg(1024*1024).map_err(|e| Error::new(ErrorKind::Other, format!("{:?}", e))));
        total += buf.len() as u64;
        f.write_all(&buf[..]);
        print!("read {}\r", total);
        if total >= filesize {
            println!("\nEOF");
            break;
        }
    }
    sock.close();
    Ok(())
}

fn main() {

    // This example may run in either server or client mode.
    // Using an enum tends to make the code cleaner and easier to read.
    enum Mode {Server, Client}

    // Start logging
    env_logger::init().expect("Error starting logger");

    // Fetch arguments
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();
    let mut opts = Options::new();
    opts.optopt("o", "output", "set output file name", "NAME");
    opts.optflag("s", "server", "server mode");
    opts.optflag("p", "port-range", "server listening port range");
    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;
    }

    let input = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(&program, opts);
        return;
    };

    // Parse the mode argument
    let mode: Mode = match matches.opt_present("s") {
        true => Mode::Server,
        false => Mode::Client
    };

    match mode {
        Mode::Server => {
            udt::init();
            let sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap();
            sock.setsockopt(UdtOpts::UDP_RCVBUF, 5590000i32);
            sock.setsockopt(UdtOpts::UDP_SNDBUF, 5590000i32);
            // sock.setsockopt(UdtOpts::UDT_SNDSYN, true);
            sock.bind(SocketAddr::V4(SocketAddrV4::from_str("0.0.0.0:55000").unwrap())).unwrap();
            let my_addr = sock.getsockname().unwrap();
            println!("Server bound to {:?}", my_addr);

            sock.listen(1).unwrap();

            let (mut stream, peer) = sock.accept().unwrap();
            println!("Received new connection from peer {:?}", peer);

            let daemonize = Daemonize::new();

            let mut clientversion = vec![0; 1];
            if let Ok(version) = stream.recvmsg(1) {
                println!("frand using protocol version {}.", version[0]);
                if version[0] == 0x00 {
                    send_file(stream, &input);
                } else {
                    panic!("Unrecognized version.");
                }
            } else {
                panic!("Failed to receive version byte from client.");
            }

            // match daemonize.start() {
            //     Ok(_) => { let _ = writeln!(&mut stderr(), "daemonized"); }
            //     Err(e) => { let _ = writeln!(&mut stderr(), "RWRWARWARARRR"); }
            // }

        }
        Mode::Client => {
            let sections: Vec<&str> = input.split(":").collect();
            let addr: String = sections[0].to_owned();
            let path: String = sections[1].to_owned();
            let cmd = format!("~/bin/shoop -s {}", path);
            println!("addr: {}, path: {}, cmd: {}", addr, path, cmd);

            // let output = Command::new("ssh")
            //                      .arg(addr.to_owned())
            //                      .arg(cmd)
            //                      .output()
            //                      .unwrap_or_else(|e| {
            //                          panic!("failed to execute process: {}", e);
            //                      });
            // let udp_addr = String::from_utf8_lossy(&output.stdout).trim().to_owned();
            //
            // // Create a stream and try to connect to the remote address
            // println!("shoop server told us to connect to {}", udp_addr);
            udt::init();
            let sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap();
            sock.setsockopt(UdtOpts::UDP_RCVBUF, 5590000i32);
            sock.setsockopt(UdtOpts::UDP_SNDBUF, 5590000i32);
            let addr: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from_str(&addr).unwrap(), 55000));
            sock.bind(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from_str("0.0.0.0").unwrap(), 0)));
            match sock.connect(addr) {
                Ok(()) => {
                    println!("connected!");
                },
                Err(e) => {
                    panic!("errrrrrrr {:?}", e);
                }
            }

            sock.sendmsg(&[0u8; 1]);
            println!("checking if server is frand");

            match sock.recvmsg(8) {
                Ok(msg) => {
                    if msg.len() == 0 {
                        panic!("failed to get filesize from server, probable timeout.");
                    }
                    let mut rdr = Cursor::new(msg);
                    let filesize = rdr.read_u64::<LittleEndian>().unwrap();
                    println!("got reported filesize of {}", filesize);
                    recv_file(sock, filesize, "outfile");
                }
                Err(e) => {
                    panic!("{:?}", e);
                }
            }
        }
    }
}

<commit_msg>better msging<commit_after>//! Implementation of a simple uTP client and server.
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate getopts;
extern crate daemonize;
extern crate udt;
extern crate crypto;
extern crate byteorder;

use daemonize::{Daemonize};
use std::process;
use std::process::Command;
use std::thread;
use std::net::{SocketAddr, SocketAddrV4, Ipv4Addr};
use std::net;
use std::str;
use std::env;
use std::fs::File;
use std::str::FromStr;
use std::path::Path;
use std::io;
use std::io::{Cursor, Error, Seek, SeekFrom, ErrorKind, stdin, stdout, stderr, Read, Write};
use getopts::Options;
use crypto::{blake2b};
use udt::*;
use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian};

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

fn send_file(stream: UdtSocket, filename: &str) -> Result<(), Error> {
    let mut f = File::open(filename).unwrap();

    let mut filesize = 0u64;
    let mut buf = vec![0; 1024 * 1024];
    loop {
        match try!(f.read(&mut buf)) {
            0    => { break },
            read => { filesize += read as u64 },
        }
    }

    let mut wtr = vec![];
    wtr.write_u64::<LittleEndian>(filesize).unwrap();
    match stream.sendmsg(&wtr[..]) {
        Ok(0) => {
            return Err(Error::new(ErrorKind::WriteZero, "failed to write filesize header before timeout"))
        },
        Err(e) => {
            return Err(Error::new(ErrorKind::Other, format!("{:?}", e)))
        }
        _ => {
            println!("wrote filesize of {:.2}kb.", filesize as f64 / 1024f64);
        }
    }
    let mut total = 0;
    let mut payload = vec![0; 1300];
    f.seek(SeekFrom::Start(0));
    loop {
        match f.read(&mut payload) {
            Ok(0) => {
                println!("\nEOF.");
                stream.sendmsg(&vec![0;0]);
                break;
            }
            Ok(read) => {
                match stream.sendmsg(&payload[0..read]) {
                    Ok(written) => {
                        total += written;
                        print!("\rwritten {}kb / {}kb ({:.1}%)", total/1024, filesize/1024, (total as f64/1024f64) / (filesize as f64/1024f64));
                    },
                    Err(e) => {
                        stream.close().expect("Error closing stream");
                        panic!("{:?}", e);
                    }
                }
            },
            Err(e) => {
                stream.close().expect("Error closing stream");
                panic!("{}", e);
            }
        }
    }

    stream.close().expect("Error closing stream.");
    println!("all done!");
    Ok(())
}

fn recv_file(sock: UdtSocket, filesize: u64, filename: &str) -> Result<(), Error> {
    let mut f = File::create(filename).unwrap();
    let mut total = 0u64;
    loop {
        let buf = try!(sock.recvmsg(1300).map_err(|e| Error::new(ErrorKind::Other, format!("{:?}", e))));
        total += buf.len() as u64;
        f.write_all(&buf[..]);
        print!("\rreceived {}kb / {}kb ({:.1}%)", total/1024, filesize/1024, (total as f64/1024f64) / (filesize as f64/1024f64));
        if total >= filesize {
            println!("\nEOF");
            break;
        }
    }
    sock.close();
    Ok(())
}

fn main() {

    // This example may run in either server or client mode.
    // Using an enum tends to make the code cleaner and easier to read.
    enum Mode {Server, Client}

    // Start logging
    env_logger::init().expect("Error starting logger");

    // Fetch arguments
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();
    let mut opts = Options::new();
    opts.optopt("o", "output", "set output file name", "NAME");
    opts.optflag("s", "server", "server mode");
    opts.optflag("p", "port-range", "server listening port range");
    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;
    }

    let input = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(&program, opts);
        return;
    };

    // Parse the mode argument
    let mode: Mode = match matches.opt_present("s") {
        true => Mode::Server,
        false => Mode::Client
    };

    match mode {
        Mode::Server => {
            udt::init();
            let sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap();
            sock.setsockopt(UdtOpts::UDP_RCVBUF, 5590000i32);
            sock.setsockopt(UdtOpts::UDP_SNDBUF, 5590000i32);
            // sock.setsockopt(UdtOpts::UDT_SNDSYN, true);
            sock.bind(SocketAddr::V4(SocketAddrV4::from_str("0.0.0.0:55000").unwrap())).unwrap();
            let my_addr = sock.getsockname().unwrap();
            println!("Server bound to {:?}", my_addr);

            sock.listen(1).unwrap();

            let (mut stream, peer) = sock.accept().unwrap();
            println!("Received new connection from peer {:?}", peer);

            let daemonize = Daemonize::new();

            let mut clientversion = vec![0; 1];
            if let Ok(version) = stream.recvmsg(1) {
                println!("frand using protocol version {}.", version[0]);
                if version[0] == 0x00 {
                    send_file(stream, &input);
                } else {
                    panic!("Unrecognized version.");
                }
            } else {
                panic!("Failed to receive version byte from client.");
            }

            // match daemonize.start() {
            //     Ok(_) => { let _ = writeln!(&mut stderr(), "daemonized"); }
            //     Err(e) => { let _ = writeln!(&mut stderr(), "RWRWARWARARRR"); }
            // }

        }
        Mode::Client => {
            let sections: Vec<&str> = input.split(":").collect();
            let addr: String = sections[0].to_owned();
            let path: String = sections[1].to_owned();
            let cmd = format!("~/bin/shoop -s {}", path);
            println!("addr: {}, path: {}, cmd: {}", addr, path, cmd);

            // let output = Command::new("ssh")
            //                      .arg(addr.to_owned())
            //                      .arg(cmd)
            //                      .output()
            //                      .unwrap_or_else(|e| {
            //                          panic!("failed to execute process: {}", e);
            //                      });
            // let udp_addr = String::from_utf8_lossy(&output.stdout).trim().to_owned();
            //
            // // Create a stream and try to connect to the remote address
            // println!("shoop server told us to connect to {}", udp_addr);
            udt::init();
            let sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap();
            sock.setsockopt(UdtOpts::UDP_RCVBUF, 5590000i32);
            sock.setsockopt(UdtOpts::UDP_SNDBUF, 5590000i32);
            let addr: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from_str(&addr).unwrap(), 55000));
            sock.bind(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from_str("0.0.0.0").unwrap(), 0)));
            match sock.connect(addr) {
                Ok(()) => {
                    println!("connected!");
                },
                Err(e) => {
                    panic!("errrrrrrr {:?}", e);
                }
            }

            sock.sendmsg(&[0u8; 1]);
            println!("checking if server is frand");

            match sock.recvmsg(8) {
                Ok(msg) => {
                    if msg.len() == 0 {
                        panic!("failed to get filesize from server, probable timeout.");
                    }
                    let mut rdr = Cursor::new(msg);
                    let filesize = rdr.read_u64::<LittleEndian>().unwrap();
                    println!("got reported filesize of {}", filesize);
                    recv_file(sock, filesize, "outfile");
                }
                Err(e) => {
                    panic!("{:?}", e);
                }
            }
        }
    }
}

<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
#[macro_use]
extern crate error_chain;
extern crate mhost;
extern crate resolv_conf;
extern crate tokio_core;
extern crate trust_dns;

use mhost::{multiple_lookup, DnsQuery};

use clap::{App, Arg, Shell};
use std::fmt;
use std::fs::File;
use std::io::Read;
use std::net::IpAddr;
use std::str::FromStr;
use std::time::Duration;
use tokio_core::reactor::Core;
use trust_dns::rr::{RData, RecordType};

static DEFAULT_RECORD_TYPES: &'static [&str] = &["a", "aaaa", "mx"];

// Arbitrary list of public DNS servers
static DEFAULT_DNS_SERVERS: &'static [&str] = &[
    // "Level3",
    "209.244.0.3",
    "209.244.0.4",
    // "Verisign",
    "64.6.64.6",
    "64.6.65.6",
    // "Google",
    "8.8.8.8",
    "8.8.4.4",
    // "DNS.WATCH",
    "84.200.69.80",
    "84.200.70.40",
    // "OpenDNS Home",
    "208.67.222.222",
    "208.67.220.220",
    // "SafeDNS",
    "195.46.39.39",
    "195.46.39.40",
    // "Dyn",
    "216.146.35.35",
    "216.146.36.36",
    // "FreeDNS",
    "37.235.1.174",
    "37.235.1.177",
    // "Alternate DNS",
    "198.101.242.72",
    "23.253.163.53",
];

// Newtype pattern for Display implementation
struct DnsResponse<'a>(pub &'a mhost::DnsResponse);

// Display impl for plain, basic output
impl<'a> fmt::Display for DnsResponse<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let DnsResponse(dns_response) = *self;
        if dns_response.answers.is_empty() {
            return write!(f, "DNS server {} has not records.", dns_response.server);
        }
        let _ = write!(f, "DNS server {} responded with\n", dns_response.server);
        let mut answers: Vec<String> = dns_response
            .answers
            .iter()
            .map(|answer| match *answer.rdata() {
                RData::A(ip) => format!(" * IPv4: {}", ip),
                RData::AAAA(ip) => format!(" * IPv6: {}", ip),
                RData::CNAME(ref name) => format!(" * CNAME: {}", name),
                RData::MX(ref mx) => {
                    format!(
                        " * MX: {} with preference {}",
                        mx.exchange(),
                        mx.preference()
                    )
                }
                RData::NS(ref name) => format!(" * NS: {}", name),
                RData::SOA(ref soa) => {
                    format!(
                        " * SOA: {} {} {} {} {} {} {}",
                        soa.mname(),
                        soa.rname(),
                        soa.serial(),
                        soa.refresh(),
                        soa.retry(),
                        soa.expire(),
                        soa.minimum()
                    )
                }
                RData::TXT(ref txt) => format!(" * TXT: {}", txt.txt_data().join(" ")),
                RData::PTR(ref ptr) => format!(" * PTR: {}", ptr.to_string()),
                ref x => format!(" * unclassified answer: {:?}", x),
            })
            .collect();
        answers.sort();
        write!(f, "{}", answers.join("\n"))
    }
}

fn run() -> Result<()> {
    let args = build_cli().get_matches();

    if args.is_present("completions") {
        let bin_name = env!("CARGO_PKG_NAME");
        let shell= args.value_of("completions").unwrap();
        build_cli().gen_completions_to(bin_name, shell.parse::<Shell>().unwrap(), &mut std::io::stdout());
        return Ok(());
    }

    // Check if domain_name is an IP address -> PTR query and ignore -t, else normal query
    let record_types = if IpAddr::from_str(&args.value_of("domain name").unwrap()).is_ok() {
        vec!["PTR"]
            .iter()
            .map(|rt| RecordType::from_str(&rt.to_uppercase()).unwrap())
            .collect()
    } else if let Some(record_types) = args.values_of_lossy("record types") {
        record_types
            .iter()
            .map(|rt| RecordType::from_str(&rt.to_uppercase()).unwrap())
            .collect()
    } else {
        DEFAULT_RECORD_TYPES
            .iter()
            .map(|rt| RecordType::from_str(&rt.to_uppercase()).unwrap())
            .collect()
    };

    let mut servers: Vec<_> = if let Some(dns_servers) = args.values_of_lossy("DNS servers") {
        dns_servers
            .iter()
            .map(|server| (IpAddr::from_str(server).unwrap(), 53))
            .collect()
    } else {
        DEFAULT_DNS_SERVERS
            .iter()
            .map(|server| (IpAddr::from_str(server).unwrap(), 53))
            .collect()
    };
    if !args.is_present("dont use local dns servers") {
        let mut buf = Vec::with_capacity(4096);
        let mut f = File::open("/etc/resolv.conf").unwrap();
        f.read_to_end(&mut buf).unwrap();
        let cfg = resolv_conf::Config::parse(&buf[..]).unwrap();
        let mut local_servers: Vec<_> = cfg.nameservers.into_iter().map(|s| (s, 53)).collect();
        servers.append(&mut local_servers);
    }

    let timeout = value_t!(args, "timeout", u64).map(|t| Duration::from_secs(t)).unwrap();

    // Check if domain_name is an IP address -> PTR query and ignore -t, else normal query
    let mut query = if let Ok(ip) = IpAddr::from_str(&args.value_of("domain name").unwrap()) {
        DnsQuery::from(ip, record_types)
    } else {
        DnsQuery::new(&args.value_of("domain name").unwrap(), record_types)
    };
    query = query.set_timeout(timeout);

    let mut io_loop = Core::new().unwrap();
    let lookup = multiple_lookup(&io_loop.handle(), query, servers);
    let result = io_loop.run(lookup);

    match result {
        Ok(ref responses) => {
            for response in responses {
                match *response {
                    Ok(ref x) => println!("{}", DnsResponse(x)),
                    Err(ref e) => println!("Error: {}", e),
                }
            }
        }
        Err(_) => {
            println!("General Error");
        }
    }

    Ok(())
}

fn build_cli() -> App<'static, 'static> {
    let name  = env!("CARGO_PKG_NAME");
    let version = env!("CARGO_PKG_VERSION");
    let about = env!("CARGO_PKG_DESCRIPTION");

    App::new(name)
        .version(version)
        .about(about)
        .arg(Arg::with_name("domain name")
            .index(1)
            .required(true)
            .help("domain name or IP address to look up"))
        .arg(Arg::with_name("timeout")
            .long("timeout")
            .default_value("5")
            .help("timeout for server responses in sec")
            .takes_value(true))
        .arg(Arg::with_name("record types")
            .long("type")
            .short("t")
            .takes_value(true)
            .multiple(true)
            .number_of_values(1)
            .possible_values(&["a", "aaaa", "any", "cname", "dnskey", "mx", "ns", "opt", "ptr", "soa", "srv", "txt"])
            .help("Select resource record type [default: a, aaaa, mx]"))
        .arg(Arg::with_name("dont use local dns servers")
            .short("L")
            .help("Do not use local (/etc/resolv.conf) DNS servers"))
        .arg(Arg::with_name("DNS servers")
            .long("server")
            .short("s")
            .takes_value(true)
            .multiple(true)
            .number_of_values(1)
            .help("DNS servers to use; if empty use predefined, public DNS server"))
        .arg(Arg::with_name("completions")
            .long("completions")
            .takes_value(true)
            .hidden(true)
            .possible_values(&["bash", "fish", "zsh"])
            .help("The shell to generate the script for"))
}

error_chain!{}

quick_main!(run);
<commit_msg>Fixes --completions vs. domain name cli args parsing bug<commit_after>#[macro_use]
extern crate clap;
#[macro_use]
extern crate error_chain;
extern crate mhost;
extern crate resolv_conf;
extern crate tokio_core;
extern crate trust_dns;

use mhost::{multiple_lookup, DnsQuery};

use clap::{App, Arg, Shell};
use std::fmt;
use std::fs::File;
use std::io::Read;
use std::net::IpAddr;
use std::str::FromStr;
use std::time::Duration;
use tokio_core::reactor::Core;
use trust_dns::rr::{RData, RecordType};

static DEFAULT_RECORD_TYPES: &'static [&str] = &["a", "aaaa", "mx"];

// Arbitrary list of public DNS servers
static DEFAULT_DNS_SERVERS: &'static [&str] = &[
    // "Level3",
    "209.244.0.3",
    "209.244.0.4",
    // "Verisign",
    "64.6.64.6",
    "64.6.65.6",
    // "Google",
    "8.8.8.8",
    "8.8.4.4",
    // "DNS.WATCH",
    "84.200.69.80",
    "84.200.70.40",
    // "OpenDNS Home",
    "208.67.222.222",
    "208.67.220.220",
    // "SafeDNS",
    "195.46.39.39",
    "195.46.39.40",
    // "Dyn",
    "216.146.35.35",
    "216.146.36.36",
    // "FreeDNS",
    "37.235.1.174",
    "37.235.1.177",
    // "Alternate DNS",
    "198.101.242.72",
    "23.253.163.53",
];

// Newtype pattern for Display implementation
struct DnsResponse<'a>(pub &'a mhost::DnsResponse);

// Display impl for plain, basic output
impl<'a> fmt::Display for DnsResponse<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let DnsResponse(dns_response) = *self;
        if dns_response.answers.is_empty() {
            return write!(f, "DNS server {} has not records.", dns_response.server);
        }
        let _ = write!(f, "DNS server {} responded with\n", dns_response.server);
        let mut answers: Vec<String> = dns_response
            .answers
            .iter()
            .map(|answer| match *answer.rdata() {
                RData::A(ip) => format!(" * IPv4: {}", ip),
                RData::AAAA(ip) => format!(" * IPv6: {}", ip),
                RData::CNAME(ref name) => format!(" * CNAME: {}", name),
                RData::MX(ref mx) => {
                    format!(
                        " * MX: {} with preference {}",
                        mx.exchange(),
                        mx.preference()
                    )
                }
                RData::NS(ref name) => format!(" * NS: {}", name),
                RData::SOA(ref soa) => {
                    format!(
                        " * SOA: {} {} {} {} {} {} {}",
                        soa.mname(),
                        soa.rname(),
                        soa.serial(),
                        soa.refresh(),
                        soa.retry(),
                        soa.expire(),
                        soa.minimum()
                    )
                }
                RData::TXT(ref txt) => format!(" * TXT: {}", txt.txt_data().join(" ")),
                RData::PTR(ref ptr) => format!(" * PTR: {}", ptr.to_string()),
                ref x => format!(" * unclassified answer: {:?}", x),
            })
            .collect();
        answers.sort();
        write!(f, "{}", answers.join("\n"))
    }
}

fn run() -> Result<()> {
    let args = build_cli().get_matches();

    if args.is_present("completions") {
        let bin_name = env!("CARGO_PKG_NAME");
        let shell= args.value_of("completions").unwrap();
        build_cli().gen_completions_to(bin_name, shell.parse::<Shell>().unwrap(), &mut std::io::stdout());
        return Ok(());
    }

    // Check if domain_name is an IP address -> PTR query and ignore -t, else normal query
    let record_types = if IpAddr::from_str(&args.value_of("domain name").unwrap()).is_ok() {
        vec!["PTR"]
            .iter()
            .map(|rt| RecordType::from_str(&rt.to_uppercase()).unwrap())
            .collect()
    } else if let Some(record_types) = args.values_of_lossy("record types") {
        record_types
            .iter()
            .map(|rt| RecordType::from_str(&rt.to_uppercase()).unwrap())
            .collect()
    } else {
        DEFAULT_RECORD_TYPES
            .iter()
            .map(|rt| RecordType::from_str(&rt.to_uppercase()).unwrap())
            .collect()
    };

    let mut servers: Vec<_> = if let Some(dns_servers) = args.values_of_lossy("DNS servers") {
        dns_servers
            .iter()
            .map(|server| (IpAddr::from_str(server).unwrap(), 53))
            .collect()
    } else {
        DEFAULT_DNS_SERVERS
            .iter()
            .map(|server| (IpAddr::from_str(server).unwrap(), 53))
            .collect()
    };
    if !args.is_present("dont use local dns servers") {
        let mut buf = Vec::with_capacity(4096);
        let mut f = File::open("/etc/resolv.conf").unwrap();
        f.read_to_end(&mut buf).unwrap();
        let cfg = resolv_conf::Config::parse(&buf[..]).unwrap();
        let mut local_servers: Vec<_> = cfg.nameservers.into_iter().map(|s| (s, 53)).collect();
        servers.append(&mut local_servers);
    }

    let timeout = value_t!(args, "timeout", u64).map(|t| Duration::from_secs(t)).unwrap();

    // Check if domain_name is an IP address -> PTR query and ignore -t, else normal query
    let mut query = if let Ok(ip) = IpAddr::from_str(&args.value_of("domain name").unwrap()) {
        DnsQuery::from(ip, record_types)
    } else {
        DnsQuery::new(&args.value_of("domain name").unwrap(), record_types)
    };
    query = query.set_timeout(timeout);

    let mut io_loop = Core::new().unwrap();
    let lookup = multiple_lookup(&io_loop.handle(), query, servers);
    let result = io_loop.run(lookup);

    match result {
        Ok(ref responses) => {
            for response in responses {
                match *response {
                    Ok(ref x) => println!("{}", DnsResponse(x)),
                    Err(ref e) => println!("Error: {}", e),
                }
            }
        }
        Err(_) => {
            println!("General Error");
        }
    }

    Ok(())
}

fn build_cli() -> App<'static, 'static> {
    let name  = env!("CARGO_PKG_NAME");
    let version = env!("CARGO_PKG_VERSION");
    let about = env!("CARGO_PKG_DESCRIPTION");

    App::new(name)
        .version(version)
        .about(about)
        .arg(Arg::with_name("domain name")
            .index(1)
            .required(true)
            .conflicts_with("completions")
            .help("domain name or IP address to look up"))
        .arg(Arg::with_name("timeout")
            .long("timeout")
            .default_value("5")
            .help("timeout for server responses in sec")
            .takes_value(true))
        .arg(Arg::with_name("record types")
            .long("type")
            .short("t")
            .takes_value(true)
            .multiple(true)
            .number_of_values(1)
            .possible_values(&["a", "aaaa", "any", "cname", "dnskey", "mx", "ns", "opt", "ptr", "soa", "srv", "txt"])
            .help("Select resource record type [default: a, aaaa, mx]"))
        .arg(Arg::with_name("dont use local dns servers")
            .short("L")
            .help("Do not use local (/etc/resolv.conf) DNS servers"))
        .arg(Arg::with_name("DNS servers")
            .long("server")
            .short("s")
            .takes_value(true)
            .multiple(true)
            .number_of_values(1)
            .help("DNS servers to use; if empty use predefined, public DNS server"))
        .arg(Arg::with_name("completions")
            .long("completions")
            .takes_value(true)
            .hidden(true)
            .possible_values(&["bash", "fish", "zsh"])
            .help("The shell to generate the script for"))
}

error_chain!{}

quick_main!(run);
<|endoftext|>


<commit_before>#[derive(Debug)]
enum Suit {
    Clubs,
    Diamonds,
    Hearts,
    Spades,
}

#[derive(Debug)]
struct Card {
    suit: Suit,
    value: char,
}

impl Card {
    fn new(suit: Suit, value: char) -> Card {
        Card { suit: suit, value: value }
    }
}
fn main() {
    println!("Hello, world!");
}
<commit_msg>add fluff<commit_after>#[derive(Debug)]
enum Suit {
    Clubs,
    Diamonds,
    Hearts,
    Spades,
}

#[derive(Debug)]
struct Card {
    suit: Suit,
    value: char,
}

impl Card {
    fn new(suit: Suit, value: char) -> Card {
        Card { suit: suit, value: value }
    }
}

fn print_card(card: Card) {
    println!("My card: {:?}", card);
}

fn main() {
    println!("Hello, world!");
    let card = Card::new(Suit::Hearts, 'Q');
    print_card(card);
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
use rustc_serialize::json::Json;
use std::collections::HashMap;

use std::ops::{Add, Sub, Mul, Div};

struct Evaluator(HashMap<String, f64>);

impl Evaluator {
  fn new() -> Evaluator { Evaluator(HashMap::new()) }

  fn get(&self, key: &str) -> f64 { *self.0.get(key).unwrap() }

  fn set(&mut self, key: &str, val: f64) { self.0.insert(key.to_owned(), val); }

  fn substitute(&mut self, expr: &Json) -> f64 {
    match *expr {
      Json::Array(ref arr) => self.eval(arr.as_slice()).as_f64().unwrap(),
      Json::F64(i) => i,
      Json::I64(i) => i as f64,
      Json::U64(i) => i as f64,
      _ => panic!("cannot substitute: {:?} (env: {:?})", expr, self.0)
    }
  }

  fn eval(&mut self, input: &[Json]) -> Json {
    let token = input[0].as_string().unwrap();
    let args = &input[1..];

    match token {
      "step" => self.eval_step(args),
      "until" => self.eval_until(args),

      "get" => self.eval_get(args),
      "set" => self.eval_set(args),

      "==" => self.eval_cmp(args, |l, r| l == r),
      "!=" => self.eval_cmp(args, |l, r| l != r),
      ">" => self.eval_cmp(args, |l, r| l > r),
      ">=" => self.eval_cmp(args, |l, r| l >= r),
      "<" => self.eval_cmp(args, |l, r| l < r),
      "<=" => self.eval_cmp(args, |l, r| l <= r),

      "+" => self.eval_binop(args, Add::add),
      "-" => self.eval_binop(args, Sub::sub),
      "*" => self.eval_binop(args, Mul::mul),
      "/" => self.eval_binop(args, Div::div),

      _ => panic!("invalid token: {:?}", token)
    }
  }

  fn eval_step(&mut self, lines: &[Json]) -> Json {
    let ret = self.eval(lines[0].as_array().unwrap().as_slice());
    if lines.len() == 1 {
      ret
    } else {
      self.eval_step(&lines[1..])
    }
  }

  fn eval_until(&mut self, args: &[Json]) -> Json {
    loop {
      let c = self.eval(args[0].as_array().unwrap().as_slice());
      if c.is_boolean() && c.as_boolean().unwrap() {
        return Json::Null;
      }
      self.eval(args[1].as_array().unwrap().as_slice());
    }
  }

  fn eval_get(&mut self, args: &[Json]) -> Json {
    let key = args[0].as_string().unwrap();
    Json::F64(self.get(key))
  }

  fn eval_set(&mut self, args: &[Json]) -> Json {
    let key = args[0].as_string().unwrap();
    let val = self.substitute(&args[1]);
    self.set(key, val);
    Json::Null
  }

  fn eval_cmp<C>(&mut self, args: &[Json], cmp: C) -> Json
    where C: Fn(f64, f64) -> bool
  {
    let lhs = self.substitute(&args[0]);
    let rhs = self.substitute(&args[1]);
    Json::Boolean(cmp(lhs, rhs))
  }

  fn eval_binop<O>(&mut self, args: &[Json], op: O) -> Json
    where O: Fn(f64, f64) -> f64
  {
    let lhs = self.substitute(&args[0]);
    let rhs = self.substitute(&args[1]);
    Json::F64(op(lhs, rhs))
  }
}

fn parse(source: &str) -> Vec<Json> { Json::from_str(source).unwrap().as_array().unwrap().to_owned() }

fn main() {
  let source = r#"
["step",
  ["set", "i", 10],
  ["set", "sum", 0],
  ["until", ["==", ["get", "i"], 0], [
    "step",
    ["set", "sum", ["+", ["get", "sum"], ["get", "i"]]],
    ["set", "i", ["+", ["get", "i"], -1]]
  ]],
  ["get", "sum"]
]
"#;
  let input = parse(source);

  let mut e = Evaluator::new();

  println!("{:?}", e.eval(input.as_slice()));
}
<commit_msg>replace unnecessary recursition with for-loop<commit_after>extern crate rustc_serialize;
use rustc_serialize::json::Json;
use std::collections::HashMap;

use std::ops::{Add, Sub, Mul, Div};

struct Evaluator(HashMap<String, f64>);

impl Evaluator {
  fn new() -> Evaluator { Evaluator(HashMap::new()) }

  fn get(&self, key: &str) -> f64 { *self.0.get(key).unwrap() }

  fn set(&mut self, key: &str, val: f64) { self.0.insert(key.to_owned(), val); }

  fn substitute(&mut self, expr: &Json) -> f64 {
    match *expr {
      Json::Array(ref arr) => self.eval(arr.as_slice()).as_f64().unwrap(),
      Json::F64(i) => i,
      Json::I64(i) => i as f64,
      Json::U64(i) => i as f64,
      _ => panic!("cannot substitute: {:?} (env: {:?})", expr, self.0)
    }
  }

  fn eval(&mut self, input: &[Json]) -> Json {
    let token = input[0].as_string().unwrap();
    let args = &input[1..];

    match token {
      "step" => self.eval_step(args).unwrap(),
      "until" => self.eval_until(args),

      "get" => self.eval_get(args),
      "set" => self.eval_set(args),

      "==" => self.eval_cmp(args, |l, r| l == r),
      "!=" => self.eval_cmp(args, |l, r| l != r),
      ">" => self.eval_cmp(args, |l, r| l > r),
      ">=" => self.eval_cmp(args, |l, r| l >= r),
      "<" => self.eval_cmp(args, |l, r| l < r),
      "<=" => self.eval_cmp(args, |l, r| l <= r),

      "+" => self.eval_binop(args, Add::add),
      "-" => self.eval_binop(args, Sub::sub),
      "*" => self.eval_binop(args, Mul::mul),
      "/" => self.eval_binop(args, Div::div),

      _ => panic!("invalid token: {:?}", token)
    }
  }

  fn eval_step(&mut self, lines: &[Json]) -> Result<Json, String> {
    let mut ret = Ok(Json::Null);
    for line in lines {
      ret = Ok(self.eval(line.as_array().unwrap().as_slice()));
    }
    ret
  }

  fn eval_until(&mut self, args: &[Json]) -> Json {
    loop {
      let c = self.eval(args[0].as_array().unwrap().as_slice());
      if c.is_boolean() && c.as_boolean().unwrap() {
        return Json::Null;
      }
      self.eval(args[1].as_array().unwrap().as_slice());
    }
  }

  fn eval_get(&mut self, args: &[Json]) -> Json {
    let key = args[0].as_string().unwrap();
    Json::F64(self.get(key))
  }

  fn eval_set(&mut self, args: &[Json]) -> Json {
    let key = args[0].as_string().unwrap();
    let val = self.substitute(&args[1]);
    self.set(key, val);
    Json::Null
  }

  fn eval_cmp<C>(&mut self, args: &[Json], cmp: C) -> Json
    where C: Fn(f64, f64) -> bool
  {
    let lhs = self.substitute(&args[0]);
    let rhs = self.substitute(&args[1]);
    Json::Boolean(cmp(lhs, rhs))
  }

  fn eval_binop<O>(&mut self, args: &[Json], op: O) -> Json
    where O: Fn(f64, f64) -> f64
  {
    let lhs = self.substitute(&args[0]);
    let rhs = self.substitute(&args[1]);
    Json::F64(op(lhs, rhs))
  }
}

fn parse(source: &str) -> Vec<Json> { Json::from_str(source).unwrap().as_array().unwrap().to_owned() }

fn main() {
  let source = r#"
["step",
  ["set", "i", 10],
  ["set", "sum", 0],
  ["until", ["==", ["get", "i"], 0], [
    "step",
    ["set", "sum", ["+", ["get", "sum"], ["get", "i"]]],
    ["set", "i", ["+", ["get", "i"], -1]]
  ]],
  ["get", "sum"]
]
"#;
  let input = parse(source);

  let mut e = Evaluator::new();

  println!("{:?}", e.eval(input.as_slice()));
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate human_name;
extern crate test;

use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use test::Bencher;

fn debug(names: Vec<&str>) {
    for raw in names.iter() {
        let maybe_name = human_name::Name::parse(raw);
        if maybe_name.is_none() {
            println!("!! {}", raw);
            continue;
        }

        let name = maybe_name.unwrap();
        let first: &str = match name.given_name {
            Some(ref given) => { given }
            None => { "[?]" }
        };
        let middle: &str = match name.middle_initials {
            Some(ref initials) => { initials }
            None => { "[?]" }
        };

        println!("{} => {} [{}, {}, {}]", raw, name.display(), name.surname, first, middle);
    }
}

fn main() {

}

#[bench]
fn bench_parsing_first_last(b: &mut Bencher) {
    b.iter(|| {
        let parsed = human_name::Name::parse("Juan Garcia");
        test::black_box(parsed.is_none())
    })
}

#[bench]
fn bench_parsing_sort_order(b: &mut Bencher) {
    b.iter(|| {
        let parsed = human_name::Name::parse("Garcia, J.Q.");
        test::black_box(parsed.is_none())
    })
}

#[bench]
fn bench_parsing_unparseable(b: &mut Bencher) {
    b.iter(|| {
        let parsed = human_name::Name::parse("foo@bar.com");
        test::black_box(parsed.is_none())
    })
}

#[bench]
fn bench_parsing_complex(b: &mut Bencher) {
    b.iter(|| {
        let parsed = human_name::Name::parse("鈴木 Velasquez y Garcia, Dr. Juan Q. 'Don Juan' Xavier III");
        test::black_box(parsed.is_none())
    })
}

#[bench]
fn bench_parsing_many(b: &mut Bencher) {
    let f = File::open("tests/benchmark-names.txt").ok().unwrap();
    let reader = BufReader::new(f);
    let names: Vec<String> = reader.lines().map( |l| l.ok().unwrap() ).collect();

    b.iter(move || {
        let mut valid = 0;
        let mut invalid = 0;

        for name in names.iter() {
            let parsed = human_name::Name::parse(&name);
            if parsed.is_none() {
                invalid += 1;
            } else {
                valid += 1;
            }
        }

        test::black_box(valid);
        test::black_box(invalid);
    })
}
<commit_msg>Move benchmark code into module<commit_after>#![feature(test)]

extern crate human_name;
extern crate test;

fn debug(names: Vec<&str>) {
    for raw in names.iter() {
        let maybe_name = human_name::Name::parse(raw);
        if maybe_name.is_none() {
            println!("!! {}", raw);
            continue;
        }

        let name = maybe_name.unwrap();
        let first: &str = match name.given_name {
            Some(ref given) => { given }
            None => { "[?]" }
        };
        let middle: &str = match name.middle_initials {
            Some(ref initials) => { initials }
            None => { "[?]" }
        };

        println!("{} => {} [{}, {}, {}]", raw, name.display(), name.surname, first, middle);
    }
}

fn main() {

}

#[cfg(test)]
mod bench {
    use std::io::prelude::*;
    use std::io::BufReader;
    use std::fs::File;
    use test::Bencher;
    use test::black_box;
    use human_name::Name;

    #[bench]
    fn bench_parsing_first_last(b: &mut Bencher) {
        b.iter(|| {
            let parsed = Name::parse("Juan Garcia");
            black_box(parsed.is_none())
        })
    }

    #[bench]
    fn bench_parsing_sort_order(b: &mut Bencher) {
        b.iter(|| {
            let parsed = Name::parse("Garcia, J.Q.");
            black_box(parsed.is_none())
        })
    }

    #[bench]
    fn bench_parsing_unparseable(b: &mut Bencher) {
        b.iter(|| {
            let parsed = Name::parse("foo@bar.com");
            black_box(parsed.is_none())
        })
    }

    #[bench]
    fn bench_parsing_complex(b: &mut Bencher) {
        b.iter(|| {
            let parsed = Name::parse("鈴木 Velasquez y Garcia, Dr. Juan Q. 'Don Juan' Xavier III");
            black_box(parsed.is_none())
        })
    }

    #[bench]
    fn bench_parsing_many(b: &mut Bencher) {
        let f = File::open("tests/benchmark-names.txt").ok().unwrap();
        let reader = BufReader::new(f);
        let names: Vec<String> = reader.lines().map( |l| l.ok().unwrap() ).collect();

        b.iter(move || {
            let mut valid = 0;
            let mut invalid = 0;

            for name in names.iter() {
                let parsed = Name::parse(&name);
                if parsed.is_none() {
                    invalid += 1;
                } else {
                    valid += 1;
                }
            }

            black_box(valid);
            black_box(invalid);
        })
    }
}
<|endoftext|>


<commit_before>#![feature(globs)]
extern crate terminal;
extern crate libc;
extern crate serialize;
extern crate collections;
extern crate getopts;

use getopts::{reqopt,getopts};
use std::os;
use std::io::IoResult;
use terminal::{Screen,Vte,ScreenError};
use terminal::c_bits::libtsm::*;
use libc::{c_uint,c_void,size_t,uint32_t};
use std::char::from_u32;
use serialize::{Encodable,Encoder};
use serialize::json;

#[deriving(Show,Copy)]
struct State {
  rendered: Vec<Vec<(String, Attribute)>>
}

#[deriving(Show,Encodable)]
struct CursorState {
  x: u32,
  y: u32,
  visible: bool
}

#[deriving(PartialEq,Show)]
struct Attribute {
  fg: Option<u8>,
  bg: Option<u8>,
  bold: bool,
  underline: bool,
  inverse: bool,
  blink: bool
}

fn main() {
  let args: Vec<String> = os::args();

  let opts = [
      reqopt("h", "height", "the height of the console", "HEIGHT"),
      reqopt("w", "width", "the width of the console", "WIDTH")
  ];
  let matches = match getopts(args.tail(), opts) {
     Ok(m) => { m }
     Err(f) => { fail!(f.to_str()) }
  };
  let width: u32 = from_str(matches.opt_str("w").unwrap().as_slice()).unwrap();
  let height: u32 = from_str(matches.opt_str("h").unwrap().as_slice()).unwrap();

  let (screen, vte) = match setup_screen(width, height) {
    Err(reason) => { fail!("screen setup failed for {}", reason) }
    Ok(v) => v
  };

  match run(screen, vte) {
    Ok(()) => {},
    Err(reason) => { fail!("runloop failed for {}", reason) }
  }
}

fn setup_screen(width: u32, height: u32) -> Result<(Screen,Vte), ScreenError> {
  let screen = try!(Screen::open());
  try!(screen.resize(width,height));
  let vte = try!(screen.vte());
  Ok((screen,vte))
}

fn run(screen: Screen, vte: Vte) -> IoResult<()> {
  let mut stdin = std::io::stdio::stdin();

  loop {
    let line = try!(stdin.read_line());

    match line.as_slice().chars().next() {
      Some('d') => {
        let next_line = try!(stdin.read_line());
        let n: uint = from_str(next_line.as_slice().trim()).expect("d must be followed by int");
        let result = try!(stdin.read_exact(n));
        vte.feed(result.as_slice())
      }
      Some('p') => {
        let mut state = State { rendered: vec![] };
        let state_ptr: *mut c_void = &mut state as *mut _ as *mut c_void;
        screen.draw(draw_cb, state_ptr);
        let encoded = json::encode(&state);
        println!("{}", encoded)
      }
      Some('c') => {
        let (x,y) = screen.cursor_pos();
        let visible = screen.cursor_visible();
        let c_state = CursorState { x: x, y: y, visible: visible };
        let encoded = json::encode(&c_state);
        println!("{}", encoded)
      }
      None => { fail!("empty input!") }
      _ => { fail!("unknown command!") }
    }
  }
}

impl State {
  fn push_if_same(&mut self, ch: char, attr: Attribute) -> bool {
    let current_line  = self.rendered.mut_last().unwrap();
    let current_stream = current_line.mut_last().unwrap();
    if current_stream.ref1() == &attr {
      current_stream.mut0().push_char(ch);
      true
    } else {
      false
    }
  }

  fn push_new_cell(&mut self, ch: char, attr: Attribute) {
    let current_line  = self.rendered.mut_last().unwrap();
    let element = (ch.to_str().to_string(), attr);
    current_line.push(element);
  }
}

impl<S: Encoder<E>, E> Encodable<S, E> for State {
  fn encode(&self, s: &mut S) -> Result<(), E> {
    self.rendered.encode(s)
  }
}

impl Attribute {
  fn new(attr: tsm_screen_attr) -> Attribute {
    Attribute {
      fg: attr.get_fg(),
      bg: attr.get_bg(),
      bold: attr.get_flag(Bold),
      underline: attr.get_flag(Underline),
      inverse: attr.get_flag(Inverse),
      blink: attr.get_flag(Blink)
    }
  }
}

impl<S: Encoder<E>, E> Encodable<S, E> for Attribute {
  fn encode(&self, e: &mut S) -> Result<(), E> {
    let fields_to_emit = vec![self.fg.is_some(), self.bg.is_some(), self.bold, self.underline, self.inverse, self.blink];
    let no_of_fields_to_emit = fields_to_emit.iter().filter(|val| **val).count();

    e.emit_map(no_of_fields_to_emit, |e| {
      let mut key_pos = 0;
      if self.fg.is_some() {
        try!(e.emit_map_elt_key(key_pos, |e| "fg".encode(e)));
        try!(e.emit_map_elt_val(key_pos, |e| self.fg.encode(e)));
        key_pos = key_pos + 1;
      }
      if self.bg.is_some() {
        try!(e.emit_map_elt_key(key_pos, |e| "bg".encode(e)));
        try!(e.emit_map_elt_val(key_pos, |e| self.bg.encode(e)));
        key_pos = key_pos + 1;
      }
      if self.bold {
        try!(e.emit_map_elt_key(key_pos, |e| "bold".encode(e)));
        try!(e.emit_map_elt_val(key_pos, |e| self.bold.encode(e)));
        key_pos = key_pos + 1;
      }
      if self.underline {
        try!(e.emit_map_elt_key(key_pos, |e| "underline".encode(e)));
        try!(e.emit_map_elt_val(key_pos, |e| self.underline.encode(e)));
        key_pos = key_pos + 1;
      }
      if self.inverse {
        try!(e.emit_map_elt_key(key_pos, |e| "inverse".encode(e)));
        try!(e.emit_map_elt_val(key_pos, |e| self.inverse.encode(e)));
        key_pos = key_pos + 1;
      }
      if self.blink {
        try!(e.emit_map_elt_key(key_pos, |e| "blink".encode(e)));
        try!(e.emit_map_elt_val(key_pos, |e| self.blink.encode(e)));
      }

      Ok(())
    })
  }
}

extern "C" fn draw_cb(
  _: *const tsm_screen,
  _: u32,
  ch: *const uint32_t,
  _: size_t,
  _: c_uint,
  _: c_uint,
  posy: c_uint,
  attr: *const tsm_screen_attr,
  _: tsm_age_t,
  data: *mut c_void
) {
  unsafe {
    let data: &mut State = &mut *(data as *mut State);
    let mut current_char;
    let attribute = Attribute::new(*attr);

    if *ch == 0 {
      current_char = ' ';
    } else {
      current_char = from_u32(*ch).unwrap();
    }

    if data.rendered.len() == (posy as uint) {
      data.rendered.push(vec![(current_char.to_str().to_string(), attribute)]);
      return
    }

    let added = data.push_if_same(current_char, attribute);
    if !added {
      data.push_new_cell(current_char, attribute);
    }
  };
}
<commit_msg>Don't crash on EOF<commit_after>#![feature(globs)]
extern crate terminal;
extern crate libc;
extern crate serialize;
extern crate collections;
extern crate getopts;

use getopts::{reqopt,getopts};
use std::os;
use std::io::IoResult;
use std::io::EndOfFile;
use terminal::{Screen,Vte,ScreenError};
use terminal::c_bits::libtsm::*;
use libc::{c_uint,c_void,size_t,uint32_t};
use std::char::from_u32;
use serialize::{Encodable,Encoder};
use serialize::json;

#[deriving(Show,Copy)]
struct State {
  rendered: Vec<Vec<(String, Attribute)>>
}

#[deriving(Show,Encodable)]
struct CursorState {
  x: u32,
  y: u32,
  visible: bool
}

#[deriving(PartialEq,Show)]
struct Attribute {
  fg: Option<u8>,
  bg: Option<u8>,
  bold: bool,
  underline: bool,
  inverse: bool,
  blink: bool
}

fn main() {
  let args: Vec<String> = os::args();

  let opts = [
      reqopt("h", "height", "the height of the console", "HEIGHT"),
      reqopt("w", "width", "the width of the console", "WIDTH")
  ];
  let matches = match getopts(args.tail(), opts) {
     Ok(m) => { m }
     Err(f) => { fail!(f.to_str()) }
  };
  let width: u32 = from_str(matches.opt_str("w").unwrap().as_slice()).unwrap();
  let height: u32 = from_str(matches.opt_str("h").unwrap().as_slice()).unwrap();

  let (screen, vte) = match setup_screen(width, height) {
    Err(reason) => { fail!("screen setup failed for {}", reason) }
    Ok(v) => v
  };

  match run(screen, vte) {
    Ok(()) => {},
    Err(reason) => {
      if !(reason.kind == EndOfFile) {
        fail!("runloop failed for {}", reason)
      }
    }
  }
}

fn setup_screen(width: u32, height: u32) -> Result<(Screen,Vte), ScreenError> {
  let screen = try!(Screen::open());
  try!(screen.resize(width,height));
  let vte = try!(screen.vte());
  Ok((screen,vte))
}

fn run(screen: Screen, vte: Vte) -> IoResult<()> {
  let mut stdin = std::io::stdio::stdin();

  loop {
    let line = try!(stdin.read_line());

    match line.as_slice().chars().next() {
      Some('d') => {
        let next_line = try!(stdin.read_line());
        let n: uint = from_str(next_line.as_slice().trim()).expect("d must be followed by int");
        let result = try!(stdin.read_exact(n));
        vte.feed(result.as_slice())
      }
      Some('p') => {
        let mut state = State { rendered: vec![] };
        let state_ptr: *mut c_void = &mut state as *mut _ as *mut c_void;
        screen.draw(draw_cb, state_ptr);
        let encoded = json::encode(&state);
        println!("{}", encoded)
      }
      Some('c') => {
        let (x,y) = screen.cursor_pos();
        let visible = screen.cursor_visible();
        let c_state = CursorState { x: x, y: y, visible: visible };
        let encoded = json::encode(&c_state);
        println!("{}", encoded)
      }
      None => { fail!("empty input!") }
      _ => { fail!("unknown command!") }
    }
  }
}

impl State {
  fn push_if_same(&mut self, ch: char, attr: Attribute) -> bool {
    let current_line  = self.rendered.mut_last().unwrap();
    let current_stream = current_line.mut_last().unwrap();
    if current_stream.ref1() == &attr {
      current_stream.mut0().push_char(ch);
      true
    } else {
      false
    }
  }

  fn push_new_cell(&mut self, ch: char, attr: Attribute) {
    let current_line  = self.rendered.mut_last().unwrap();
    let element = (ch.to_str().to_string(), attr);
    current_line.push(element);
  }
}

impl<S: Encoder<E>, E> Encodable<S, E> for State {
  fn encode(&self, s: &mut S) -> Result<(), E> {
    self.rendered.encode(s)
  }
}

impl Attribute {
  fn new(attr: tsm_screen_attr) -> Attribute {
    Attribute {
      fg: attr.get_fg(),
      bg: attr.get_bg(),
      bold: attr.get_flag(Bold),
      underline: attr.get_flag(Underline),
      inverse: attr.get_flag(Inverse),
      blink: attr.get_flag(Blink)
    }
  }
}

impl<S: Encoder<E>, E> Encodable<S, E> for Attribute {
  fn encode(&self, e: &mut S) -> Result<(), E> {
    let fields_to_emit = vec![self.fg.is_some(), self.bg.is_some(), self.bold, self.underline, self.inverse, self.blink];
    let no_of_fields_to_emit = fields_to_emit.iter().filter(|val| **val).count();

    e.emit_map(no_of_fields_to_emit, |e| {
      let mut key_pos = 0;
      if self.fg.is_some() {
        try!(e.emit_map_elt_key(key_pos, |e| "fg".encode(e)));
        try!(e.emit_map_elt_val(key_pos, |e| self.fg.encode(e)));
        key_pos = key_pos + 1;
      }
      if self.bg.is_some() {
        try!(e.emit_map_elt_key(key_pos, |e| "bg".encode(e)));
        try!(e.emit_map_elt_val(key_pos, |e| self.bg.encode(e)));
        key_pos = key_pos + 1;
      }
      if self.bold {
        try!(e.emit_map_elt_key(key_pos, |e| "bold".encode(e)));
        try!(e.emit_map_elt_val(key_pos, |e| self.bold.encode(e)));
        key_pos = key_pos + 1;
      }
      if self.underline {
        try!(e.emit_map_elt_key(key_pos, |e| "underline".encode(e)));
        try!(e.emit_map_elt_val(key_pos, |e| self.underline.encode(e)));
        key_pos = key_pos + 1;
      }
      if self.inverse {
        try!(e.emit_map_elt_key(key_pos, |e| "inverse".encode(e)));
        try!(e.emit_map_elt_val(key_pos, |e| self.inverse.encode(e)));
        key_pos = key_pos + 1;
      }
      if self.blink {
        try!(e.emit_map_elt_key(key_pos, |e| "blink".encode(e)));
        try!(e.emit_map_elt_val(key_pos, |e| self.blink.encode(e)));
      }

      Ok(())
    })
  }
}

extern "C" fn draw_cb(
  _: *const tsm_screen,
  _: u32,
  ch: *const uint32_t,
  _: size_t,
  _: c_uint,
  _: c_uint,
  posy: c_uint,
  attr: *const tsm_screen_attr,
  _: tsm_age_t,
  data: *mut c_void
) {
  unsafe {
    let data: &mut State = &mut *(data as *mut State);
    let mut current_char;
    let attribute = Attribute::new(*attr);

    if *ch == 0 {
      current_char = ' ';
    } else {
      current_char = from_u32(*ch).unwrap();
    }

    if data.rendered.len() == (posy as uint) {
      data.rendered.push(vec![(current_char.to_str().to_string(), attribute)]);
      return
    }

    let added = data.push_if_same(current_char, attribute);
    if !added {
      data.push_new_cell(current_char, attribute);
    }
  };
}
<|endoftext|>


<commit_before>// disable warnings for dead code when running debug
#![cfg_attr(debug_assertions, allow(dead_code))]

extern crate net2;
extern crate bincode;
extern crate rustc_serialize;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate byteorder;

use std::net::{Ipv4Addr, Ipv6Addr};
#[cfg(not(windows))]
use net2::unix::UnixUdpBuilderExt;
use net2::UdpBuilder;
use bincode::rustc_serialize::decode;
use byteorder::{ByteOrder, NetworkEndian};

#[repr(C)]
#[repr(packed)]
#[derive(Default)]
#[derive(Debug)]
#[derive(RustcEncodable, RustcDecodable)]
struct MDNSPacketHeader {
    id: u16, // transaction ID
    flags: u16,
    num_qn: u16,
    num_ans_rr: u16,
    num_auth_rr: u16,
    num_add_rr: u16,
}

#[derive(Debug)]
enum MDNSType {
    A(Ipv4Addr),
    PTR(String),
    TXT(Vec<String>),
    AAAA(Ipv6Addr),
    // SRV,
    // NSEC,
    // ANY,
    UNKNOW(u16),
}

impl MDNSType {
    #[doc(hidden)]
    pub fn to_u16(&self) -> u16 {
        match *self {
            MDNSType::A(_) => 0x01,
            MDNSType::PTR(_) => 0x0C,
            MDNSType::TXT(_) => 0x10,
            MDNSType::AAAA(_) => 0x1C,
            // MDNSType::SRV => 0x21,
            // MDNSType::NSEC => 0x2F,
            // MDNSType::ANY => 0xFF,
            MDNSType::UNKNOW(n) => n,
        }
    }

    pub fn from_data(mdns_type_id: u16,
                     full_packet: &[u8],
                     data_len: usize,
                     offset: usize)
                     -> Result<MDNSType, String> {
        match mdns_type_id {
            0x10 => {
                let mut txt_map = vec![];
                let mut data_offset: usize = 0;
                while data_len > data_offset {
                    let (label_string, label_size) = label_to_string(full_packet,
                                                                     offset + data_offset);
                    trace!("TXT: {} {}", label_string, label_size);
                    txt_map.push(label_string);
                    data_offset += label_size;
                }
                trace!("{:?}", txt_map);
                Ok(MDNSType::TXT(txt_map))
            }
            0x01 => {
                if data_len < 4 {
                    return Err("Data section to small for IPV4 address".to_owned());
                }

                let ip = NetworkEndian::read_u32(&full_packet[offset..(offset + 4)]);
                let address = Ipv4Addr::new(((ip >> 24) & 0xFF) as u8,
                                            ((ip >> 16) & 0xFF) as u8,
                                            ((ip >> 8) & 0xFF) as u8,
                                            (ip & 0xFF) as u8);

                Ok(MDNSType::A(address))
            }
            0x1C => {
                if data_len < (8 * 2) {
                    return Err("Data section to small for IPV6 address".to_owned());
                }

                let mut ipv6_octets = [0u16; 8];
                for ip_index in 0..8 {
                    ipv6_octets[ip_index] =
                        NetworkEndian::read_u16(&full_packet[(offset+(ip_index * 2))..(offset +((ip_index + 1) * 2))]);

                }

                Ok(MDNSType::AAAA(Ipv6Addr::new(ipv6_octets[0],
                                                ipv6_octets[1],
                                                ipv6_octets[2],
                                                ipv6_octets[3],
                                                ipv6_octets[4],
                                                ipv6_octets[5],
                                                ipv6_octets[6],
                                                ipv6_octets[7])))
            }
            0x0C => Ok(MDNSType::PTR(decompress_label(full_packet, offset).0)),
            _ => Ok(MDNSType::UNKNOW(mdns_type_id)),
        }
    }
}

#[derive(Debug)]
struct MDNSData {
    id: u16,
    flags: u16,
    questions: Vec<MDNSQuestion>,
    answers: Vec<MDNSAnswer>,
}

#[derive(Debug)]
struct MDNSQuestion {
    name: String,
    rr_type_id: u16,
    rr_class: u16,
}

#[derive(Debug)]
struct MDNSAnswer {
    name: String,
    rr_type: MDNSType,
    rr_class: u16,
    ttl: u32,
}

#[inline]
fn label_to_string(packet: &[u8], offset: usize) -> (String, usize) {
    let string_size = packet[offset] as usize;

    let full_string = String::from_utf8_lossy(&packet[(offset + 1)..(offset + 1 + string_size)])
        .into_owned();

    (full_string, string_size + 1)
}

fn decompress_label(packet: &[u8], mut offset: usize) -> (String, usize) {
    // create the string
    let mut full_string = String::new();
    // second offset to let the caller know how much we moved
    // from the current offset
    let mut label_offset = 0;

    // helper that gets true as soon as we have hit a compress token
    // the label_offset calculation is different when we have have
    // a commpressed label
    let mut compressed = false;

    // Now go until we found a string with ZERO length
    while 0 != packet[offset] {
        // if this is not the first string we have found,
        // add a . to join them
        if full_string.len() > 0 {
            full_string.push('.');
        }

        trace!("size buffer: {:?}", &packet[offset..(offset + 2)]);

        // is this a compressed token?
        if 0xC0 == (packet[offset] & 0xC0) {
            // yes
            if false == compressed {
                compressed = true;
                // we have moved 2 bytes from the current position in memory
                label_offset += 2;
            }

            // now the second byte after the token
            // is the lower size of the uint16 offset
            // from the packet start!!!
            let small_size = packet[offset + 1] as usize;
            trace!("In BIG SIZE: {}", small_size);

            // get the higher size
            offset = (packet[offset] & 0x3F) as usize;
            trace!("In BIG SIZE_1: {}", offset);

            // shift 8 bits to the left
            offset *= 256;
            trace!("In BIG SIZE_2: {}", offset);

            // add the lower part
            offset += small_size;
        }

        // get size of the string
        let string_size = packet[offset] as usize;
        // jump over the size byte
        offset += 1;

        trace!("Before UTF8_2: {} {}", offset, string_size);
        trace!("Before UTF8: {:?}", &packet[offset..(offset + string_size)]);

        // now convert the bytes to a string
        // TODO: UTF8???? Or ASCII?
        full_string += std::str::from_utf8(&packet[offset..(offset + string_size)]).unwrap();

        // move to the next token
        offset += string_size;

        if false == compressed {
            // if we haven't had a compress token yet
            // just a the size byte and the string length
            label_offset += string_size;
            label_offset += 1;
        }
    }

    // skip the last ZERO byte indicating the end of the string
    if false == compressed {
        // but only if we have NO compressed string
        label_offset += 1;
    }

    trace!("{:?} {}", full_string, label_offset);

    // done, return the string and the offset we moved
    // in memory to get the String
    (full_string, label_offset)
}

fn parse_packet(packet: &[u8]) -> Result<MDNSData, String> {
    let decoded: MDNSPacketHeader = try!(decode(&packet[0..12]).map_err(|e| e.to_string()));

    let mut result = MDNSData {
        id: decoded.id,
        flags: decoded.flags,
        questions: vec![],
        answers: vec![],
    };

    let mut decode_position = std::mem::size_of::<MDNSPacketHeader>();

    // parse the questions
    for _ in 0..decoded.num_qn {
        // first read the label
        let (label_string, label_offset) = decompress_label(packet, decode_position);
        // move the offset
        decode_position += label_offset;

        // now read the uint16 type
        let rr_type = NetworkEndian::read_u16(&packet[decode_position..(decode_position + 2)]);
        decode_position += 2;
        // and the class (uint16)
        let class_type = NetworkEndian::read_u16(&packet[decode_position..(decode_position + 2)]);
        decode_position += 2;

        // Add the create and push the question struct
        result.questions.push(MDNSQuestion {
            name: label_string,
            rr_type_id: rr_type,
            rr_class: class_type,
        });
    }

    for _ in 0..decoded.num_ans_rr {
        // first read the label
        let (label_string, label_offset) = decompress_label(packet, decode_position);
        // move the offset
        decode_position += label_offset;

        // now read the uint16 type
        let rr_type = NetworkEndian::read_u16(&packet[decode_position..(decode_position + 2)]);
        decode_position += 2;
        // and the class (uint16)
        let class_type = NetworkEndian::read_u16(&packet[decode_position..(decode_position + 2)]);
        decode_position += 2;

        let ttl = NetworkEndian::read_u32(&packet[decode_position..(decode_position + 4)]);
        decode_position += 4;

        // RR data
        let data_len =
            NetworkEndian::read_u16(&packet[decode_position..(decode_position + 2)]) as usize;
        decode_position += 2;

        trace!("Data len: {}, type: {:x}", data_len, rr_type);

        match MDNSType::from_data(rr_type, packet, data_len, decode_position) {
            Ok(mdns_type) => {

                // Add the create and push the question struct
                result.answers.push(MDNSAnswer {
                    name: label_string,
                    rr_type: mdns_type,
                    rr_class: class_type,
                    ttl: ttl,
                });
            }
            Err(e) => {
                warn!("{}", e);
            }
        }

        decode_position += data_len;

    }

    debug!("{:?}", decoded);

    Ok(result)
}

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

    let udp_builder = UdpBuilder::new_v4().unwrap();

    match udp_builder.reuse_address(true) {
        Ok(s) => s,
        Err(e) => panic!("couldn't reuse_address: {}", e),
    };

    match udp_builder.reuse_port(true) {
        Ok(s) => s,
        Err(e) => panic!("couldn't reuse_address: {}", e),
    };

    let udp_socket = match udp_builder.bind("224.0.0.251:5353") {
        Ok(s) => s,
        Err(e) => panic!("couldn't bind: {}", e),
    };

    let ip_mdns = Ipv4Addr::new(224, 0, 0, 251);
    let ip_any = Ipv4Addr::new(0, 0, 0, 0);

    match udp_socket.join_multicast_v4(&ip_mdns, &ip_any) {
        Ok(s) => s,
        Err(e) => panic!("couldn't join_multicast_v4: {}", e),
    };

    match udp_socket.set_multicast_loop_v4(true) {
        Ok(s) => s,
        Err(e) => panic!("couldn't set_multicast_loop_v4: {}", e),
    };

    info!("start reading");

    loop {
        // 	let mut read_packet: mdns_packet = Default::default();
        let mut byte_array = [0u8; 65536];

        let (amt, _) = udp_socket.recv_from(&mut byte_array).unwrap();
        // println!("{:?} {:?}", amt, src);

        if let Ok(mdns_data) = parse_packet(&byte_array[0..amt]) {
            debug!("{:?}", mdns_data);
        }
    }
}
<commit_msg>Added SRV parsing<commit_after>// disable warnings for dead code when running debug
#![cfg_attr(debug_assertions, allow(dead_code))]

extern crate net2;
extern crate bincode;
extern crate rustc_serialize;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate byteorder;

use std::net::{Ipv4Addr, Ipv6Addr};
#[cfg(not(windows))]
use net2::unix::UnixUdpBuilderExt;
use net2::UdpBuilder;
use bincode::rustc_serialize::decode;
use byteorder::{ByteOrder, NetworkEndian};

#[repr(C)]
#[repr(packed)]
#[derive(Default)]
#[derive(Debug)]
#[derive(RustcEncodable, RustcDecodable)]
struct MDNSPacketHeader {
    id: u16,
    flags: u16,
    num_qn: u16,
    num_ans_rr: u16,
    num_auth_rr: u16,
    num_add_rr: u16,
}

#[derive(Debug)]
struct MDNSService {
    priority: u16,
    weight: u16,
    port: u16,
    name: String,
}

#[derive(Debug)]
enum MDNSType {
    A(Ipv4Addr),
    PTR(String), // CNAME, NS ?
    TXT(Vec<String>),
    AAAA(Ipv6Addr),
    SRV(MDNSService),
    // NSEC,
    // ANY,
    UNKNOW(u16),
}

impl MDNSType {
    #[doc(hidden)]
    pub fn to_u16(&self) -> u16 {
        match *self {
            MDNSType::A(_) => 0x01,
            MDNSType::PTR(_) => 0x0C,
            MDNSType::TXT(_) => 0x10,
            MDNSType::AAAA(_) => 0x1C,
            MDNSType::SRV(_) => 0x21,
            // MDNSType::NSEC => 0x2F,
            // MDNSType::ANY => 0xFF,
            MDNSType::UNKNOW(n) => n,
        }
    }

    pub fn from_data(mdns_type_id: u16,
                     full_packet: &[u8],
                     data_len: usize,
                     offset: usize)
                     -> Result<MDNSType, String> {
        match mdns_type_id {
            0x10 => {
                let mut txt_map = vec![];
                let mut data_offset: usize = 0;
                while data_len > data_offset {
                    let (label_string, label_size) = label_to_string(full_packet,
                                                                     offset + data_offset);
                    trace!("TXT: {} {}", label_string, label_size);
                    txt_map.push(label_string);
                    data_offset += label_size;
                }
                trace!("{:?}", txt_map);
                Ok(MDNSType::TXT(txt_map))
            }

            0x01 => {
                if data_len < 4 {
                    return Err("Data section to small for IPV4 address".to_owned());
                }

                let ip = NetworkEndian::read_u32(&full_packet[offset..(offset + 4)]);
                let address = Ipv4Addr::new(((ip >> 24) & 0xFF) as u8,
                                            ((ip >> 16) & 0xFF) as u8,
                                            ((ip >> 8) & 0xFF) as u8,
                                            (ip & 0xFF) as u8);

                Ok(MDNSType::A(address))
            }

            0x1C => {
                if data_len < (8 * 2) {
                    return Err("Data section to small for IPV6 address".to_owned());
                }

                let mut ipv6_octets = [0u16; 8];
                for ip_index in 0..8 {
                    ipv6_octets[ip_index] =
                        NetworkEndian::read_u16(&full_packet[(offset+(ip_index * 2))..(offset +((ip_index + 1) * 2))]);

                }

                Ok(MDNSType::AAAA(Ipv6Addr::new(ipv6_octets[0],
                                                ipv6_octets[1],
                                                ipv6_octets[2],
                                                ipv6_octets[3],
                                                ipv6_octets[4],
                                                ipv6_octets[5],
                                                ipv6_octets[6],
                                                ipv6_octets[7])))
            }
            0x0C => Ok(MDNSType::PTR(decompress_label(full_packet, offset).0)),

            0x21 => {
                Ok(MDNSType::SRV(MDNSService {
                    priority: NetworkEndian::read_u16(&full_packet[offset..(offset + 2)]),
                    weight: NetworkEndian::read_u16(&full_packet[(offset + 2)..(offset + 4)]),
                    port: NetworkEndian::read_u16(&full_packet[(offset + 4)..(offset + 6)]),
                    name: decompress_label(full_packet, offset + 6).0,
                }))
            }

            _ => Ok(MDNSType::UNKNOW(mdns_type_id)),
        }
    }
}

#[derive(Debug)]
struct MDNSData {
    id: u16,
    flags: u16,
    questions: Vec<MDNSQuestion>,
    answers: Vec<MDNSAnswer>,
}

#[derive(Debug)]
struct MDNSQuestion {
    name: String,
    rr_type_id: u16,
    rr_class: u16,
}

#[derive(Debug)]
struct MDNSAnswer {
    name: String,
    rr_type: MDNSType,
    rr_class: u16,
    ttl: u32,
}

#[inline]
fn label_to_string(packet: &[u8], offset: usize) -> (String, usize) {
    let string_size = packet[offset] as usize;

    let full_string = String::from_utf8_lossy(&packet[(offset + 1)..(offset + 1 + string_size)])
        .into_owned();

    (full_string, string_size + 1)
}

fn decompress_label(packet: &[u8], mut offset: usize) -> (String, usize) {
    // create the string
    let mut full_string = String::new();
    // second offset to let the caller know how much we moved
    // from the current offset
    let mut label_offset = 0;

    // helper that gets true as soon as we have hit a compress token
    // the label_offset calculation is different when we have have
    // a commpressed label
    let mut compressed = false;

    // Now go until we found a string with ZERO length
    while 0 != packet[offset] {
        // if this is not the first string we have found,
        // add a . to join them
        if full_string.len() > 0 {
            full_string.push('.');
        }

        trace!("size buffer: {:?}", &packet[offset..(offset + 2)]);

        // is this a compressed token?
        if 0xC0 == (packet[offset] & 0xC0) {
            // yes
            if false == compressed {
                compressed = true;
                // we have moved 2 bytes from the current position in memory
                label_offset += 2;
            }

            // now the second byte after the token
            // is the lower size of the uint16 offset
            // from the packet start!!!
            let small_size = packet[offset + 1] as usize;
            trace!("In BIG SIZE: {}", small_size);

            // get the higher size
            offset = (packet[offset] & 0x3F) as usize;
            trace!("In BIG SIZE_1: {}", offset);

            // shift 8 bits to the left
            offset *= 256;
            trace!("In BIG SIZE_2: {}", offset);

            // add the lower part
            offset += small_size;
        }

        // get size of the string
        let string_size = packet[offset] as usize;
        // jump over the size byte
        offset += 1;

        trace!("Before UTF8_2: {} {}", offset, string_size);
        trace!("Before UTF8: {:?}", &packet[offset..(offset + string_size)]);

        // now convert the bytes to a string
        // TODO: UTF8???? Or ASCII?
        full_string += std::str::from_utf8(&packet[offset..(offset + string_size)]).unwrap();

        // move to the next token
        offset += string_size;

        if false == compressed {
            // if we haven't had a compress token yet
            // just a the size byte and the string length
            label_offset += string_size;
            label_offset += 1;
        }
    }

    // skip the last ZERO byte indicating the end of the string
    if false == compressed {
        // but only if we have NO compressed string
        label_offset += 1;
    }

    trace!("{:?} {}", full_string, label_offset);

    // done, return the string and the offset we moved
    // in memory to get the String
    (full_string, label_offset)
}

fn parse_packet(packet: &[u8]) -> Result<MDNSData, String> {
    let decoded: MDNSPacketHeader = try!(decode(&packet[0..12]).map_err(|e| e.to_string()));

    let mut result = MDNSData {
        id: decoded.id,
        flags: decoded.flags,
        questions: vec![],
        answers: vec![],
    };

    let mut decode_position = std::mem::size_of::<MDNSPacketHeader>();

    // parse the questions
    for _ in 0..decoded.num_qn {
        // first read the label
        let (label_string, label_offset) = decompress_label(packet, decode_position);
        // move the offset
        decode_position += label_offset;

        // now read the uint16 type
        let rr_type = NetworkEndian::read_u16(&packet[decode_position..(decode_position + 2)]);
        decode_position += 2;
        // and the class (uint16)
        let class_type = NetworkEndian::read_u16(&packet[decode_position..(decode_position + 2)]);
        decode_position += 2;

        // Add the create and push the question struct
        result.questions.push(MDNSQuestion {
            name: label_string,
            rr_type_id: rr_type,
            rr_class: class_type,
        });
    }

    for _ in 0..decoded.num_ans_rr {
        // first read the label
        let (label_string, label_offset) = decompress_label(packet, decode_position);
        // move the offset
        decode_position += label_offset;

        // now read the uint16 type
        let rr_type = NetworkEndian::read_u16(&packet[decode_position..(decode_position + 2)]);
        decode_position += 2;
        // and the class (uint16)
        let class_type = NetworkEndian::read_u16(&packet[decode_position..(decode_position + 2)]);
        decode_position += 2;

        let ttl = NetworkEndian::read_u32(&packet[decode_position..(decode_position + 4)]);
        decode_position += 4;

        // RR data
        let data_len =
            NetworkEndian::read_u16(&packet[decode_position..(decode_position + 2)]) as usize;
        decode_position += 2;

        trace!("Data len: {}, type: {:x}", data_len, rr_type);

        match MDNSType::from_data(rr_type, packet, data_len, decode_position) {
            Ok(mdns_type) => {

                // Add the create and push the question struct
                result.answers.push(MDNSAnswer {
                    name: label_string,
                    rr_type: mdns_type,
                    rr_class: class_type,
                    ttl: ttl,
                });
            }
            Err(e) => {
                warn!("{}", e);
            }
        }

        decode_position += data_len;

    }

    debug!("{:?}", decoded);

    Ok(result)
}

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

    let udp_builder = UdpBuilder::new_v4().unwrap();

    match udp_builder.reuse_address(true) {
        Ok(s) => s,
        Err(e) => panic!("couldn't reuse_address: {}", e),
    };

    match udp_builder.reuse_port(true) {
        Ok(s) => s,
        Err(e) => panic!("couldn't reuse_address: {}", e),
    };

    let udp_socket = match udp_builder.bind("224.0.0.251:5353") {
        Ok(s) => s,
        Err(e) => panic!("couldn't bind: {}", e),
    };

    let ip_mdns = Ipv4Addr::new(224, 0, 0, 251);
    let ip_any = Ipv4Addr::new(0, 0, 0, 0);

    match udp_socket.join_multicast_v4(&ip_mdns, &ip_any) {
        Ok(s) => s,
        Err(e) => panic!("couldn't join_multicast_v4: {}", e),
    };

    match udp_socket.set_multicast_loop_v4(true) {
        Ok(s) => s,
        Err(e) => panic!("couldn't set_multicast_loop_v4: {}", e),
    };

    info!("start reading");

    loop {
        // 	let mut read_packet: mdns_packet = Default::default();
        let mut byte_array = [0u8; 65536];

        let (amt, _) = udp_socket.recv_from(&mut byte_array).unwrap();
        // println!("{:?} {:?}", amt, src);

        if let Ok(mdns_data) = parse_packet(&byte_array[0..amt]) {
            debug!("{:?}", mdns_data);
        }
    }
}
<|endoftext|>


<commit_before>#![feature(advanced_slice_patterns, slice_patterns, convert)]

extern crate argparse;
extern crate yaml;
extern crate term;

use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use std::fmt;

use yaml::constructor::*;
use yaml::constructor::YamlStandardData::{YamlMapping, YamlString, YamlInteger};

use argparse::{ArgumentParser, List};

struct Season {
    num: isize,
    matches: Vec<Match>,
}

impl Season {
    fn new(num: isize, matches: Vec<Match>) -> Season {
        Season { num: num, matches: matches }
    }

    fn winrate(&self) -> f32 {
        let wins: Vec<&Match> = self.matches.iter()
            .filter(|m| m.result == MatchResult::Win).collect();

        let total   = self.matches.len() as f32;
        let winrate = (wins.len() as f32) / total * 100.0;

        winrate
    }

    fn winrate_by_deck(&self, name: &String, class: &String) -> f32 {
        let deck = lowercase(&format!("{} {}", name, class));

        let dms: Vec<&Match> = self.matches.iter()
            .filter(|m| lowercase(&m.deck) == deck).collect();

        let wins: Vec<&&Match> = dms.iter()
            .filter(|m| m.result == MatchResult::Win).collect();

        let total   = dms.len() as f32;
        let winrate = (wins.len() as f32) / total * 100.0;

        winrate
    }
}

struct Match {
    id: isize,
    deck: String,
    opponent: String,
    result: MatchResult,
    kind: MatchType,
}

impl Match {
    fn new(id: isize) -> Match {
        Match { id:       id,
                deck:     String::new(),
                opponent: String::new(),
                result:   MatchResult::Win,
                kind:     MatchType::Casual }
    }
}

impl fmt::Display for Season {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut t = term::stdout().unwrap();
        writeln!(f, "{}", format!("Season {}", self.num));

        for m in &self.matches {
            if m.result == MatchResult:: Win {
                t.fg(term::color::GREEN).unwrap();
            } else {
                t.fg(term::color::RED).unwrap();
            }

            writeln!(f, "{}",
                format!(" {}) {} vs {} \t\t{}",
                    m.id, m.deck, m.opponent, m.kind));

            t.reset().unwrap();
        }

        writeln!(f, "{}", "")
    }
}

#[derive(PartialEq, Eq)]
enum MatchResult {
    Win,
    Loss,
}

impl fmt::Display for MatchResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = match self {
            &MatchResult::Win  => "Win",
            &MatchResult::Loss => "Loss",
        };

        write!(f, "{}", s)
    }
}

enum MatchType {
    Ranked,
    Casual,
    Friendly,
}

impl fmt::Display for MatchType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = match self {
            &MatchType::Ranked   => "Rankend",
            &MatchType::Casual   => "Casual",
            &MatchType::Friendly => "Friendly",
        };

        write!(f, "{}", s)
    }
}

fn parse_seasons(map: &Vec<(YamlStandardData, YamlStandardData)>) -> Result<Vec<Season>, &'static str> {
    let mut seasons: Vec<Season> = Vec::new();

    match map.as_slice() {
        [(YamlString(ref name), YamlMapping(ref map))] => {
            let mut matches: Vec<Match>  = Vec::new();

            for m in map.as_slice() {
                match m {
                    &(YamlInteger(ref id), YamlMapping(ref content)) =>
                        matches.push(parse_match(*id, content)),

                    _ => continue,
                }
            }

            let s_name = name.to_string();
            let temp: Vec<&str> = s_name.split(' ').collect();
            let season_num = temp[1].to_string().parse::<isize>().unwrap();

            seasons.push(Season::new(season_num, matches));
            Ok(seasons)
        },

        _ => Err("Error"),
    }
}

fn lowercase(s: &String) -> String {
    s.chars().map(|c| c.to_lowercase().next().unwrap()).collect::<String>()
}

fn capitalize(s: &String) -> String {
    s.chars().enumerate()
        .map(|(i, c)| if i == 0 {
                c.to_uppercase().next().unwrap()
            } else {
                c.to_lowercase().next().unwrap()
            }).collect::<String>()
}

fn parse_match(id: isize, map: &Vec<(YamlStandardData, YamlStandardData)>) -> Match {
    let mut m = Match::new(id);

    for e in map.as_slice() {
        match e {
            &(YamlString(ref key), YamlString(ref value)) =>
                match key.as_str() {
                    "deck"     => m.deck     = value.trim().to_string(),
                    "opponent" => m.opponent = value.trim().to_string(),
                    "result"   =>
                        match value.as_str() {
                            "Win"  => m.result = MatchResult::Win,
                            "Loss" => m.result = MatchResult::Loss,
                            _      => continue,
                        },
                    "type"     =>
                        match value.as_str() {
                            "Ranked"   => m.kind = MatchType::Ranked,
                            "Casual"   => m.kind = MatchType::Casual,
                            "Friendly" => m.kind = MatchType::Friendly,
                            _          => continue,
                        },
                    _ => continue,
                },

            _ => continue
        }
    }

    m
}

fn parse(data: Vec<YamlStandardData>) -> Result<Vec<Season>, &'static str> {
    for doc in data.iter() {
        match doc {
            &YamlMapping(ref map) => return parse_seasons(map),

            _ => return Err("No docs"),
        }
    }

    Err("No docs")
}

fn main() {
    let path = "hearthstone.yaml";

    let mut args: Vec<String> = Vec::new();

    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Calc HS stats");
        ap.refer(&mut args)
            .add_argument("args", List,
                          "Deck to calc winrate for");
        ap.parse_args_or_exit();
    }

    let mut reader = BufReader::new(File::open(path).unwrap());
    let data = yaml::parse_io_utf8(&mut reader).unwrap();

    let seasons = parse(data).unwrap();

    if args.len() >= 1 {
        let season = seasons.last().unwrap();

        match args[0].as_str() {
            "deck" => {
                let deck   = &args[1..3];
                let name   = deck[0].to_string();
                let class  = deck[1].to_string();

                println!("{} {} Winrate: {}%", capitalize(&name),
                    capitalize(&class), season.winrate_by_deck(&name, &class));
            },

            "show" => {
                print!("{}", season);
                println!("Total Winrate: {}%", season.winrate());
            },

            _ => println!("Command unknown"),
        }
    }
}
<commit_msg>better stats by deck<commit_after>#![feature(advanced_slice_patterns, slice_patterns, convert)]

extern crate argparse;
extern crate yaml;
extern crate term;

use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use std::fmt;

use yaml::constructor::*;
use yaml::constructor::YamlStandardData::{YamlMapping, YamlString, YamlInteger};

use argparse::{ArgumentParser, List};

struct Season {
    num: isize,
    matches: Vec<Match>,
}

impl Season {
    fn new(num: isize, matches: Vec<Match>) -> Season {
        Season { num: num, matches: matches }
    }

    fn winrate(&self) -> f32 {
        let wins: Vec<&Match> = self.matches.iter()
            .filter(|m| m.result == MatchResult::Win).collect();

        let total   = self.matches.len() as f32;
        let winrate = (wins.len() as f32) / total * 100.0;

        winrate
    }

    fn deck(&self, name: &String, class: &String) -> (Vec<&Match>, f32)  {
        let deck = lowercase(&format!("{} {}", name, class));

        let dms: Vec<&Match> = self.matches.iter()
            .filter(|m| lowercase(&m.deck) == deck).collect();

        let wins: Vec<&&Match> = dms.iter()
            .filter(|m| m.result == MatchResult::Win).collect();

        let total   = dms.len() as f32;
        let winrate = (wins.len() as f32) / total * 100.0;

        (dms.clone(), winrate)
    }
}

impl fmt::Display for Season {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut t = term::stdout().unwrap();
        writeln!(f, "{}", format!("Season {}", self.num));

        for m in &self.matches {

            writeln!(f, "{}", m);

        }

        writeln!(f, "{}", "")
    }
}

struct Match {
    id: isize,
    deck: String,
    opponent: String,
    result: MatchResult,
    kind: MatchType,
}

impl Match {
    fn new(id: isize) -> Match {
        Match { id:       id,
                deck:     String::new(),
                opponent: String::new(),
                result:   MatchResult::Win,
                kind:     MatchType::Casual }
    }
}

impl fmt::Display for Match {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut t = term::stdout().unwrap();

        if self.result == MatchResult:: Win {
            t.fg(term::color::GREEN).unwrap();
        } else {
            t.fg(term::color::RED).unwrap();
        }

        write!(f, "{}",
            format!(" {}) {} vs {} \t\t{}",
                self.id, self.deck, self.opponent, self.kind));

        t.reset().unwrap();

        write!(f, "{}", "")
    }
}

#[derive(PartialEq, Eq)]
enum MatchResult {
    Win,
    Loss,
}

impl fmt::Display for MatchResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = match self {
            &MatchResult::Win  => "Win",
            &MatchResult::Loss => "Loss",
        };

        write!(f, "{}", s)
    }
}

enum MatchType {
    Ranked,
    Casual,
    Friendly,
}

impl fmt::Display for MatchType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = match self {
            &MatchType::Ranked   => "Rankend",
            &MatchType::Casual   => "Casual",
            &MatchType::Friendly => "Friendly",
        };

        write!(f, "{}", s)
    }
}

fn parse_seasons(map: &Vec<(YamlStandardData, YamlStandardData)>) -> Result<Vec<Season>, &'static str> {
    let mut seasons: Vec<Season> = Vec::new();

    match map.as_slice() {
        [(YamlString(ref name), YamlMapping(ref map))] => {
            let mut matches: Vec<Match>  = Vec::new();

            for m in map.as_slice() {
                match m {
                    &(YamlInteger(ref id), YamlMapping(ref content)) =>
                        matches.push(parse_match(*id, content)),

                    _ => continue,
                }
            }

            let s_name = name.to_string();
            let temp: Vec<&str> = s_name.split(' ').collect();
            let season_num = temp[1].to_string().parse::<isize>().unwrap();

            seasons.push(Season::new(season_num, matches));
            Ok(seasons)
        },

        _ => Err("Error"),
    }
}

fn lowercase(s: &String) -> String {
    s.chars().map(|c| c.to_lowercase().next().unwrap()).collect::<String>()
}

fn capitalize(s: &String) -> String {
    s.chars().enumerate()
        .map(|(i, c)| if i == 0 {
                c.to_uppercase().next().unwrap()
            } else {
                c.to_lowercase().next().unwrap()
            }).collect::<String>()
}

fn parse_match(id: isize, map: &Vec<(YamlStandardData, YamlStandardData)>) -> Match {
    let mut m = Match::new(id);

    for e in map.as_slice() {
        match e {
            &(YamlString(ref key), YamlString(ref value)) =>
                match key.as_str() {
                    "deck"     => m.deck     = value.trim().to_string(),
                    "opponent" => m.opponent = value.trim().to_string(),
                    "result"   =>
                        match value.as_str() {
                            "Win"  => m.result = MatchResult::Win,
                            "Loss" => m.result = MatchResult::Loss,
                            _      => continue,
                        },
                    "type"     =>
                        match value.as_str() {
                            "Ranked"   => m.kind = MatchType::Ranked,
                            "Casual"   => m.kind = MatchType::Casual,
                            "Friendly" => m.kind = MatchType::Friendly,
                            _          => continue,
                        },
                    _ => continue,
                },

            _ => continue
        }
    }

    m
}

fn parse(data: Vec<YamlStandardData>) -> Result<Vec<Season>, &'static str> {
    for doc in data.iter() {
        match doc {
            &YamlMapping(ref map) => return parse_seasons(map),

            _ => return Err("No docs"),
        }
    }

    Err("No docs")
}

fn main() {
    let path = "hearthstone.yaml";

    let mut args: Vec<String> = Vec::new();

    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Calc HS stats");
        ap.refer(&mut args)
            .add_argument("args", List,
                          "Deck to calc winrate for");
        ap.parse_args_or_exit();
    }

    let mut reader = BufReader::new(File::open(path).unwrap());
    let data = yaml::parse_io_utf8(&mut reader).unwrap();

    let seasons = parse(data).unwrap();

    if args.len() >= 1 {
        let season = seasons.last().unwrap();

        match args[0].as_str() {
            "deck" => {
                let deck   = &args[1..3];
                let name   = deck[0].to_string();
                let class  = deck[1].to_string();

                let data = season.deck(&name, &class);

                println!("Matches: ");

                for m in &data.0 {
                    println!("{}", m);
                }

                println!("\nMatches: {}", data.0.len());
                println!("Winrate: {}%", data.1);
            },

            "show" => {
                print!("{}", season);
                println!("Total Winrate: {}%", season.winrate());
            },

            _ => println!("Command unknown"),
        }
    }
}
<|endoftext|>


<commit_before>extern crate itertools;
extern crate num;
extern crate permutohedron;
extern crate chrono;

use std::env;

mod euler1;
mod euler2;
mod euler3;
mod euler4;
mod euler5;
mod euler6;
mod euler7;
mod euler8;
mod euler9;
mod euler10;
mod euler11;
mod euler12;
mod euler13;
mod euler14;
mod euler15;
mod euler16;
mod euler17;
mod euler18;
mod euler19;
mod euler20;
mod euler21;
mod euler22;
mod euler23;
mod euler24;
mod euler25;
mod euler26;
mod euler27;
mod euler28;
mod euler29;
mod euler30;
mod euler31;
mod euler32;
mod euler33;
mod euler34;
mod euler35;
mod euler36;
mod euler37;
mod euler38;
mod euler39;
mod euler40;
mod euler41;
mod euler42;
mod euler43;
mod euler44;
mod euler45;
mod euler46;
mod euler47;
mod euler48;
mod euler49;
mod euler50;
mod euler51;
mod euler67;
mod euler52;
mod euler74;
mod euler79;
mod euler92;
mod euler92b;

fn main() {
    let args = env::args().collect::<Vec<_>>();
    if args.len() < 2 {
        println!("Provide a number as parameter");
    } else {
        match args[1].as_ref() {
            "1" => euler1::main(),
            "2" => euler2::main(),
            "3" => euler3::main(),
            "4" => euler4::main(),
            "5" => euler5::main(),
            "6" => euler6::main(),
            "7" => euler7::main(),
            "8" => euler8::main(),
            "9" => euler9::main(),
            "10" => euler10::main(),
            "11" => euler11::main(),
            "12" => euler12::main(),
            "13" => euler13::main(),
            "14" => euler14::main(),
            "15" => euler15::main(),
            "16" => euler16::main(),
            "17" => euler17::main(),
            "18" => euler18::main(),
            "19" => euler19::main(),
            "20" => euler20::main(),
            "21" => euler21::main(),
            "22" => euler22::main(),
            "23" => euler23::main(),
            "24" => euler24::main(),
            "25" => euler25::main(),
            "26" => euler26::main(),
            "27" => euler27::main(),
            "28" => euler28::main(),
            "29" => euler29::main(),
            "30" => euler30::main(),
            "31" => euler31::main(),
            "32" => euler32::main(),
            "33" => euler33::main(),
            "34" => euler34::main(),
            "35" => euler35::main(),
            "36" => euler36::main(),
            "37" => euler37::main(),
            "38" => euler38::main(),
            "39" => euler39::main(),
            "40" => euler40::main(),
            "41" => euler41::main(),
            "42" => euler42::main(),
            "43" => euler43::main(),
            "44" => euler44::main(),
            "45" => euler45::main(),
            "46" => euler46::main(),
            "47" => euler47::main(),
            "48" => euler48::main(),
            "49" => euler49::main(),
            "50" => euler50::main(),
            "51" => euler51::main(),
            "52" => euler52::main(),
            "67" => euler67::main(),
            "74" => euler74::main(),
            "79" => euler79::main(),
            "92" => euler92::main(),
            "92b" => euler92b::main(),
            _ => println!("Hasn't solved yet"),
        }
    }
}
<commit_msg>reorder modules<commit_after>extern crate itertools;
extern crate num;
extern crate permutohedron;
extern crate chrono;

use std::env;

mod euler1;
mod euler2;
mod euler3;
mod euler4;
mod euler5;
mod euler6;
mod euler7;
mod euler8;
mod euler9;
mod euler10;
mod euler11;
mod euler12;
mod euler13;
mod euler14;
mod euler15;
mod euler16;
mod euler17;
mod euler18;
mod euler19;
mod euler20;
mod euler21;
mod euler22;
mod euler23;
mod euler24;
mod euler25;
mod euler26;
mod euler27;
mod euler28;
mod euler29;
mod euler30;
mod euler31;
mod euler32;
mod euler33;
mod euler34;
mod euler35;
mod euler36;
mod euler37;
mod euler38;
mod euler39;
mod euler40;
mod euler41;
mod euler42;
mod euler43;
mod euler44;
mod euler45;
mod euler46;
mod euler47;
mod euler48;
mod euler49;
mod euler50;
mod euler51;
mod euler52;
mod euler67;
mod euler74;
mod euler79;
mod euler92;
mod euler92b;

fn main() {
    let args = env::args().collect::<Vec<_>>();
    if args.len() < 2 {
        println!("Provide a number as parameter");
    } else {
        match args[1].as_ref() {
            "1" => euler1::main(),
            "2" => euler2::main(),
            "3" => euler3::main(),
            "4" => euler4::main(),
            "5" => euler5::main(),
            "6" => euler6::main(),
            "7" => euler7::main(),
            "8" => euler8::main(),
            "9" => euler9::main(),
            "10" => euler10::main(),
            "11" => euler11::main(),
            "12" => euler12::main(),
            "13" => euler13::main(),
            "14" => euler14::main(),
            "15" => euler15::main(),
            "16" => euler16::main(),
            "17" => euler17::main(),
            "18" => euler18::main(),
            "19" => euler19::main(),
            "20" => euler20::main(),
            "21" => euler21::main(),
            "22" => euler22::main(),
            "23" => euler23::main(),
            "24" => euler24::main(),
            "25" => euler25::main(),
            "26" => euler26::main(),
            "27" => euler27::main(),
            "28" => euler28::main(),
            "29" => euler29::main(),
            "30" => euler30::main(),
            "31" => euler31::main(),
            "32" => euler32::main(),
            "33" => euler33::main(),
            "34" => euler34::main(),
            "35" => euler35::main(),
            "36" => euler36::main(),
            "37" => euler37::main(),
            "38" => euler38::main(),
            "39" => euler39::main(),
            "40" => euler40::main(),
            "41" => euler41::main(),
            "42" => euler42::main(),
            "43" => euler43::main(),
            "44" => euler44::main(),
            "45" => euler45::main(),
            "46" => euler46::main(),
            "47" => euler47::main(),
            "48" => euler48::main(),
            "49" => euler49::main(),
            "50" => euler50::main(),
            "51" => euler51::main(),
            "52" => euler52::main(),
            "67" => euler67::main(),
            "74" => euler74::main(),
            "79" => euler79::main(),
            "92" => euler92::main(),
            "92b" => euler92b::main(),
            _ => println!("Hasn't solved yet"),
        }
    }
}
<|endoftext|>