<commit_before>// Copyright 2017 Dave Goodell <dave@goodell.io>
// See LICENSE file for license terms (MIT license)

// TODO:
// - package the Alfred workflow properly, including icon
// - add a README.md
// - add "<icon>hex.png</icon>" (etc.) to xml output
// - add tests for the binary's behavior
// - convert all signed integer arithmetic to use "wrapping_add()" and friends to avoid undefined
//   behavior?
// - toggle type width/signedness with shift/option/ctrl/cmd modifier keys?
// - add "--binary"/"--hex"/etc. output format options for the default (non-"--alfred2") mode

extern crate rustc_serialize;
extern crate docopt;

use std::process;
use docopt::Docopt;

const USAGE: &'static str = "
Usage: alfred-rust-calc [--alfred2] [--] <expr>...
       alfred-rust-calc (-h | --help)

Options:
    -h,--help    Show this screen.
    --alfred2    Emit Alfred2-style workflow XML.
";

mod calc {
    include!(concat!(env!("OUT_DIR"), "/calc.rs"));
}

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_alfred2: bool,
    arg_expr: Vec<String>,
}

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

    let expr_str = args.arg_expr.join(" ");

    if args.flag_alfred2 {
        match calc::expr(&*expr_str) {
            Ok(expr) => {
                // the Alfred2 Script Filter XML output format is documented here:
                // https://www.alfredapp.com/help/workflows/inputs/script-filter/xml/
                print!("\
<?xml version=\"1.0\"?>
<items>
  <item arg=\"{0}\" valid=\"YES\" autocomplete=\"{0}\" type=\"default\">
    <title>{0}</title>
    <subtitle>(decimal)</subtitle>
  </item>
  <item arg=\"0x{0:x}\" valid=\"YES\" autocomplete=\"0x{0:x}\" type=\"default\">
    <title>0x{0:x}</title>
    <subtitle>(hexadecimal)</subtitle>
  </item>
  <item arg=\"0o{0:o}\" valid=\"YES\" autocomplete=\"0o{0:o}\" type=\"default\">
    <title>0o{0:o}</title>
    <subtitle>(octal)</subtitle>
  </item>
  <item arg=\"0b{0:b}\" valid=\"YES\" autocomplete=\"0b{0:b}\" type=\"default\">
    <title>0b{0:o}</title>
    <subtitle>(binary)</subtitle>
  </item>
</items>
", expr);
            },
            Err(err) => {
                print!("\
<?xml version=\"1.0\"?>
<items>
  <item arg=\"{0}\" valid=\"NO\" autocomplete=\"{0}\" type=\"default\">
    <title>{0}</title>
    <subtitle><![CDATA[{1}]]></subtitle>
  </item>
</items>
", "...", err);
                // don't "process::exit(1)" here, it makes Alfred mildly angry
            }
        }
    } else {
        match calc::expr(&*expr_str) {
            Ok(expr) => {
                println!("{:}", expr);
            },
            Err(err) => {
                println!("Error: {}", err);
                process::exit(1);
            }
        }
    }
}
<commit_msg>rustfmt main.rs<commit_after>// Copyright 2017 Dave Goodell <dave@goodell.io>
// See LICENSE file for license terms (MIT license)

// TODO:
// - package the Alfred workflow properly, including icon
// - add a README.md
// - add "<icon>hex.png</icon>" (etc.) to xml output
// - add tests for the binary's behavior
// - convert all signed integer arithmetic to use "wrapping_add()" and friends to avoid undefined
//   behavior?
// - toggle type width/signedness with shift/option/ctrl/cmd modifier keys?
// - add "--binary"/"--hex"/etc. output format options for the default (non-"--alfred2") mode

extern crate rustc_serialize;
extern crate docopt;

use std::process;
use docopt::Docopt;

const USAGE: &'static str = "
Usage: alfred-rust-calc [--alfred2] [--] <expr>...
       alfred-rust-calc (-h | --help)

Options:
    -h,--help    Show this screen.
    --alfred2    Emit Alfred2-style workflow XML.
";

mod calc {
    include!(concat!(env!("OUT_DIR"), "/calc.rs"));
}

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_alfred2: bool,
    arg_expr: Vec<String>,
}

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

    let expr_str = args.arg_expr.join(" ");

    if args.flag_alfred2 {
        match calc::expr(&*expr_str) {
            Ok(expr) => {
                // the Alfred2 Script Filter XML output format is documented here:
                // https://www.alfredapp.com/help/workflows/inputs/script-filter/xml/
                print!("\
<?xml version=\"1.0\"?>
<items>
  <item arg=\"{0}\" valid=\"YES\" autocomplete=\"{0}\" type=\"default\">
    <title>{0}</title>
    <subtitle>(decimal)</subtitle>
  </item>
  <item arg=\"0x{0:x}\" valid=\"YES\" autocomplete=\"0x{0:x}\" type=\"default\">
    <title>0x{0:x}</title>
    <subtitle>(hexadecimal)</subtitle>
  </item>
  <item arg=\"0o{0:o}\" valid=\"YES\" autocomplete=\"0o{0:o}\" type=\"default\">
    <title>0o{0:o}</title>
    <subtitle>(octal)</subtitle>
  </item>
  <item arg=\"0b{0:b}\" valid=\"YES\" autocomplete=\"0b{0:b}\" type=\"default\">
    <title>0b{0:o}</title>
    <subtitle>(binary)</subtitle>
  </item>
</items>
",
                       expr);
            }
            Err(err) => {
                print!("\
<?xml version=\"1.0\"?>
<items>
  <item arg=\"{0}\" valid=\"NO\" autocomplete=\"{0}\" type=\"default\">
    <title>{0}</title>
    <subtitle><![CDATA[{1}]]></subtitle>
  </item>
</items>
",
                       "...",
                       err);
                // don't "process::exit(1)" here, it makes Alfred mildly angry
            }
        }
    } else {
        match calc::expr(&*expr_str) {
            Ok(expr) => {
                println!("{:}", expr);
            }
            Err(err) => {
                println!("Error: {}", err);
                process::exit(1);
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate tray_rust;

use tray_rust::linalg;
use tray_rust::film;
use tray_rust::geometry;
use tray_rust::geometry::Geometry;

fn main() {
    let width = 800u;
    let height = 600u;
    let mut rt = film::RenderTarget::new(width, height);
    let camera = film::Camera::new(linalg::Transform::look_at(
        &linalg::Point::new(0.0, 0.0, -10.0), &linalg::Point::new(0.0, 0.0, 0.0),
        &linalg::Vector::new(0.0, 1.0, 0.0)), 40.0, rt.dimensions());
    let sphere = geometry::Sphere::new(1.5);
    let instance = geometry::Instance::new(&sphere,
        linalg::Transform::translate(&linalg::Vector::new(0.0, 2.0, 0.0)));
    for y in range(0, height) {
        for x in range(0, width) {
            let px = (x as f32 + 0.5, y as f32 + 0.5);
            let mut ray = camera.generate_ray(px);
            match instance.intersect(&mut ray) {
                Some(_) => rt.write(px.0, px.1, &film::Colorf::broadcast(1.0)),
                None => {},
            }
        }
    }
    film::write_ppm("out.ppm", width, height, rt.get_render().as_slice());
}

<commit_msg>Use new Intersection type in the simple hit marker render<commit_after>extern crate tray_rust;

use tray_rust::linalg;
use tray_rust::film;
use tray_rust::geometry;
use tray_rust::geometry::Geometry;

fn main() {
    let width = 800u;
    let height = 600u;
    let mut rt = film::RenderTarget::new(width, height);
    let camera = film::Camera::new(linalg::Transform::look_at(
        &linalg::Point::new(0.0, 0.0, -10.0), &linalg::Point::new(0.0, 0.0, 0.0),
        &linalg::Vector::new(0.0, 1.0, 0.0)), 40.0, rt.dimensions());
    let sphere = geometry::Sphere::new(1.5);
    let instance = geometry::Instance::new(&sphere,
        linalg::Transform::translate(&linalg::Vector::new(0.0, 2.0, 0.0)));
    for y in range(0, height) {
        for x in range(0, width) {
            let px = (x as f32 + 0.5, y as f32 + 0.5);
            let mut ray = camera.generate_ray(px);
            if let Some(_) = geometry::Intersection::from_diffgeom(instance.intersect(&mut ray)) {
                rt.write(px.0, px.1, &film::Colorf::broadcast(1.0));
            }
        }
    }
    film::write_ppm("out.ppm", width, height, rt.get_render().as_slice());
}

<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
extern crate itertools;
extern crate walkdir;
extern crate toml;

use std::env;
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;
use std::process::{exit, Command, Output};
use clap::{App, SubCommand, AppSettings};
use walkdir::{DirEntry, WalkDirIterator};

fn announce(banner: &str) {
    let mut line = String::new();
    for _ in 0..banner.len() {
        line.push('-');
    }
    println!("{}\n{}\n{}", line, banner, line);
}

fn print_ident(buf: Vec<u8>) {
    for line in String::from_utf8_lossy(&buf[..]).lines() {
        println!("        {}", line);
    }
}

fn report_output(output: Output) -> std::process::ExitStatus {
    if output.status.success() {
        print_ident(output.stdout);
    }

    // Always print stderr as warnings from cargo are sent to stderr.
    print_ident(output.stderr);

    // I am still not sure what is more idiomatic - the 'if' above or the 'match' below
    //
    // match output.status.success() {
    //     true => print_ident(output.stdout),
    //     false => print_ident(output.stderr),
    // }
    println!("");

    output.status
}

const CARGO: &'static str = "cargo";
const MIN_DEPTH: usize = 1;
const MAX_DEPTH: usize = 1;

fn main() {

    let matches = App::new(CARGO)
        .bin_name(CARGO)
        .version(crate_version!())
        .about("Run cargo command on multiple crates")
        .setting(AppSettings::SubcommandRequired)
        .setting(AppSettings::ArgRequiredElseHelp)
        .subcommand(SubCommand::with_name("multi")
            .version(crate_version!())
            .setting(AppSettings::ArgRequiredElseHelp)
            .setting(AppSettings::TrailingVarArg)
            .arg_from_usage("<cmd>... 'cargo command to run'"))
        .get_matches();

    let mut cargo_cmd = Command::new(CARGO);
    let mut banner = String::from("Executing ") + CARGO;

    if let Some(arg_cmd) = matches.subcommand_matches("multi")
        .and_then(|m| m.values_of("cmd")) {
        for arg in arg_cmd {
            cargo_cmd.arg(arg);
            banner = banner + " " + arg;
        }
    }

    announce(&banner);
    let is_crate = |e: &DirEntry| e.path().join("Cargo.toml").exists();
    let display_path = |p: &PathBuf| println!("{}:", p.to_string_lossy());
    let execute = |p: PathBuf| cargo_cmd.current_dir(p).output().ok();

    // First check if there is a Cargo.toml file with a workspace section in.
    let mut workspace_members = match File::open("Cargo.toml") {
        Ok(mut file) => {
            let mut toml = String::new();
            match file.read_to_string(&mut toml) {
                Ok(_) => {
                    let value: toml::Value = toml.parse().expect("Failed to parse Cargo.toml");

                    match value.lookup("workspace.members") {
                        Some(members) => {
                            Some(members.as_slice()
                                        .expect("Failed to read workspace members")
                                        .into_iter()
                                        .map(|m| PathBuf::from(m.as_str().unwrap()))
                                        .collect::<Vec<_>>())
                        }
                        None => None,
                    }
                }
                Err(_) => None,
            }
        }
        Err(_) => None,
    };

    // If there was no workspace members present, add each crate directory
    // present.
    if workspace_members.is_none() {
        workspace_members = match env::current_dir() {
            Ok(cwd) => {
                Some(walkdir::WalkDir::new(cwd)
                                .min_depth(MIN_DEPTH)
                                .max_depth(MAX_DEPTH)
                                .into_iter()
                                .filter_entry(is_crate)
                                .filter_map(|e| e.ok())
                                .map(|m| m.path().to_path_buf())
                                .collect::<Vec<_>>())
            }
            Err(_) => None,
        }
    }

    let failed_commands = match workspace_members {
        Some(members) => {
            members.into_iter()
                   .inspect(display_path)
                   .filter_map(execute)
                   .map(report_output)
                   .filter(|x| !x.success())
                   .collect::<Vec<_>>()
        }
        None => Vec::new(),
    };

    // If there are any failed commands, return the error code of the
    // first of them.
    if failed_commands.len() > 0 {
        exit(failed_commands[0].code().unwrap());
    }
}
<commit_msg>rustfmt<commit_after>#[macro_use]
extern crate clap;
extern crate itertools;
extern crate walkdir;
extern crate toml;

use std::env;
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;
use std::process::{exit, Command, Output};
use clap::{App, SubCommand, AppSettings};
use walkdir::{DirEntry, WalkDirIterator};

fn announce(banner: &str) {
    let mut line = String::new();
    for _ in 0..banner.len() {
        line.push('-');
    }
    println!("{}\n{}\n{}", line, banner, line);
}

fn print_ident(buf: Vec<u8>) {
    for line in String::from_utf8_lossy(&buf[..]).lines() {
        println!("        {}", line);
    }
}

fn report_output(output: Output) -> std::process::ExitStatus {
    if output.status.success() {
        print_ident(output.stdout);
    }

    // Always print stderr as warnings from cargo are sent to stderr.
    print_ident(output.stderr);

    // I am still not sure what is more idiomatic - the 'if' above or the 'match' below
    //
    // match output.status.success() {
    //     true => print_ident(output.stdout),
    //     false => print_ident(output.stderr),
    // }
    println!("");

    output.status
}

const CARGO: &'static str = "cargo";
const MIN_DEPTH: usize = 1;
const MAX_DEPTH: usize = 1;

fn main() {

    let matches = App::new(CARGO)
        .bin_name(CARGO)
        .version(crate_version!())
        .about("Run cargo command on multiple crates")
        .setting(AppSettings::SubcommandRequired)
        .setting(AppSettings::ArgRequiredElseHelp)
        .subcommand(SubCommand::with_name("multi")
            .version(crate_version!())
            .setting(AppSettings::ArgRequiredElseHelp)
            .setting(AppSettings::TrailingVarArg)
            .arg_from_usage("<cmd>... 'cargo command to run'"))
        .get_matches();

    let mut cargo_cmd = Command::new(CARGO);
    let mut banner = String::from("Executing ") + CARGO;

    if let Some(arg_cmd) = matches.subcommand_matches("multi")
        .and_then(|m| m.values_of("cmd")) {
        for arg in arg_cmd {
            cargo_cmd.arg(arg);
            banner = banner + " " + arg;
        }
    }

    announce(&banner);
    let is_crate = |e: &DirEntry| e.path().join("Cargo.toml").exists();
    let display_path = |p: &PathBuf| println!("{}:", p.to_string_lossy());
    let execute = |p: PathBuf| cargo_cmd.current_dir(p).output().ok();

    // First check if there is a Cargo.toml file with a workspace section in.
    let mut workspace_members = match File::open("Cargo.toml") {
        Ok(mut file) => {
            let mut toml = String::new();
            match file.read_to_string(&mut toml) {
                Ok(_) => {
                    let value: toml::Value = toml.parse().expect("Failed to parse Cargo.toml");

                    match value.lookup("workspace.members") {
                        Some(members) => {
                            Some(members.as_slice()
                                .expect("Failed to read workspace members")
                                .into_iter()
                                .map(|m| PathBuf::from(m.as_str().unwrap()))
                                .collect::<Vec<_>>())
                        }
                        None => None,
                    }
                }
                Err(_) => None,
            }
        }
        Err(_) => None,
    };

    // If there was no workspace members present, add each crate directory
    // present.
    if workspace_members.is_none() {
        workspace_members = match env::current_dir() {
            Ok(cwd) => {
                Some(walkdir::WalkDir::new(cwd)
                    .min_depth(MIN_DEPTH)
                    .max_depth(MAX_DEPTH)
                    .into_iter()
                    .filter_entry(is_crate)
                    .filter_map(|e| e.ok())
                    .map(|m| m.path().to_path_buf())
                    .collect::<Vec<_>>())
            }
            Err(_) => None,
        }
    }

    let failed_commands = match workspace_members {
        Some(members) => {
            members.into_iter()
                .inspect(display_path)
                .filter_map(execute)
                .map(report_output)
                .filter(|x| !x.success())
                .collect::<Vec<_>>()
        }
        None => Vec::new(),
    };

    // If there are any failed commands, return the error code of the
    // first of them.
    if failed_commands.len() > 0 {
        exit(failed_commands[0].code().unwrap());
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate log;
extern crate env_logger;
extern crate rustylnk;
extern crate clap;
extern crate seek_bufread;
extern crate jmespath;
extern crate serde_json;
extern crate serde;
use clap::{App, Arg, ArgMatches};
use jmespath::{Expression};
use seek_bufread::BufReader;
use rustylnk::lnkpkg::lnk::{Lnk};
use std::fs;

fn process_directory(directory: &str, options: &ArgMatches) {
    for entry in fs::read_dir(directory).unwrap() {
        let entry = entry.unwrap();
        let path = entry.path();
        if path.is_file() {
            let path_string = path.into_os_string().into_string().unwrap();
            if path_string.ends_with(".lnk"){
                process_file(&path_string, &options);
            }
        }
    }
}

fn process_file(filename: &str, options: &ArgMatches) -> bool {
    // JMES Expression if needed
    let mut expr: Option<Expression> = None;
    if options.is_present("query") {
        expr = Some(jmespath::compile(
            options.value_of("query").unwrap()
        ).unwrap());
    }

    // Expression bool flag
    let mut expr_as_bool = false;
    if options.is_present("bool_expr"){
        expr_as_bool = true;
    }

    let file = match fs::File::open(filename) {
        Ok(file) => file,
        Err(error) => {
            error!("Could not open file: {} [error: {}]", filename, error);
            return false;
        }
    };

    let reader = BufReader::new(file);

    info!("Parsing file: {}",filename);
    let lnk = match Lnk::new(reader) {
        Ok(lnk) => lnk,
        Err(error) => {
            error!("Could not parse file: {} [error: {}]", filename, error);
            return false;
        }
    };

    let json_str = serde_json::to_string(&lnk).unwrap();
    match expr {
        Some(ref j_expr) => {
            let data = jmespath::Variable::from_json(&json_str).unwrap();
            let result = j_expr.search(data).unwrap();
            if expr_as_bool {
                match result.as_boolean() {
                    Some(bool_value) => {
                        match bool_value {
                            true => println!("{}",json_str),
                            false => {}
                        }
                    },
                    None => {
                        error!("Query expression is not a bool expression! [{}]",options.value_of("query").unwrap());
                    }
                }
            } else {
                println!("{}",result)
            }
        },
        None => {
            println!("{}",json_str);
        }
    }

    return true;
}

fn is_directory(source: &str)->bool{
    let metadata = fs::metadata(source).unwrap();

    let file_type = metadata.file_type();

    file_type.is_dir()
}

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

    let source_arg = Arg::with_name("source")
        .short("s")
        .long("source")
        .value_name("PATH")
        .help("The LNK file or folder with LNK files to parse.")
        .takes_value(true);

    let jmes_arg = Arg::with_name("query")
        .short("q")
        .long("query")
        .value_name("QUERY")
        .help("JMES Query")
        .takes_value(true);

    let bool_arg = Arg::with_name("bool_expr")
        .short("b")
        .long("bool_expr")
        .help("JMES Query as bool only. (Prints whole record if true.)");

    let options = App::new("RusyLnk")
        .version("0.0.0")
        .author("Matthew Seyer <https://github.com/forensicmatt/RustyUsn>")
        .about("LNK Parser written in Rust.")
        .arg(source_arg)
        .arg(jmes_arg)
        .arg(bool_arg)
        .get_matches();

    let source = options.value_of("source").unwrap();

    if is_directory(source) {
        process_directory(source,&options);
    } else {
        process_file(source,&options);
    }
}
<commit_msg>Removed .lnk extention for processing<commit_after>#[macro_use] extern crate log;
extern crate env_logger;
extern crate rustylnk;
extern crate clap;
extern crate seek_bufread;
extern crate jmespath;
extern crate serde_json;
extern crate serde;
use clap::{App, Arg, ArgMatches};
use jmespath::{Expression};
use seek_bufread::BufReader;
use rustylnk::lnkpkg::lnk::{Lnk};
use std::fs;

fn process_directory(directory: &str, options: &ArgMatches) {
    for entry in fs::read_dir(directory).unwrap() {
        let entry = entry.unwrap();
        let path = entry.path();
        if path.is_file() {
            let path_string = path.into_os_string().into_string().unwrap();
            process_file(&path_string, &options);
        }
    }
}

fn process_file(filename: &str, options: &ArgMatches) -> bool {
    // JMES Expression if needed
    let mut expr: Option<Expression> = None;
    if options.is_present("query") {
        expr = Some(jmespath::compile(
            options.value_of("query").unwrap()
        ).unwrap());
    }

    // Expression bool flag
    let mut expr_as_bool = false;
    if options.is_present("bool_expr"){
        expr_as_bool = true;
    }

    let file = match fs::File::open(filename) {
        Ok(file) => file,
        Err(error) => {
            error!("Could not open file: {} [error: {}]", filename, error);
            return false;
        }
    };

    let reader = BufReader::new(file);

    info!("Parsing file: {}",filename);
    let lnk = match Lnk::new(reader) {
        Ok(lnk) => lnk,
        Err(error) => {
            error!("Could not parse file: {} [error: {}]", filename, error);
            return false;
        }
    };

    let json_str = serde_json::to_string(&lnk).unwrap();
    match expr {
        Some(ref j_expr) => {
            let data = jmespath::Variable::from_json(&json_str).unwrap();
            let result = j_expr.search(data).unwrap();
            if expr_as_bool {
                match result.as_boolean() {
                    Some(bool_value) => {
                        match bool_value {
                            true => println!("{}",json_str),
                            false => {}
                        }
                    },
                    None => {
                        error!("Query expression is not a bool expression! [{}]",options.value_of("query").unwrap());
                    }
                }
            } else {
                println!("{}",result)
            }
        },
        None => {
            println!("{}",json_str);
        }
    }

    return true;
}

fn is_directory(source: &str)->bool{
    let metadata = fs::metadata(source).unwrap();

    let file_type = metadata.file_type();

    file_type.is_dir()
}

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

    let source_arg = Arg::with_name("source")
        .short("s")
        .long("source")
        .value_name("PATH")
        .help("The LNK file or folder with LNK files to parse.")
        .takes_value(true);

    let jmes_arg = Arg::with_name("query")
        .short("q")
        .long("query")
        .value_name("QUERY")
        .help("JMES Query")
        .takes_value(true);

    let bool_arg = Arg::with_name("bool_expr")
        .short("b")
        .long("bool_expr")
        .help("JMES Query as bool only. (Prints whole record if true.)");

    let options = App::new("RusyLnk")
        .version("0.0.0")
        .author("Matthew Seyer <https://github.com/forensicmatt/RustyUsn>")
        .about("LNK Parser written in Rust.")
        .arg(source_arg)
        .arg(jmes_arg)
        .arg(bool_arg)
        .get_matches();

    let source = options.value_of("source").unwrap();

    if is_directory(source) {
        process_directory(source,&options);
    } else {
        process_file(source,&options);
    }
}
<|endoftext|>


<commit_before>extern crate futures;
extern crate tokio_core;
extern crate tokio_proto;
extern crate tokio_service;

use std::io;
use std::str;
use std::collections::BTreeMap;
use tokio_core::io::{Codec, EasyBuf};
use tokio_core::io::{Io, Framed};
use tokio_proto::pipeline::ServerProto;
use tokio_proto::TcpServer;
use tokio_service::Service;
use futures::{future, Future, BoxFuture};

#[derive(Default)]
pub struct CliCodec {
    /// Offset within the incoming EasyBuf at which newline search last ended
    search_offset: usize,
}

impl Codec for CliCodec {
    /// Input type is a tuple with the command name and an optional argument string
    type In = (String, Option<String>);

    /// Response type is just a string
    type Out = String;

    /// Find a newline, decode to a tuple of command name and argument string
    fn decode(&mut self, buf: &mut EasyBuf) -> io::Result<Option<Self::In>> {
        // Find newline
        let m = buf
            .as_slice()
            .iter()
            .skip(self.search_offset)
            .position(|&b| b == b'\n');

        match m {
            // Process the line if a newline was found
            Some(idx) => {
                println!("Found newline at position {}, started at {}", idx, self.search_offset); // XXX

                let line = buf.drain_to(self.search_offset + idx);
                buf.drain_to(1);

                self.search_offset = 0;

                match str::from_utf8(line.as_slice()) {
                    // Return the string on successful UTF-8 decode
                    // (TODO: ignore blank lines)
                    Ok(s) => {
                        // TODO: Find a better way to split the string
                        let s = s.trim();

                        let request = match s.find(' ') {
                            Some(i) => {
                                let (cmd, args) = s.split_at(i);
                                (cmd.trim().to_string(), Some(args.trim().to_string()))
                            },
                            None => (s.to_string(), None)
                        };

                        Ok(Some(request))
                    },

                    // Return an error if invalid UTF-8 is received
                    Err(e) => Err(io::Error::new(io::ErrorKind::Other, format!("invalid UTF-8: {:?}", e))),
                }
            },

            // Save our position if a newline wasn't found
            _ => {
                println!("Haven't received newline yet!  We started at offset {}, now at {}", self.search_offset, buf.len()); // XXX

                self.search_offset = buf.len();

                Ok(None)
            }
        }
    }

    /// Append the String to the outgoing buffer
    fn encode(&mut self, msg: String, buf: &mut Vec<u8>) -> io::Result<()> {
        buf.extend(msg.as_bytes());
        buf.push(b'\n');
        Ok(())
    }
}

pub struct CliProto;

impl<T: Io + 'static> ServerProto<T> for CliProto {
    type Request = (String, Option<String>);
    type Response = String;

    type Transport = Framed<T, CliCodec>;
    type BindTransport = Result<Self::Transport, io::Error>;

    fn bind_transport(&self, io: T) -> Self::BindTransport {
        Ok(io.framed(CliCodec::default()))
    }
}

trait CliCommand {
    fn name(&self) -> &str;
    fn description(&self) -> &str;
    fn call(&self, args: Option<String>) -> String;
}

#[derive(Default)]
pub struct CliServer<'a> {
    commands: BTreeMap<&'a str, &'a CliCommand>,
}

impl<'a> CliServer<'a> {
    fn add_command(&mut self, cmd: &'a CliCommand) {
        self.commands.insert(cmd.name(), cmd);
    }
}

impl<'a> Service for CliServer<'a> {
    type Request = (String, Option<String>);
    type Response = String;

    type Error = io::Error;

    type Future = BoxFuture<Self::Response, Self::Error>;

    fn call(&self, req: Self::Request) -> Self::Future {
        match self.commands.get(&req.0[..]) {
            Some(cmd) => {
                println!("Calling command {}", req.0);
                // TODO: have commands return futures?
                future::ok(cmd.call(req.1)).boxed()
            },
            None => {
                println!("No match found for command {}", req.0);
                future::ok(format!("Unknown command: {}", req.0)).boxed()
            }
        }
    }
}

fn main() {
    let addr = "0.0.0.0:14311".parse().unwrap();
    let server = TcpServer::new(CliProto, addr);

    println!("Serving on {}", addr);
    server.serve(|| Ok(CliServer::default()));
}
<commit_msg>Implemented the "echo" command.<commit_after>extern crate futures;
extern crate tokio_core;
extern crate tokio_proto;
extern crate tokio_service;

use std::io;
use std::str;
use std::collections::BTreeMap;
use tokio_core::io::{Codec, EasyBuf};
use tokio_core::io::{Io, Framed};
use tokio_proto::pipeline::ServerProto;
use tokio_proto::TcpServer;
use tokio_service::Service;
use futures::{future, Future, BoxFuture};

#[derive(Default)]
pub struct CliCodec {
    /// Offset within the incoming EasyBuf at which newline search last ended
    search_offset: usize,
}

impl Codec for CliCodec {
    /// Input type is a tuple with the command name and an optional argument string
    type In = (String, Option<String>);

    /// Response type is just a string
    type Out = String;

    /// Find a newline, decode to a tuple of command name and argument string
    fn decode(&mut self, buf: &mut EasyBuf) -> io::Result<Option<Self::In>> {
        // Find newline
        let m = buf
            .as_slice()
            .iter()
            .skip(self.search_offset)
            .position(|&b| b == b'\n');

        match m {
            // Process the line if a newline was found
            Some(idx) => {
                println!("Found newline at position {}, started at {}", idx, self.search_offset); // XXX

                let line = buf.drain_to(self.search_offset + idx);
                buf.drain_to(1);

                self.search_offset = 0;

                match str::from_utf8(line.as_slice()) {
                    // Return the string on successful UTF-8 decode
                    // (TODO: ignore blank lines)
                    Ok(s) => {
                        // TODO: Find a better way to split the string
                        let s = s.trim();

                        let request = match s.find(' ') {
                            Some(i) => {
                                let (cmd, args) = s.split_at(i);
                                (cmd.trim().to_string(), Some(args.trim().to_string()))
                            },
                            None => (s.to_string(), None)
                        };

                        Ok(Some(request))
                    },

                    // Return an error if invalid UTF-8 is received
                    Err(e) => Err(io::Error::new(io::ErrorKind::Other, format!("invalid UTF-8: {:?}", e))),
                }
            },

            // Save our position if a newline wasn't found
            _ => {
                println!("Haven't received newline yet!  We started at offset {}, now at {}", self.search_offset, buf.len()); // XXX

                self.search_offset = buf.len();

                Ok(None)
            }
        }
    }

    /// Append the String to the outgoing buffer
    fn encode(&mut self, msg: String, buf: &mut Vec<u8>) -> io::Result<()> {
        buf.extend(msg.as_bytes());
        buf.push(b'\n');
        Ok(())
    }
}

pub struct CliProto;

impl<T: Io + 'static> ServerProto<T> for CliProto {
    type Request = (String, Option<String>);
    type Response = String;

    type Transport = Framed<T, CliCodec>;
    type BindTransport = Result<Self::Transport, io::Error>;

    fn bind_transport(&self, io: T) -> Self::BindTransport {
        Ok(io.framed(CliCodec::default()))
    }
}

trait CliCommand {
    fn name(&self) -> &str;
    fn description(&self) -> &str;
    fn call(&self, args: Option<String>) -> String;
}

#[derive(Default)]
pub struct CliServer<'a> {
    commands: BTreeMap<&'a str, &'a CliCommand>,
}

impl<'a> CliServer<'a> {
    fn add_command(&mut self, cmd: &'a CliCommand) {
        self.commands.insert(cmd.name(), cmd);
    }
}

impl<'a> Service for CliServer<'a> {
    type Request = (String, Option<String>);
    type Response = String;

    type Error = io::Error;

    type Future = BoxFuture<Self::Response, Self::Error>;

    fn call(&self, req: Self::Request) -> Self::Future {
        match self.commands.get(&req.0[..]) {
            Some(cmd) => {
                println!("Calling command {}", req.0);
                // TODO: have commands return futures?
                future::ok(cmd.call(req.1)).boxed()
            },
            None => {
                println!("No match found for command {}", req.0);
                future::ok(format!("Unknown command: {}", req.0)).boxed()
            }
        }
    }
}

// TODO: Consider registering commands by passing two strings and a closure
struct EchoCommand;

impl CliCommand for EchoCommand {
    fn name(&self) -> &str {
        "echo"
    }

    fn description(&self) -> &str {
        "Prints the command line."
    }

    fn call(&self, args: Option<String>) -> String {
        match args {
            Some(s) => s,
            None => "".to_string()
        }
    }
}

static ECHO: EchoCommand = EchoCommand;

fn main() {
    let addr = "0.0.0.0:14311".parse().unwrap();
    let server = TcpServer::new(CliProto, addr);

    println!("Serving on {}", addr);
    server.serve(|| {
        let mut cli = CliServer::default();
        cli.add_command(&ECHO);
        Ok(cli)
    });
}
<|endoftext|>


<commit_before>extern crate chrono;

use std::io::{BufRead, BufReader};
use std::process::{Command, Stdio};
use std::sync::mpsc::{channel, Sender};
use std::thread::{self, sleep};
use std::time::Duration;

const OCCUPIED_ICON: &'static str = "";
const FREE_ICON: &'static str = "";

enum Update {
    Workspaces(String),
    Time(String),
    Title(String),
}

fn workspace_info(sender: Sender<Update>) {
    let output = Command::new("bspc").arg("subscribe").arg("report").stdout(Stdio::piped()).spawn().unwrap();

    let reader = BufReader::new(output.stdout.unwrap());
    for line in reader.lines() {
        let mut message: Vec<String> = Vec::new();
        message.push(format!(" %{{l}}"));
        message.push(format!("%{{A4:bspc desktop -f prev:}}%{{A5:bspc desktop -f next:}}"));

        let line = line.unwrap();
        let line_vector = line.split(":").collect::<Vec<&str>>();

        for line in &line_vector {
            match &line[0..1] {
                // Occupied focused
                "O" => {
                    message.push(format!("%{{A:bspc desktop -f {}:}}", &line[1..]));
                    message.push(format!("%{{F#FFF6F9FF}} {}%{{F-}}", OCCUPIED_ICON));
                    message.push(format!("%{{A}}"));
                }

                // Occupied unfocused
                "o" => {
                    message.push(format!("%{{A:bspc desktop -f {}:}}", &line[1..]));
                    message.push(format!("%{{F#FFA3A6AB}} {}%{{F-}}", OCCUPIED_ICON));
                    message.push(format!("%{{A}}"));
                }

                // Free focused
                "F" => {
                    message.push(format!("%{{A:bspc desktop -f {}:}}", &line[1..]));
                    message.push(format!("%{{F#FFF6F9FF}} {}%{{F-}}", FREE_ICON));
                    message.push(format!("%{{A}}"));
                }

                // Free unfocused
                "f" => {
                    message.push(format!("%{{A:bspc desktop -f {}:}}", &line[1..]));
                    message.push(format!("%{{F#FF6F7277}} {}%{{F-}}", FREE_ICON));
                    message.push(format!("%{{A}}"));
                }

                // Urgent focused
                "U" => {
                    message.push(format!("%{{A:bspc desktop -f {}:}}", &line[1..]));
                    message.push(format!("%{{F#FF916255}} {}%{{F-}}", OCCUPIED_ICON));
                    message.push(format!("%{{A}}"));
                }

                // Urgent unfocused
                "u" => {
                    message.push(format!("%{{A:bspc desktop -f {}:}}", &line[1..]));
                    message.push(format!("%{{F#FF543B3B}} {}%{{F-}}", OCCUPIED_ICON));
                    message.push(format!("%{{A}}"));
                }

                _ => {}
            }
        }
        message.push(format!("%{{A}}%{{A}}"));

        let _ = sender.send(Update::Workspaces(message.join("")));
    }
}

fn title(sender: Sender<Update>) {
    let output = Command::new("xtitle").arg("-s").arg("-i").arg("-t").arg("100").stdout(Stdio::piped()).spawn().unwrap();

    let reader = BufReader::new(output.stdout.unwrap());
    for line in reader.lines() {
        let line = line.unwrap();
        let _ = sender.send(Update::Title(format!("%{{c}}{}", line)));
    }
}

fn time(sender: Sender<Update>) {
    loop {
        let time = chrono::Local::now().format("%I:%M %p");
        let _ = sender.send(Update::Time(format!("%{{r}}%{{B#FF665B5B}} {} %{{B-}}", time)));
        sleep(Duration::from_secs(1));
    }
}

fn main() {
    let (sender, receiver) = channel::<Update>();

    let mut workspace_message: String = "".to_owned();
    let mut title_message: String = "".to_owned();
    let mut time_message: String = "".to_owned();
    let mut message: String = "".to_owned();

    let sender_clone = sender.clone();
    let _ = thread::spawn(move || {
        workspace_info(sender_clone);
    });

    let sender_clone = sender.clone();
    let _ = thread::spawn(move || {
        title(sender_clone);
    });

    let sender_clone = sender.clone();
    let _ = thread::spawn(move || {
        time(sender_clone);
    });

    for line in receiver.iter() {
        match line {
            Update::Workspaces(info) => {
                workspace_message = info;
            }

            Update::Title(title) => {
                title_message = title;
            }

            Update::Time(time) => {
                time_message = time;
            }
        }

        if message != workspace_message.to_owned() + &title_message + &time_message {
            message = workspace_message.to_owned() + &title_message + &time_message;
            sleep(Duration::from_millis(5));
            println!("{}", message);
        }
    }
}
<commit_msg>Fixed spacing issue on workspace icons<commit_after>extern crate chrono;

use std::io::{BufRead, BufReader};
use std::process::{Command, Stdio};
use std::sync::mpsc::{channel, Sender};
use std::thread::{self, sleep};
use std::time::Duration;

const OCCUPIED_ICON: &'static str = "";
const FREE_ICON: &'static str = "";

enum Update {
    Workspaces(String),
    Time(String),
    Title(String),
}

fn workspace_info(sender: Sender<Update>) {
    let output = Command::new("bspc").arg("subscribe").arg("report").stdout(Stdio::piped()).spawn().unwrap();

    let reader = BufReader::new(output.stdout.unwrap());
    for line in reader.lines() {
        let mut message: Vec<String> = Vec::new();
        message.push(format!("%{{l}} "));
        message.push(format!("%{{A4:bspc desktop -f prev:}}%{{A5:bspc desktop -f next:}}"));

        let line = line.unwrap();
        let line_vector = line.split(":").collect::<Vec<&str>>();

        for line in &line_vector {
            match &line[0..1] {
                // Occupied focused
                "O" => {
                    message.push(format!("%{{A:bspc desktop -f {}:}}", &line[1..]));
                    message.push(format!("%{{F#FFF6F9FF}}{}%{{F-}}", OCCUPIED_ICON));
                    message.push(format!("%{{A}} "));
                }

                // Occupied unfocused
                "o" => {
                    message.push(format!("%{{A:bspc desktop -f {}:}}", &line[1..]));
                    message.push(format!("%{{F#FFA3A6AB}}{}%{{F-}}", OCCUPIED_ICON));
                    message.push(format!("%{{A}} "));
                }

                // Free focused
                "F" => {
                    message.push(format!("%{{A:bspc desktop -f {}:}}", &line[1..]));
                    message.push(format!("%{{F#FFF6F9FF}}{}%{{F-}}", FREE_ICON));
                    message.push(format!("%{{A}} "));
                }

                // Free unfocused
                "f" => {
                    message.push(format!("%{{A:bspc desktop -f {}:}}", &line[1..]));
                    message.push(format!("%{{F#FF6F7277}}{}%{{F-}}", FREE_ICON));
                    message.push(format!("%{{A}} "));
                }

                // Urgent focused
                "U" => {
                    message.push(format!("%{{A:bspc desktop -f {}:}}", &line[1..]));
                    message.push(format!("%{{F#FF916255}}{}%{{F-}}", OCCUPIED_ICON));
                    message.push(format!("%{{A}} "));
                }

                // Urgent unfocused
                "u" => {
                    message.push(format!("%{{A:bspc desktop -f {}:}}", &line[1..]));
                    message.push(format!("%{{F#FF543B3B}}{}%{{F-}}", OCCUPIED_ICON));
                    message.push(format!("%{{A}} "));
                }

                _ => {}
            }
        }
        message.push(format!("%{{A}}%{{A}}"));

        let _ = sender.send(Update::Workspaces(message.join("")));
    }
}

fn title(sender: Sender<Update>) {
    let output = Command::new("xtitle").arg("-s").arg("-i").arg("-t").arg("100").stdout(Stdio::piped()).spawn().unwrap();

    let reader = BufReader::new(output.stdout.unwrap());
    for line in reader.lines() {
        let line = line.unwrap();
        let _ = sender.send(Update::Title(format!("%{{c}}{}", line)));
    }
}

fn time(sender: Sender<Update>) {
    loop {
        let time = chrono::Local::now().format("%I:%M %p");
        let _ = sender.send(Update::Time(format!("%{{r}}%{{B#FF665B5B}} {} %{{B-}}", time)));
        sleep(Duration::from_secs(1));
    }
}

fn main() {
    let (sender, receiver) = channel::<Update>();

    let mut workspace_message: String = "".to_owned();
    let mut title_message: String = "".to_owned();
    let mut time_message: String = "".to_owned();
    let mut message: String = "".to_owned();

    let sender_clone = sender.clone();
    let _ = thread::spawn(move || {
        workspace_info(sender_clone);
    });

    let sender_clone = sender.clone();
    let _ = thread::spawn(move || {
        title(sender_clone);
    });

    let sender_clone = sender.clone();
    let _ = thread::spawn(move || {
        time(sender_clone);
    });

    for line in receiver.iter() {
        match line {
            Update::Workspaces(info) => {
                workspace_message = info;
            }

            Update::Title(title) => {
                title_message = title;
            }

            Update::Time(time) => {
                time_message = time;
            }
        }

        if message != workspace_message.to_owned() + &title_message + &time_message {
            message = workspace_message.to_owned() + &title_message + &time_message;
            sleep(Duration::from_millis(5));
            println!("{}", message);
        }
    }
}
<|endoftext|>


<commit_before>extern crate getopts;
extern crate pnet;

use getopts::Options;
use std::os;
use std::net::{IpAddr};
use std::str::FromStr;

use pnet::transport::TransportProtocol::{Ipv4};
use pnet::old_packet::ip::IpNextHeaderProtocols;
use pnet::transport::TransportChannelType::{Layer3};
use pnet::transport::{transport_channel};

fn main() {
    let args: Vec<String> = os::args();
    let mut opts = Options::new();
    let matches = match opts.parse(args.tail()) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string())
    };
    let addr_arg = matches.free[0].as_slice();
    let addr: IpAddr = FromStr::from_str(addr_arg.as_slice()).unwrap();

    let protocol = Layer3(IpNextHeaderProtocols::Test1);
    let (mut tx, mut rx) = match transport_channel(4096, protocol) {
        Ok((tx, rx)) => (tx, rx),
        Err(e) => panic!("An error occurred when creating the transport channel:
                        {}", e)
    };
}
<commit_msg>slightly more meaningful names for transport channel return values<commit_after>extern crate getopts;
extern crate pnet;

use getopts::Options;
use std::os;
use std::net::{IpAddr};
use std::str::FromStr;

use pnet::transport::TransportProtocol::{Ipv4};
use pnet::old_packet::ip::IpNextHeaderProtocols;
use pnet::transport::TransportChannelType::{Layer3};
use pnet::transport::{transport_channel};

fn main() {
    let args: Vec<String> = os::args();
    let mut opts = Options::new();
    let matches = match opts.parse(args.tail()) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string())
    };
    let addr_arg = matches.free[0].as_slice();
    let addr: IpAddr = FromStr::from_str(addr_arg.as_slice()).unwrap();

    let protocol = Layer3(IpNextHeaderProtocols::Test1);
    let (mut icmp_sender, mut icmp_receiver) = match transport_channel(4096, protocol) {
        Ok((tx, rx)) => (tx, rx),
        Err(e) => panic!("An error occurred when creating the transport channel:
                        {}", e)
    };
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Bytes;

enum Mnemonic {
    Add, Call, Cls, Drw,
    Jp, Ld, Or, Ret,
    Rnd, Se, Shl, Shr,
    Sknp, Skp, Sne, Sub,
    Subn, Sys, Xor,
}

enum Register {
    V0, V1, V2, V3,
    V4, V5, V6, V7,
    V8, V9, Va, Vb,
    Vc, Vd, Ve, Vf,
    Sp, Pc, I, St, Dt, IVal,
}

enum Token {
    Opcode(Mnemonic),
    Reg(Register),
    ImmConst(u16),
}

struct Stream {
    input: Bytes<File>,
}

impl Stream {
    fn new(input: Bytes<File>) -> Stream {
        Stream {
            input: input,
        }
    }

    fn next_token(&mut self) -> Option<Token> {
        let mut buffer: Vec<u8> = vec![];

        loop {
            let bs = self.input.next().map_or(None, |bm| match bm {
                Ok(b) => Some(b),
                _ => None
            });

            match bs {
                Some(b) => {
                    if Stream::is_separator(b) {
                        return Stream::create_token(buffer);
                    }
                    buffer.push(b);
                },
                None => {
                    return Stream::create_token(buffer);
                }
            }
        }
    }

    fn create_token(input: Vec<u8>) -> Option<Token> {
        let token_str: String = String::from_utf8(input).unwrap_or_else(|err| {
            println!("Error: {:?}", err);
            "".to_owned()
        }).to_lowercase();

        if Stream::is_numeric(&token_str) {
            return Some(Token::ImmConst(token_str.parse::<u16>().unwrap()));
        }

        match token_str.as_str() {
            "add"   => Some(Token::Opcode(Mnemonic::Add)),
            "call"  => Some(Token::Opcode(Mnemonic::Call)),
            "cls"   => Some(Token::Opcode(Mnemonic::Cls)),
            "drw"   => Some(Token::Opcode(Mnemonic::Drw)),
            "jp"    => Some(Token::Opcode(Mnemonic::Jp)),
            "ld"    => Some(Token::Opcode(Mnemonic::Ld)),
            "or"    => Some(Token::Opcode(Mnemonic::Or)),
            "ret"   => Some(Token::Opcode(Mnemonic::Ret)),
            "rnd"   => Some(Token::Opcode(Mnemonic::Rnd)),
            "se"    => Some(Token::Opcode(Mnemonic::Se)),
            "shl"   => Some(Token::Opcode(Mnemonic::Shl)),
            "shr"   => Some(Token::Opcode(Mnemonic::Shr)),
            "sknp"  => Some(Token::Opcode(Mnemonic::Sknp)),
            "skp"   => Some(Token::Opcode(Mnemonic::Skp)),
            "sne"   => Some(Token::Opcode(Mnemonic::Sne)),
            "sub"   => Some(Token::Opcode(Mnemonic::Sub)),
            "subn"  => Some(Token::Opcode(Mnemonic::Subn)),
            "sys"   => Some(Token::Opcode(Mnemonic::Sys)),
            "xor"   => Some(Token::Opcode(Mnemonic::Xor)),
            _       => None
        }
    }

    fn is_separator(b: u8) -> bool {
        match b as char {
            ','|' '|'\n' => { true }
            _ => { false }
        }
    }

    fn is_numeric(input: &str) -> bool {
        if input.len() < 1 {
            return false;
        }

        let in_bytes = input.as_bytes();
        if !Stream::is_ascii_numeric(in_bytes[0]) {
            return false;
        }

        // hex
        if input.starts_with("0x") {
            for i in 2..(in_bytes.len()) {
                if !Stream::is_ascii_hex(in_bytes[i]) {
                    return false
                }
                return true
            }
        } else {
            for b in in_bytes {
                if !Stream::is_ascii_numeric(*b) {
                    return false
                }
                return true
            }
        }
        false
    }

    fn is_ascii_numeric(input: u8) -> bool {
        input >= 48 && input <= 57
    }

    fn is_ascii_hex(input: u8) -> bool {
        (input >= 48 && input <= 57) || ((input >= 97 && input <= 102) || (input >= 65 && input <= 70))
    }
}

fn main() {
}
<commit_msg>Add check for regitster matches<commit_after>use std::fs::File;
use std::io::Bytes;

enum Mnemonic {
    Add, Call, Cls, Drw,
    Jp, Ld, Or, Ret,
    Rnd, Se, Shl, Shr,
    Sknp, Skp, Sne, Sub,
    Subn, Sys, Xor,
}

enum Register {
    V0, V1, V2, V3,
    V4, V5, V6, V7,
    V8, V9, Va, Vb,
    Vc, Vd, Ve, Vf,
    Sp, Pc, I, St, Dt, IVal,
}

enum Token {
    Opcode(Mnemonic),
    Reg(Register),
    ImmConst(u16),
}

struct Stream {
    input: Bytes<File>,
}

impl Stream {
    fn new(input: Bytes<File>) -> Stream {
        Stream {
            input: input,
        }
    }

    fn next_token(&mut self) -> Option<Token> {
        let mut buffer: Vec<u8> = vec![];

        loop {
            let bs = self.input.next().map_or(None, |bm| match bm {
                Ok(b) => Some(b),
                _ => None
            });

            match bs {
                Some(b) => {
                    if Stream::is_separator(b) {
                        return Stream::create_token(buffer);
                    }
                    buffer.push(b);
                },
                None => {
                    return Stream::create_token(buffer);
                }
            }
        }
    }

    fn create_token(input: Vec<u8>) -> Option<Token> {
        let token_str: String = String::from_utf8(input).unwrap_or_else(|err| {
            println!("Error: {:?}", err);
            "".to_owned()
        }).to_lowercase();

        if Stream::is_numeric(&token_str) {
            return Some(Token::ImmConst(token_str.parse::<u16>().unwrap()));
        }

        if Stream::is_register(&token_str) {
            return match token_str.as_str() {
                "v0"   => Some(Token::Reg(Register::V0)),
                "v1"   => Some(Token::Reg(Register::V1)),
                "v2"   => Some(Token::Reg(Register::V2)),
                "v3"   => Some(Token::Reg(Register::V3)),
                "v4"   => Some(Token::Reg(Register::V4)),
                "v5"   => Some(Token::Reg(Register::V5)),
                "v6"   => Some(Token::Reg(Register::V6)),
                "v7"   => Some(Token::Reg(Register::V7)),
                "v8"   => Some(Token::Reg(Register::V8)),
                "v9"   => Some(Token::Reg(Register::V9)),
                "va"   => Some(Token::Reg(Register::Va)),
                "vb"   => Some(Token::Reg(Register::Vb)),
                "vc"   => Some(Token::Reg(Register::Vc)),
                "vd"   => Some(Token::Reg(Register::Vd)),
                "ve"   => Some(Token::Reg(Register::Ve)),
                "vf"   => Some(Token::Reg(Register::Vf)),
                "sp"   => Some(Token::Reg(Register::Sp)),
                "st"   => Some(Token::Reg(Register::St)),
                "dt"   => Some(Token::Reg(Register::Dt)),
                "pc"   => Some(Token::Reg(Register::Pc)),
                "i"    => Some(Token::Reg(Register::I)),
                "[i]"  => Some(Token::Reg(Register::IVal)),
                _      => None
            }
        }

        match token_str.as_str() {
            "add"   => Some(Token::Opcode(Mnemonic::Add)),
            "call"  => Some(Token::Opcode(Mnemonic::Call)),
            "cls"   => Some(Token::Opcode(Mnemonic::Cls)),
            "drw"   => Some(Token::Opcode(Mnemonic::Drw)),
            "jp"    => Some(Token::Opcode(Mnemonic::Jp)),
            "ld"    => Some(Token::Opcode(Mnemonic::Ld)),
            "or"    => Some(Token::Opcode(Mnemonic::Or)),
            "ret"   => Some(Token::Opcode(Mnemonic::Ret)),
            "rnd"   => Some(Token::Opcode(Mnemonic::Rnd)),
            "se"    => Some(Token::Opcode(Mnemonic::Se)),
            "shl"   => Some(Token::Opcode(Mnemonic::Shl)),
            "shr"   => Some(Token::Opcode(Mnemonic::Shr)),
            "sknp"  => Some(Token::Opcode(Mnemonic::Sknp)),
            "skp"   => Some(Token::Opcode(Mnemonic::Skp)),
            "sne"   => Some(Token::Opcode(Mnemonic::Sne)),
            "sub"   => Some(Token::Opcode(Mnemonic::Sub)),
            "subn"  => Some(Token::Opcode(Mnemonic::Subn)),
            "sys"   => Some(Token::Opcode(Mnemonic::Sys)),
            "xor"   => Some(Token::Opcode(Mnemonic::Xor)),
            _       => None
        }
    }

    fn is_separator(b: u8) -> bool {
        match b as char {
            ','|' '|'\n' => { true }
            _ => { false }
        }
    }

    fn is_register(input: &str) -> bool {
        input == "v0" || input == "v1" || input == "v2" ||
        input == "v3" || input == "v4" || input == "v5" ||
        input == "v6" || input == "v7" || input == "v8" ||
        input == "v9" || input == "va" || input == "vb" ||
        input == "vc" || input == "vd" || input == "ve" ||
        input == "vf" || input == "sp" || input == "st" ||
        input == "dt" || input == "pc" || input == "i" ||
        input == "[i]"
    }

    fn is_numeric(input: &str) -> bool {
        if input.len() < 1 {
            return false;
        }

        let in_bytes = input.as_bytes();
        if !Stream::is_ascii_numeric(in_bytes[0]) {
            return false;
        }

        // hex
        if input.starts_with("0x") {
            for i in 2..(in_bytes.len()) {
                if !Stream::is_ascii_hex(in_bytes[i]) {
                    return false
                }
                return true
            }
        } else {
            for b in in_bytes {
                if !Stream::is_ascii_numeric(*b) {
                    return false
                }
                return true
            }
        }
        false
    }

    fn is_ascii_numeric(input: u8) -> bool {
        input >= 48 && input <= 57
    }

    fn is_ascii_hex(input: u8) -> bool {
        (input >= 48 && input <= 57) || ((input >= 97 && input <= 102) || (input >= 65 && input <= 70))
    }
}

fn main() {
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate serenity;
extern crate rand;
extern crate typemap;
extern crate stalch;
extern crate seximal;

use std::io;
use stalch::{run_with_state, InOuter, State, Result as StalchResult};

use std::env;
use std::result::Result as StdResult;
use typemap::Key;

use rand::Rng;
use rand::thread_rng;

use serenity::prelude::*;
use serenity::model::*;
use serenity::Result;
use serenity::utils;

use serenity::framework::StandardFramework;

const PREFIX: &str = "f>";
const WESTMANN: UserId = UserId(229154015626264577);
const MEMES: ChannelId = ChannelId(306454829738491904);

command!(info(_ctx, msg, _args) {
    msg.channel_id.send_message(|cm| {
        cm.embed(|e| {
            e.title("lfalchbot")
             .colour(utils::Colour::blue())
             .description("(c) LFalch.com 2017")
             .footer(|f| f.text(serenity::constants::USER_AGENT))
        })
    }).unwrap();
});

command!(setgame(ctx, _msg, args) {
    ctx.set_game(Game::playing(&args.join(" ")));
});

command!(rpn(_ctx, msg, args) {
    match calculate(&*args) {
        Ok(r) => msg.reply(&format!("Result: {}", r)),
        Err(e) => msg.reply(&format!("Error: {:?}", e))
    }.unwrap();
});

command!(stalch(_ctx, msg, args) {
    match stalch_run(args.join(" ") + "\n") {
        Ok((r, s)) => {
            if r.is_empty() {
                msg.reply(&format!("Stack:\n```\n{}\n```", s))
            } else {
                msg.reply(&format!("Output:\n```\n{}\n```", r))
            }
        }
        Err(e) => msg.reply(&format!("Error: {:?}", e))
    }.unwrap();
});

command!(seximal(_ctx, msg, args) {
    let s = args.join("");
    match seximal::to_seximal_words(&s) {
        Ok(ref s) => msg.reply(s),
        Err(_) => msg.reply("Malformed number")
    }.unwrap();
});

const CSGO_MSGS: [&str; 6] = [
    "Vi varmer op med en comp!",
    "Jeg er på!",
    "Jeg er mere til Call of Duty ..",
    "Сука блядь!",
    "-skyder en bot for at få dens Bizon-",
    "Mongoskrald!"
];

const BEARTOOTH: [&str; 3] = [
    "I’m not useless! I’m just the king of excuses!",
    "One life and one decision! Make sure it ends with you still living!",
    "Lorteskat på T-shirts."
];

const RESPONSES: [&str; 4] = [
    "Undskyld, kan ikke snakke lige nu :(",
    "Hey, kan jeg ringe igen senere?",
    "Hva' så, din noob!? :P",
    "Ad, hvem er du?"
];

const REDALERT: [&str; 4] = [
    "Your base is under a salt!",
    "Det gamle lortespil?",
    "Jeg er mere til CSGO.",
    "\"Mine depleted\" ..."
];

struct BotUser;

impl Key for BotUser {
    type Value = String;
}

struct Handler;

fn main() {
    let token = env::var("DISCORD_TOKEN")
        .expect("Expected a token in the environment");
    let mut client = Client::new(&token, Handler);

    client.with_framework(StandardFramework::new()
        .configure(|c| c.prefix(PREFIX))
        .command("ping", |c| c.exec_str("Pong!"))
        .on("info", info)
        .on("setgame", setgame)
        .on("rpn", rpn)
        .on("stalch", stalch)
        .on("seximal", seximal)
    );

    {
        let mut data = client.data.lock();
        data.insert::<BotUser>(String::default());
    }

    if let Err(why) = client.start() {
        println!("Client error: {:?}", why);
    }
}

macro_rules! joke {
    ($s:expr; $($trigger:expr),+; $bl:block) => (
        if $($s.contains($trigger))||* $bl
    );
    ($s:expr, $channel_id:expr; $($trigger:expr),+;; $joke:expr) => (
        joke!($s; $($trigger),*; {
            $channel_id.say($joke).unwrap();
        })
    );
    ($s:expr, $channel_id:expr; $($trigger:expr),+; $jokes:expr) => (
        joke!($s; $($trigger),*; {
            send_random($channel_id, &$jokes).unwrap();
        })
    );
}

impl EventHandler for Handler {
    fn on_ready(&self, ctx: Context, ready: Ready) {
        println!("{} is connected!", ready.user.name);
        println!("Guilds:");
        for name in ready.guilds.iter().map(|g| g.id().get().unwrap().name) {
            println!("    {}", name);
        }
        {
            let mut data = ctx.data.lock();
            *data.get_mut::<BotUser>().unwrap() = ready.user.tag();
        }
    }

    fn on_message(&self, ctx: Context, msg: Message) {
        if msg.author.bot {
            return
        }
        if msg.channel_id == MEMES && msg.author.id = WESTMANN && msg.embeds.iter().any(|a| a.image.is_some()) {
            msg.channel_id.say("Den er gammel!");
        }
        let s: String = msg.content.chars()
        .filter(|c| c.is_alphanumeric())
        .flat_map(|c|c.to_lowercase())
        .collect();

        joke!(s, msg.channel_id; "css", "source";; "Hvor er mine skins!?");
        joke!(s, msg.channel_id; "csgo", "counterstrike", "globaloffensive"; CSGO_MSGS);
        joke!(s, msg.channel_id; "mc", "minecraft";; "MINECRAFT!");
        joke!(s, msg.channel_id; "beartooth"; BEARTOOTH);
        joke!(s, msg.channel_id; "rep";; "Rep mig!");
        joke!(s, msg.channel_id; "ftl";; "Zoltan shield OP");
        joke!(s, msg.channel_id; "bindingofisaac";; "Mom OP");
        joke!(s, msg.channel_id; "meme";; "krydrede migmig'er");
        joke!(s, msg.channel_id; "gunsoficarus";; "Spillere online: 85");
        joke!(s, msg.channel_id; "doom";; "Rip and tear!");
        joke!(s, msg.channel_id; "dyinglight";; "Det dér Left 4 Dead-spil?");
        joke!(s, msg.channel_id; "report";; "ReviewBrah");
        joke!(s; "english"; {
            msg.channel_id.send_message(|cm| {
                cm.embed(|e| {
                    e.image("http://dev.lfalch.com/english.jpg")
                })
            }).unwrap();
        });
        joke!(s, msg.channel_id; "warthunder", "wt", "thunder", "tankspil";; "Jeg hader World of Tanks!");
        joke!(s, msg.channel_id; "ra3", "redalert"; REDALERT);
        joke!(s, msg.channel_id; "rusland", "russia", "росси", "russisk",
        "russian", "русск", "russer";; "Communism is the ultimate goal of socialism.");

        let user = {
            ctx.data.lock().get::<BotUser>().unwrap().clone()
        };
        if msg.mentions.iter().map(|u| u.tag()).any(|u| u == user) {
            send_random(msg.channel_id, &RESPONSES).unwrap();
        }
    }
}

fn send_random(chl: ChannelId, list: &[&str]) -> Result<Message> {
    let i = thread_rng().gen_range(0, list.len());
    chl.say(list[i])
}

#[derive(Debug, Copy, Clone)]
pub enum RpnError<'a> {
    StackTooSmall,
    UnknownOperator(&'a str)
}

use RpnError::*;

pub fn calculate<'a, T: IntoIterator<Item=&'a String>>(operations: T) -> StdResult<f64, RpnError<'a>> {
    let mut stack = Vec::new();

    for operation in operations {
        if let Some(d) = operation.parse::<f64>().ok() {
            stack.push(d)
        }else{
            calc(operation, &mut stack)?
        }
    }

    stack.pop().ok_or(StackTooSmall)
}

fn calc<'a>(op: &'a str, stack: &mut Vec<f64>) -> StdResult<(), RpnError<'a>>{
    let res = match (stack.pop(), stack.pop()){
        (Some(op1), Some(op2)) => match op{
            "+"|"add" => op2 + op1,
            "-"|"sub" => op2 - op1,
            "/"|"div" => op2 / op1,
            "*"|"mul" => op2 * op1,
            "^"|"pow" => op2.powf(op1),
            "log" => op2.log(op1),
            "hypot" => op2.hypot(op1),
            "%"|"rem" => op2 % op1,
            "|"|"or" => (op2 as i64 | op1 as i64) as f64,
            "&"|"and" => (op2 as i64 & op1 as i64) as f64,
            "xor" => (op2  as i64 ^ op1 as i64) as f64,
            _ => return Err(UnknownOperator(op))
        },
        _ => return Err(StackTooSmall)
    };
    Ok(stack.push(res))
}

fn stalch_run<'a>(s: String) -> StalchResult<(String, String)> {
    let mut state = State::new();
    let mut io = InOuter::new(Vec::new(), io::repeat(b'\n'));

    run_with_state(s.as_bytes(), &mut state, &mut io)?;

    let (output, _) = io.extract();

    let s = String::from_utf8(output).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;

    Ok((s, format!("{:?}", state.stack())))
}
<commit_msg>Fix typo<commit_after>#[macro_use]
extern crate serenity;
extern crate rand;
extern crate typemap;
extern crate stalch;
extern crate seximal;

use std::io;
use stalch::{run_with_state, InOuter, State, Result as StalchResult};

use std::env;
use std::result::Result as StdResult;
use typemap::Key;

use rand::Rng;
use rand::thread_rng;

use serenity::prelude::*;
use serenity::model::*;
use serenity::Result;
use serenity::utils;

use serenity::framework::StandardFramework;

const PREFIX: &str = "f>";
const WESTMANN: UserId = UserId(229154015626264577);
const MEMES: ChannelId = ChannelId(306454829738491904);

command!(info(_ctx, msg, _args) {
    msg.channel_id.send_message(|cm| {
        cm.embed(|e| {
            e.title("lfalchbot")
             .colour(utils::Colour::blue())
             .description("(c) LFalch.com 2017")
             .footer(|f| f.text(serenity::constants::USER_AGENT))
        })
    }).unwrap();
});

command!(setgame(ctx, _msg, args) {
    ctx.set_game(Game::playing(&args.join(" ")));
});

command!(rpn(_ctx, msg, args) {
    match calculate(&*args) {
        Ok(r) => msg.reply(&format!("Result: {}", r)),
        Err(e) => msg.reply(&format!("Error: {:?}", e))
    }.unwrap();
});

command!(stalch(_ctx, msg, args) {
    match stalch_run(args.join(" ") + "\n") {
        Ok((r, s)) => {
            if r.is_empty() {
                msg.reply(&format!("Stack:\n```\n{}\n```", s))
            } else {
                msg.reply(&format!("Output:\n```\n{}\n```", r))
            }
        }
        Err(e) => msg.reply(&format!("Error: {:?}", e))
    }.unwrap();
});

command!(seximal(_ctx, msg, args) {
    let s = args.join("");
    match seximal::to_seximal_words(&s) {
        Ok(ref s) => msg.reply(s),
        Err(_) => msg.reply("Malformed number")
    }.unwrap();
});

const CSGO_MSGS: [&str; 6] = [
    "Vi varmer op med en comp!",
    "Jeg er på!",
    "Jeg er mere til Call of Duty ..",
    "Сука блядь!",
    "-skyder en bot for at få dens Bizon-",
    "Mongoskrald!"
];

const BEARTOOTH: [&str; 3] = [
    "I’m not useless! I’m just the king of excuses!",
    "One life and one decision! Make sure it ends with you still living!",
    "Lorteskat på T-shirts."
];

const RESPONSES: [&str; 4] = [
    "Undskyld, kan ikke snakke lige nu :(",
    "Hey, kan jeg ringe igen senere?",
    "Hva' så, din noob!? :P",
    "Ad, hvem er du?"
];

const REDALERT: [&str; 4] = [
    "Your base is under a salt!",
    "Det gamle lortespil?",
    "Jeg er mere til CSGO.",
    "\"Mine depleted\" ..."
];

struct BotUser;

impl Key for BotUser {
    type Value = String;
}

struct Handler;

fn main() {
    let token = env::var("DISCORD_TOKEN")
        .expect("Expected a token in the environment");
    let mut client = Client::new(&token, Handler);

    client.with_framework(StandardFramework::new()
        .configure(|c| c.prefix(PREFIX))
        .command("ping", |c| c.exec_str("Pong!"))
        .on("info", info)
        .on("setgame", setgame)
        .on("rpn", rpn)
        .on("stalch", stalch)
        .on("seximal", seximal)
    );

    {
        let mut data = client.data.lock();
        data.insert::<BotUser>(String::default());
    }

    if let Err(why) = client.start() {
        println!("Client error: {:?}", why);
    }
}

macro_rules! joke {
    ($s:expr; $($trigger:expr),+; $bl:block) => (
        if $($s.contains($trigger))||* $bl
    );
    ($s:expr, $channel_id:expr; $($trigger:expr),+;; $joke:expr) => (
        joke!($s; $($trigger),*; {
            $channel_id.say($joke).unwrap();
        })
    );
    ($s:expr, $channel_id:expr; $($trigger:expr),+; $jokes:expr) => (
        joke!($s; $($trigger),*; {
            send_random($channel_id, &$jokes).unwrap();
        })
    );
}

impl EventHandler for Handler {
    fn on_ready(&self, ctx: Context, ready: Ready) {
        println!("{} is connected!", ready.user.name);
        println!("Guilds:");
        for name in ready.guilds.iter().map(|g| g.id().get().unwrap().name) {
            println!("    {}", name);
        }
        {
            let mut data = ctx.data.lock();
            *data.get_mut::<BotUser>().unwrap() = ready.user.tag();
        }
    }

    fn on_message(&self, ctx: Context, msg: Message) {
        if msg.author.bot {
            return
        }
        if msg.channel_id == MEMES && msg.author.id == WESTMANN && msg.embeds.iter().any(|a| a.image.is_some()) {
            msg.channel_id.say("Den er gammel!");
        }
        let s: String = msg.content.chars()
        .filter(|c| c.is_alphanumeric())
        .flat_map(|c|c.to_lowercase())
        .collect();

        joke!(s, msg.channel_id; "css", "source";; "Hvor er mine skins!?");
        joke!(s, msg.channel_id; "csgo", "counterstrike", "globaloffensive"; CSGO_MSGS);
        joke!(s, msg.channel_id; "mc", "minecraft";; "MINECRAFT!");
        joke!(s, msg.channel_id; "beartooth"; BEARTOOTH);
        joke!(s, msg.channel_id; "rep";; "Rep mig!");
        joke!(s, msg.channel_id; "ftl";; "Zoltan shield OP");
        joke!(s, msg.channel_id; "bindingofisaac";; "Mom OP");
        joke!(s, msg.channel_id; "meme";; "krydrede migmig'er");
        joke!(s, msg.channel_id; "gunsoficarus";; "Spillere online: 85");
        joke!(s, msg.channel_id; "doom";; "Rip and tear!");
        joke!(s, msg.channel_id; "dyinglight";; "Det dér Left 4 Dead-spil?");
        joke!(s, msg.channel_id; "report";; "ReviewBrah");
        joke!(s; "english"; {
            msg.channel_id.send_message(|cm| {
                cm.embed(|e| {
                    e.image("http://dev.lfalch.com/english.jpg")
                })
            }).unwrap();
        });
        joke!(s, msg.channel_id; "warthunder", "wt", "thunder", "tankspil";; "Jeg hader World of Tanks!");
        joke!(s, msg.channel_id; "ra3", "redalert"; REDALERT);
        joke!(s, msg.channel_id; "rusland", "russia", "росси", "russisk",
        "russian", "русск", "russer";; "Communism is the ultimate goal of socialism.");

        let user = {
            ctx.data.lock().get::<BotUser>().unwrap().clone()
        };
        if msg.mentions.iter().map(|u| u.tag()).any(|u| u == user) {
            send_random(msg.channel_id, &RESPONSES).unwrap();
        }
    }
}

fn send_random(chl: ChannelId, list: &[&str]) -> Result<Message> {
    let i = thread_rng().gen_range(0, list.len());
    chl.say(list[i])
}

#[derive(Debug, Copy, Clone)]
pub enum RpnError<'a> {
    StackTooSmall,
    UnknownOperator(&'a str)
}

use RpnError::*;

pub fn calculate<'a, T: IntoIterator<Item=&'a String>>(operations: T) -> StdResult<f64, RpnError<'a>> {
    let mut stack = Vec::new();

    for operation in operations {
        if let Some(d) = operation.parse::<f64>().ok() {
            stack.push(d)
        }else{
            calc(operation, &mut stack)?
        }
    }

    stack.pop().ok_or(StackTooSmall)
}

fn calc<'a>(op: &'a str, stack: &mut Vec<f64>) -> StdResult<(), RpnError<'a>>{
    let res = match (stack.pop(), stack.pop()){
        (Some(op1), Some(op2)) => match op{
            "+"|"add" => op2 + op1,
            "-"|"sub" => op2 - op1,
            "/"|"div" => op2 / op1,
            "*"|"mul" => op2 * op1,
            "^"|"pow" => op2.powf(op1),
            "log" => op2.log(op1),
            "hypot" => op2.hypot(op1),
            "%"|"rem" => op2 % op1,
            "|"|"or" => (op2 as i64 | op1 as i64) as f64,
            "&"|"and" => (op2 as i64 & op1 as i64) as f64,
            "xor" => (op2  as i64 ^ op1 as i64) as f64,
            _ => return Err(UnknownOperator(op))
        },
        _ => return Err(StackTooSmall)
    };
    Ok(stack.push(res))
}

fn stalch_run<'a>(s: String) -> StalchResult<(String, String)> {
    let mut state = State::new();
    let mut io = InOuter::new(Vec::new(), io::repeat(b'\n'));

    run_with_state(s.as_bytes(), &mut state, &mut io)?;

    let (output, _) = io.extract();

    let s = String::from_utf8(output).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;

    Ok((s, format!("{:?}", state.stack())))
}
<|endoftext|>


<commit_before>extern crate crypto;
extern crate base64;
extern crate byteorder;
extern crate rand;
extern crate docopt;
extern crate rustc_serialize;

use std::process;
use std::mem;
use std::io::prelude::*;
use std::io::{self, BufReader, Cursor};
use std::fs::File;
use std::convert::AsRef;
use std::path::Path;

use rand::Rng;
use rand::os::OsRng;

use crypto::ed25519;
use crypto::digest::Digest;
use crypto::sha2::Sha512;

use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};

use docopt::Docopt;

const KEYNUMLEN : usize = 8;
const PUBLICBYTES : usize = 32;
const SECRETBYTES : usize = 64;
const SIGBYTES : usize = 64;

const PKGALG : [u8; 2] = *b"Ed";
const KDFALG : [u8; 2] = *b"BK";

const COMMENTHDR : &'static str = "untrusted comment: ";
const COMMENTHDRLEN : usize = 19;
const COMMENTMAXLEN : usize = 1024;

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

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

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

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

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

    flag_p: String,
    flag_s: String,
    flag_m: String,
}

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

struct PublicKey {
    pkgalg: [u8; 2],
    keynum: [u8; KEYNUMLEN],
    publkey: [u8; PUBLICBYTES],
}

struct PrivateKey {
   pkgalg: [u8; 2],
   kdfalg: [u8; 2],
   kdfrounds: u32,
   salt: [u8; 16],
   checksum: [u8; 8],
   keynum: [u8; KEYNUMLEN],
   seckey: [u8; SECRETBYTES],
}

struct Signature {
    pkgalg: [u8; 2],
    keynum: [u8; KEYNUMLEN],
    sig: [u8; SIGBYTES],
}

impl PublicKey {
    fn with_key_and_keynum(key: [u8; PUBLICBYTES], keynum: [u8; KEYNUMLEN]) -> PublicKey {
        PublicKey {
            pkgalg: PKGALG,
            keynum: keynum,
            publkey: key,
        }
    }

    fn write<W: Write>(&self, mut w: W) -> Result<(), io::Error> {
        try!(w.write(&self.pkgalg));
        try!(w.write(&self.keynum));
        try!(w.write(&self.publkey));

        Ok(())
    }

    fn from_buf(buf: &[u8]) -> Result<PublicKey, io::Error> {
        assert!(buf.len() >= mem::size_of::<Self>());

        let mut buf = Cursor::new(buf);

        let mut pkgalg = [0; 2];
        let mut keynum = [0; KEYNUMLEN];
        let mut publkey = [0; PUBLICBYTES];

        try!(buf.read(&mut pkgalg));
        try!(buf.read(&mut keynum));
        try!(buf.read(&mut publkey));

        Ok(PublicKey {
            pkgalg: pkgalg,
            keynum: keynum,
            publkey: publkey,
        })
    }
}

impl PrivateKey {
    fn write<W: Write>(&self, mut w: W) -> Result<(), io::Error> {
        try!(w.write(&self.pkgalg));
        try!(w.write(&self.kdfalg));
        try!(w.write_u32::<BigEndian>(self.kdfrounds));
        try!(w.write(&self.salt));
        try!(w.write(&self.checksum));
        try!(w.write(&self.keynum));
        try!(w.write(&self.seckey));

        Ok(())
    }

    fn from_buf(buf: &[u8]) -> Result<PrivateKey, io::Error> {
        assert!(buf.len() >= mem::size_of::<Self>());

        let mut buf = Cursor::new(buf);

        let mut pkgalg = [0; 2];
        let mut kdfalg = [0; 2];
        let kdfrounds;
        let mut salt = [0; 16];
        let mut checksum = [0; 8];
        let mut keynum = [0; KEYNUMLEN];
        let mut seckey = [0; SECRETBYTES];

        try!(buf.read(&mut pkgalg));
        try!(buf.read(&mut kdfalg));
        kdfrounds = try!(buf.read_u32::<BigEndian>());
        try!(buf.read(&mut salt));
        try!(buf.read(&mut checksum));
        try!(buf.read(&mut keynum));
        try!(buf.read(&mut seckey));

        Ok(PrivateKey {
            pkgalg: pkgalg,
            kdfalg: kdfalg,
            kdfrounds: kdfrounds,
            salt: salt,
            checksum: checksum,
            keynum: keynum,
            seckey: seckey,
        })
    }

    fn sign(&self, msg: &[u8]) -> Signature {
        let signature = ed25519::signature(msg, &self.seckey);
        Signature {
            pkgalg: PKGALG,
            keynum: self.keynum,
            sig: signature
        }
    }
}

impl Signature {
    fn write<W: Write>(&self, mut w: W) -> Result<(), io::Error> {
        try!(w.write(&self.pkgalg));
        try!(w.write(&self.keynum));
        try!(w.write(&self.sig));

        Ok(())
    }

    fn from_buf(buf: &[u8]) -> Result<Signature, io::Error> {
        assert!(buf.len() >= mem::size_of::<Self>());

        let mut buf = Cursor::new(buf);

        let mut pkgalg = [0; 2];
        let mut keynum = [0; KEYNUMLEN];
        let mut sig = [0; SIGBYTES];

        try!(buf.read(&mut pkgalg));
        try!(buf.read(&mut keynum));
        try!(buf.read(&mut sig));

        Ok(Signature {
            pkgalg: pkgalg,
            keynum: keynum,
            sig: sig,
        })
    }

    fn verify(&self, msg: &[u8], pkey: &PublicKey) -> bool {
        ed25519::verify(msg, &pkey.publkey, &self.sig)
    }
}

fn write_base64_file<P: AsRef<Path>>(file: P, comment: &str, buf: &[u8]) -> Result<(), io::Error> {
    let mut f = File::create(file).unwrap();

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

    Ok(())
}

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

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

    if len == 0 || len < COMMENTHDRLEN || !comment_line.starts_with(COMMENTHDR) {
        println!("invalid comment in {}; must start with '{}'", file_display, COMMENTHDR);
        process::exit(1);
    }

    if &comment_line[len-1..len] != "\n" {
        println!("missing new line after comment in '{}'", file_display);
        process::exit(1);
    }

    if len > COMMENTHDRLEN + COMMENTMAXLEN {
        println!("comment too long");
        process::exit(1);
    }

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

    if len == 0 {
        println!("missing line in {}", file_display);
        process::exit(1);
    }

    if &base64_line[len-1..len] != "\n" {
        println!("missing new line after comment in '{}'", file_display);
        process::exit(1);
    }

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

    let data = match base64::decode(&base64_line) {
        Ok(data) => data,
        Err(e) => {
            println!("invalid base64 encoding in {}: {:?}", file_display, e);
            process::exit(1);
        }
    };

    if &data[0..2] != PKGALG {
        println!("unsupported file {}", file_display);
        process::exit(1);
    }

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

fn verify(pubkey_path: String, msg_path: String, signature_path: Option<String>) {
    let pkey = match read_base64_file(&pubkey_path) {
        Ok(FileContent::PublicKey(pkey)) => pkey,
        _ => {
            println!("an error occured.");
            process::exit(2);
        }
    };

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

    let signature = match read_base64_file(&signature_path) {
        Ok(FileContent::Signature(sig)) => sig,
        _ => {
            println!("Can't read signature from '{}'", signature_path);
            process::exit(2);
        }
    };

    let mut msgfile = File::open(&msg_path).expect(&format!("Can't open message file '{}'", msg_path));
    let mut msg = vec![];
    msgfile.read_to_end(&mut msg).expect(&format!("Can't read file '{}'", msg_path));

    if signature.verify(&msg, &pkey) {
        println!("Signature Verified");
    } else {
        println!("signature verification failed");
        process::exit(1);
    }
}

fn sign(seckey_path: String, msg_path: String, signature_path: Option<String>) {
    let skey = match read_base64_file(&seckey_path) {
        Ok(FileContent::PrivateKey(skey)) => skey,
        _ => {
            println!("an error occured.");
            process::exit(2);
        }
    };

    let mut msgfile = File::open(&msg_path).expect(&format!("Can't open message file '{}'", msg_path));
    let mut msg = vec![];
    msgfile.read_to_end(&mut msg).expect(&format!("Can't read file '{}'", msg_path));

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

    let sig = skey.sign(&msg);

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

    let sig_comment = "signature from signify secret key";
    write_base64_file(&signature_path, sig_comment, &out).unwrap();
}

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

    let mut keynum = [0; KEYNUMLEN];

    let mut rng = OsRng::new().expect("Can't create random number generator");
    rng.fill_bytes(&mut keynum);

    let mut seed = [0; 32];
    rng.fill_bytes(&mut seed);
    let (skey, pkey) = ed25519::keypair(&seed);

    // Store private key
    let mut ctx = Sha512::new();
    ctx.input(&skey);
    let mut digest = [0; 64];
    ctx.result(&mut digest);
    let mut checksum = [0; 8];
    checksum.copy_from_slice(&digest[0..8]);

    let mut salt = [0; 16];
    rng.fill_bytes(&mut salt);

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

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

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

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

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

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

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

    if args.flag_V {
        verify(args.flag_p, args.flag_m, args.flag_x);
    } else if args.flag_G {
        generate(args.flag_p, args.flag_s, args.flag_c);
    } else if args.flag_S {
        sign(args.flag_s, args.flag_m, args.flag_x);
    }
}
<commit_msg>refactor: Remove unnecessary reference<commit_after>extern crate crypto;
extern crate base64;
extern crate byteorder;
extern crate rand;
extern crate docopt;
extern crate rustc_serialize;

use std::process;
use std::mem;
use std::io::prelude::*;
use std::io::{self, BufReader, Cursor};
use std::fs::File;
use std::convert::AsRef;
use std::path::Path;

use rand::Rng;
use rand::os::OsRng;

use crypto::ed25519;
use crypto::digest::Digest;
use crypto::sha2::Sha512;

use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};

use docopt::Docopt;

const KEYNUMLEN : usize = 8;
const PUBLICBYTES : usize = 32;
const SECRETBYTES : usize = 64;
const SIGBYTES : usize = 64;

const PKGALG : [u8; 2] = *b"Ed";
const KDFALG : [u8; 2] = *b"BK";

const COMMENTHDR : &'static str = "untrusted comment: ";
const COMMENTHDRLEN : usize = 19;
const COMMENTMAXLEN : usize = 1024;

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

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

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

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

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

    flag_p: String,
    flag_s: String,
    flag_m: String,
}

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

struct PublicKey {
    pkgalg: [u8; 2],
    keynum: [u8; KEYNUMLEN],
    publkey: [u8; PUBLICBYTES],
}

struct PrivateKey {
   pkgalg: [u8; 2],
   kdfalg: [u8; 2],
   kdfrounds: u32,
   salt: [u8; 16],
   checksum: [u8; 8],
   keynum: [u8; KEYNUMLEN],
   seckey: [u8; SECRETBYTES],
}

struct Signature {
    pkgalg: [u8; 2],
    keynum: [u8; KEYNUMLEN],
    sig: [u8; SIGBYTES],
}

impl PublicKey {
    fn with_key_and_keynum(key: [u8; PUBLICBYTES], keynum: [u8; KEYNUMLEN]) -> PublicKey {
        PublicKey {
            pkgalg: PKGALG,
            keynum: keynum,
            publkey: key,
        }
    }

    fn write<W: Write>(&self, mut w: W) -> Result<(), io::Error> {
        try!(w.write(&self.pkgalg));
        try!(w.write(&self.keynum));
        try!(w.write(&self.publkey));

        Ok(())
    }

    fn from_buf(buf: &[u8]) -> Result<PublicKey, io::Error> {
        assert!(buf.len() >= mem::size_of::<Self>());

        let mut buf = Cursor::new(buf);

        let mut pkgalg = [0; 2];
        let mut keynum = [0; KEYNUMLEN];
        let mut publkey = [0; PUBLICBYTES];

        try!(buf.read(&mut pkgalg));
        try!(buf.read(&mut keynum));
        try!(buf.read(&mut publkey));

        Ok(PublicKey {
            pkgalg: pkgalg,
            keynum: keynum,
            publkey: publkey,
        })
    }
}

impl PrivateKey {
    fn write<W: Write>(&self, mut w: W) -> Result<(), io::Error> {
        try!(w.write(&self.pkgalg));
        try!(w.write(&self.kdfalg));
        try!(w.write_u32::<BigEndian>(self.kdfrounds));
        try!(w.write(&self.salt));
        try!(w.write(&self.checksum));
        try!(w.write(&self.keynum));
        try!(w.write(&self.seckey));

        Ok(())
    }

    fn from_buf(buf: &[u8]) -> Result<PrivateKey, io::Error> {
        assert!(buf.len() >= mem::size_of::<Self>());

        let mut buf = Cursor::new(buf);

        let mut pkgalg = [0; 2];
        let mut kdfalg = [0; 2];
        let kdfrounds;
        let mut salt = [0; 16];
        let mut checksum = [0; 8];
        let mut keynum = [0; KEYNUMLEN];
        let mut seckey = [0; SECRETBYTES];

        try!(buf.read(&mut pkgalg));
        try!(buf.read(&mut kdfalg));
        kdfrounds = try!(buf.read_u32::<BigEndian>());
        try!(buf.read(&mut salt));
        try!(buf.read(&mut checksum));
        try!(buf.read(&mut keynum));
        try!(buf.read(&mut seckey));

        Ok(PrivateKey {
            pkgalg: pkgalg,
            kdfalg: kdfalg,
            kdfrounds: kdfrounds,
            salt: salt,
            checksum: checksum,
            keynum: keynum,
            seckey: seckey,
        })
    }

    fn sign(&self, msg: &[u8]) -> Signature {
        let signature = ed25519::signature(msg, &self.seckey);
        Signature {
            pkgalg: PKGALG,
            keynum: self.keynum,
            sig: signature
        }
    }
}

impl Signature {
    fn write<W: Write>(&self, mut w: W) -> Result<(), io::Error> {
        try!(w.write(&self.pkgalg));
        try!(w.write(&self.keynum));
        try!(w.write(&self.sig));

        Ok(())
    }

    fn from_buf(buf: &[u8]) -> Result<Signature, io::Error> {
        assert!(buf.len() >= mem::size_of::<Self>());

        let mut buf = Cursor::new(buf);

        let mut pkgalg = [0; 2];
        let mut keynum = [0; KEYNUMLEN];
        let mut sig = [0; SIGBYTES];

        try!(buf.read(&mut pkgalg));
        try!(buf.read(&mut keynum));
        try!(buf.read(&mut sig));

        Ok(Signature {
            pkgalg: pkgalg,
            keynum: keynum,
            sig: sig,
        })
    }

    fn verify(&self, msg: &[u8], pkey: &PublicKey) -> bool {
        ed25519::verify(msg, &pkey.publkey, &self.sig)
    }
}

fn write_base64_file<P: AsRef<Path>>(file: P, comment: &str, buf: &[u8]) -> Result<(), io::Error> {
    let mut f = File::create(file).unwrap();

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

    Ok(())
}

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

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

    if len == 0 || len < COMMENTHDRLEN || !comment_line.starts_with(COMMENTHDR) {
        println!("invalid comment in {}; must start with '{}'", file_display, COMMENTHDR);
        process::exit(1);
    }

    if &comment_line[len-1..len] != "\n" {
        println!("missing new line after comment in '{}'", file_display);
        process::exit(1);
    }

    if len > COMMENTHDRLEN + COMMENTMAXLEN {
        println!("comment too long");
        process::exit(1);
    }

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

    if len == 0 {
        println!("missing line in {}", file_display);
        process::exit(1);
    }

    if &base64_line[len-1..len] != "\n" {
        println!("missing new line after comment in '{}'", file_display);
        process::exit(1);
    }

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

    let data = match base64::decode(base64_line) {
        Ok(data) => data,
        Err(e) => {
            println!("invalid base64 encoding in {}: {:?}", file_display, e);
            process::exit(1);
        }
    };

    if &data[0..2] != PKGALG {
        println!("unsupported file {}", file_display);
        process::exit(1);
    }

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

fn verify(pubkey_path: String, msg_path: String, signature_path: Option<String>) {
    let pkey = match read_base64_file(&pubkey_path) {
        Ok(FileContent::PublicKey(pkey)) => pkey,
        _ => {
            println!("an error occured.");
            process::exit(2);
        }
    };

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

    let signature = match read_base64_file(&signature_path) {
        Ok(FileContent::Signature(sig)) => sig,
        _ => {
            println!("Can't read signature from '{}'", signature_path);
            process::exit(2);
        }
    };

    let mut msgfile = File::open(&msg_path).expect(&format!("Can't open message file '{}'", msg_path));
    let mut msg = vec![];
    msgfile.read_to_end(&mut msg).expect(&format!("Can't read file '{}'", msg_path));

    if signature.verify(&msg, &pkey) {
        println!("Signature Verified");
    } else {
        println!("signature verification failed");
        process::exit(1);
    }
}

fn sign(seckey_path: String, msg_path: String, signature_path: Option<String>) {
    let skey = match read_base64_file(&seckey_path) {
        Ok(FileContent::PrivateKey(skey)) => skey,
        _ => {
            println!("an error occured.");
            process::exit(2);
        }
    };

    let mut msgfile = File::open(&msg_path).expect(&format!("Can't open message file '{}'", msg_path));
    let mut msg = vec![];
    msgfile.read_to_end(&mut msg).expect(&format!("Can't read file '{}'", msg_path));

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

    let sig = skey.sign(&msg);

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

    let sig_comment = "signature from signify secret key";
    write_base64_file(&signature_path, sig_comment, &out).unwrap();
}

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

    let mut keynum = [0; KEYNUMLEN];

    let mut rng = OsRng::new().expect("Can't create random number generator");
    rng.fill_bytes(&mut keynum);

    let mut seed = [0; 32];
    rng.fill_bytes(&mut seed);
    let (skey, pkey) = ed25519::keypair(&seed);

    // Store private key
    let mut ctx = Sha512::new();
    ctx.input(&skey);
    let mut digest = [0; 64];
    ctx.result(&mut digest);
    let mut checksum = [0; 8];
    checksum.copy_from_slice(&digest[0..8]);

    let mut salt = [0; 16];
    rng.fill_bytes(&mut salt);

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

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

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

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

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

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

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

    if args.flag_V {
        verify(args.flag_p, args.flag_m, args.flag_x);
    } else if args.flag_G {
        generate(args.flag_p, args.flag_s, args.flag_c);
    } else if args.flag_S {
        sign(args.flag_s, args.flag_m, args.flag_x);
    }
}
<|endoftext|>