<commit_before>use crossbeam_channel::bounded;
use crossbeam_channel::Receiver;
use crossbeam_channel::Sender;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::thread;
use std::vec::Vec;

#[derive(Debug)]
struct TranscodeJob {
    src: PathBuf,
    dest: PathBuf,
}

fn main() {
    const NTHREADS: i32 = 4;

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

    let pathbuf = match args.len() {
        2 => PathBuf::from(&args[1]),
        _ => env::current_dir().unwrap(),
    };

    println!("looking for videos at: {}", pathbuf.display());

    thread::scope(|s| {
        let (job_sender, job_recv) = bounded::<TranscodeJob>(0);

        for i in 0..NTHREADS {
            let job_recv = job_recv.clone();
            s.spawn(move || transcoder(i, job_recv));
        }

        jobscheduler(pathbuf.as_path(), job_sender);
    });

    println!("done");
}

fn jobscheduler(path: &Path, job_sender: Sender<TranscodeJob>) {
    println!("starting job scheduler");

    let entries = fs::read_dir(path).unwrap();
    let mut srcs = Vec::new();

    for entry in entries {
        match entry {
            Ok(entry) => {
                let path = entry.path();
                if let Some(extension) = path.extension() {
                    let extension = extension
                        .to_str()
                        .expect("file extensions should be valid utf-8");

                    match extension {
                        "avi" => {
                            srcs.push(path);
                        }
                        _ => {
                            println!("ignoring file with extension: {}", extension)
                        }
                    }
                }
            }
            Err(err) => {
                print!("error reading dir {}: {}", path.display(), err);
            }
        }
    }

    let job = TranscodeJob {
        src: PathBuf::from("src"),
        dest: PathBuf::from("dest"),
    };
    job_sender.send(job).expect("failed to send job to workers");
    drop(job_sender);
}

fn transcoder(id: i32, job_recv: Receiver<TranscodeJob>) {
    println!("starting transcoder {}", id);

    while let Ok(job) = job_recv.recv() {
        println!(
            "transcoder {} transcoding from {} to {}",
            id,
            job.src.display(),
            job.dest.display()
        );
    }

    println!("finishing transcoder {}", id);
}
<commit_msg>feat: add destdir arg<commit_after>use crossbeam_channel::bounded;
use crossbeam_channel::Receiver;
use crossbeam_channel::Sender;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::ExitCode;
use std::thread;
use std::vec::Vec;

#[derive(Debug)]
struct TranscodeJob {
    src: PathBuf,
    dest: PathBuf,
}

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

    let (srcdir, destdir) = match args.len() {
        1 => {
            let src = env::current_dir().unwrap();
            let mut dest = src.clone();
            dest.push("transcoded");
            (src, dest)
        }
        3 => (PathBuf::from(&args[1]), PathBuf::from(&args[2])),
        _ => {
            println!("usage using current dir: {}", args[0]);
            println!("usage explicit dirs: {} <src dir> <dest dir>", args[0]);
            std::process::exit(1)
        }
    };

    println!(
        "videos src: {} dest: {}",
        srcdir.display(),
        destdir.display()
    );

    thread::scope(|s| {
        const NTHREADS: i32 = 4;

        let (job_sender, job_recv) = bounded::<TranscodeJob>(0);

        for i in 0..NTHREADS {
            let job_recv = job_recv.clone();
            s.spawn(move || transcoder(i, job_recv));
        }

        jobscheduler(srcdir.as_path(), job_sender);
    });

    println!("done");

    ExitCode::SUCCESS
}

fn jobscheduler(path: &Path, job_sender: Sender<TranscodeJob>) {
    println!("starting job scheduler");

    let entries = fs::read_dir(path).unwrap();
    let mut srcs = Vec::new();

    for entry in entries {
        match entry {
            Ok(entry) => {
                let path = entry.path();
                if let Some(extension) = path.extension() {
                    let extension = extension
                        .to_str()
                        .expect("file extensions should be valid utf-8");

                    match extension {
                        "avi" => {
                            srcs.push(path);
                        }
                        _ => {
                            println!("ignoring file with extension: {}", extension)
                        }
                    }
                }
            }
            Err(err) => {
                print!("error reading dir {}: {}", path.display(), err);
            }
        }
    }

    let job = TranscodeJob {
        src: PathBuf::from("src"),
        dest: PathBuf::from("dest"),
    };
    job_sender.send(job).expect("failed to send job to workers");
    drop(job_sender);
}

fn transcoder(id: i32, job_recv: Receiver<TranscodeJob>) {
    println!("starting transcoder {}", id);

    while let Ok(job) = job_recv.recv() {
        println!(
            "transcoder {} transcoding from {} to {}",
            id,
            job.src.display(),
            job.dest.display()
        );
    }

    println!("finishing transcoder {}", id);
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate ast;
extern crate rand;
extern crate rustc_serialize;

use rustc_serialize::json;

use ast::structure::{Program,Command};
use ast::data::{SensorData,Evaluate};
use ast::source::Source;

fn main() {
	let program: Program = iff!(less!(vx!(),multiply!(constant!(2.0000),constant!(3.0000))),left!(),right!());

	let data: SensorData = SensorData { x: 37.0, y: 51.0, vx: 1.0, vy: 0.0, o: 0.0, w: 0.0 };

	let command = program.evaluate(data);

	let message = match **command {
		Command::Skip  => "skip",
		Command::Left  => "turnLeft",
		Command::Right => "turnRight",
		Command::Up    => "thruster",
	};

	println!("{}", program.source());
	println!("{}", json::encode(&program).unwrap());
	println!("action is {}", message);

	let generated: Program = rand::random();
	println!("{}", generated.source());
}
<commit_msg>Temporary fix for stackoverflow<commit_after>#[macro_use]
extern crate ast;
extern crate rand;
extern crate rustc_serialize;

use rustc_serialize::json;

use ast::structure::{Program,Command};
use ast::data::{SensorData,Evaluate};
use ast::source::Source;

fn main() {
	let program: Program = iff!(less!(vx!(),multiply!(constant!(2.0000),constant!(3.0000))),left!(),right!());

	let data: SensorData = SensorData { x: 37.0, y: 51.0, vx: 1.0, vy: 0.0, o: 0.0, w: 0.0 };

	let command = program.evaluate(data);

	let message = match **command {
		Command::Skip  => "skip",
		Command::Left  => "turnLeft",
		Command::Right => "turnRight",
		Command::Up    => "thruster",
	};

	println!("{}", program.source());
	println!("{}", json::encode(&program).unwrap());
	println!("action is {}", message);

	// let generated: Program = rand::random();
	// println!("{}", generated.source());
}
<|endoftext|>


<commit_before>extern crate branch_destroyer;
extern crate clap;

use branch_destroyer::*;
use clap::{App, Arg};

fn main() {
    let matches = get_args();

    let days_ago = match matches.value_of("days").unwrap().parse::<u32>() {
        Ok(x) => x,
        Err(e) => {
            println!("unable to parse --days because {}", e);
            panic!(e);
        }
    };

    let mut ctx = Context {
        token: matches.value_of("token").unwrap().to_string(),
        owner: matches.value_of("owner").unwrap().to_string(),
        repo: matches.value_of("repo").unwrap().to_string(),
        repo_id: 0,
        default_branch: "Develop".to_string(),
        days_ago
    };

    get_repository(&mut ctx);

    println!("Context: {:?}", ctx);

    let branches = get_branches(&ctx);
    let total_branches = branches.len();

    let branches_info: Vec<BranchInfo> = branches
        .into_iter()
        .filter(|x| x.name != "master")
        .filter(|x| x.name != "develop")
        //.filter(|x| x.name == "andrew/minivan-fixer")
        .take(100)
        .map(|x| get_branch_compare_info(&ctx, x))
//        .filter(|x| x.age.num_days() >= ctx.days_ago)
        .collect();

    let branches_to_delete = branches_info.iter().filter(|x| will_delete(x, &ctx)).collect();

    print_branch_info(&branches_info, &ctx);
    print_summary(&ctx, &branches_to_delete, total_branches);
}

fn print_summary(ctx: &Context, branches: &Vec<&BranchInfo>, total_branches: usize) {
    println!();
    println!("Found {} branches to delete out of {} branches total for {}/{}. SHAME SHAME SHAME", branches.len(), total_branches, ctx.owner, ctx.repo )
}

fn get_args<'a>() -> clap::ArgMatches<'a> {
    App::new("branch-destroyer")
        .version("1.0")
        .author("Andrew Varnerin <andrew@varnerin.info>")
        .about(
            "Hunts down and destroys useless branches with little remorse",
        )
        .arg(
            Arg::with_name("token")
                .short("t")
                .long("token")
                .value_name("TOKEN")
                .takes_value(true)
                .required(true)
                .help(
                    "Personal OAuth token with permissions to read/write repo info",
                ),
        )
        .arg(
            Arg::with_name("owner")
            .short("o")
            .long("owner")
            .value_name("OWNER")
            .takes_value(true)
            .required(true)
            .help(
                "Owner of the repository to run the branch destroyer against"
            )
        )
        .arg(
            Arg::with_name("repo")
            .short("r")
            .long("repo")
            .value_name("REPOSITORY")
            .takes_value(true)
            .required(true)
            .help(
                "Repository to run the branch destroyer against. You must have read/write permissions to this repository"
            )
        )
        .arg(
            Arg::with_name("days")
            .short("d")
            .long("days")
            .value_name("DAYS")
            .takes_value(true)
            .default_value("7")
            .help(
                "Filters to branches whose last commit was created at least this many days ago"
            )
        )
        .get_matches()
}
<commit_msg>Update main.rs<commit_after>extern crate branch_destroyer;
extern crate clap;

use branch_destroyer::*;
use clap::{App, Arg};

fn main() {
    let matches = get_args();

    let days_ago = match matches.value_of("days").unwrap().parse::<u32>() {
        Ok(x) => x,
        Err(e) => {
            println!("unable to parse --days because {}", e);
            panic!(e);
        }
    };

    let mut ctx = Context {
        token: matches.value_of("token").unwrap().to_string(),
        owner: matches.value_of("owner").unwrap().to_string(),
        repo: matches.value_of("repo").unwrap().to_string(),
        repo_id: 0,
        default_branch: "Develop".to_string(),
        days_ago
    };

    get_repository(&mut ctx);

    println!("Context: {:?}", ctx);

    let branches = get_branches(&ctx);
    let total_branches = branches.len();

    let branches_info: Vec<BranchInfo> = branches
        .into_iter()
        .filter(|x| x.name != "master")
        .filter(|x| x.name != "develop")
        .take(100)
        .map(|x| get_branch_compare_info(&ctx, x))
        .collect();

    let branches_to_delete = branches_info.iter().filter(|x| will_delete(x, &ctx)).collect();

    print_branch_info(&branches_info, &ctx);
    print_summary(&ctx, &branches_to_delete, total_branches);
}

fn print_summary(ctx: &Context, branches: &Vec<&BranchInfo>, total_branches: usize) {
    println!();
    println!("Found {} branches to delete out of {} branches total for {}/{}. SHAME SHAME SHAME", branches.len(), total_branches, ctx.owner, ctx.repo )
}

fn get_args<'a>() -> clap::ArgMatches<'a> {
    App::new("branch-destroyer")
        .version("1.0")
        .author("Andrew Varnerin <andrew@varnerin.info>")
        .about(
            "Hunts down and destroys useless branches with little remorse",
        )
        .arg(
            Arg::with_name("token")
                .short("t")
                .long("token")
                .value_name("TOKEN")
                .takes_value(true)
                .required(true)
                .help(
                    "Personal OAuth token with permissions to read/write repo info",
                ),
        )
        .arg(
            Arg::with_name("owner")
            .short("o")
            .long("owner")
            .value_name("OWNER")
            .takes_value(true)
            .required(true)
            .help(
                "Owner of the repository to run the branch destroyer against"
            )
        )
        .arg(
            Arg::with_name("repo")
            .short("r")
            .long("repo")
            .value_name("REPOSITORY")
            .takes_value(true)
            .required(true)
            .help(
                "Repository to run the branch destroyer against. You must have read/write permissions to this repository"
            )
        )
        .arg(
            Arg::with_name("days")
            .short("d")
            .long("days")
            .value_name("DAYS")
            .takes_value(true)
            .default_value("7")
            .help(
                "Filters to branches whose last commit was created at least this many days ago"
            )
        )
        .get_matches()
}
<|endoftext|>


<commit_before>use csv;
use io::Write;
use std::env;
use std::io;
use std::process;
use table::ascii_table_writer;

const HELP_MESSAGE: &str = r#"
Usage:
  table -h | --help
  table -v | --version

Options:
  -h --help     Print help message
  -v --version  Print version
"#;

const VERSION: &str = "0.3.0";

fn main() {
    for (i, arg) in env::args().enumerate() {
        if i == 0 {
            continue;
        }

        match &*arg {
            "-h" | "--help" => {
                println!("{}", HELP_MESSAGE.trim());
                process::exit(0);
            }
            "-v" | "--version" => {
                println!("{}", VERSION);
                process::exit(0);
            }
            _ => println!("TODO: implement other flags"),
        }
    }

    if let Err(error) = start() {
        println!("{}", error);
        process::exit(0);
    }
}

fn start() -> io::Result<()> {
    let mut reader = csv::ReaderBuilder::new()
        .delimiter(b'\t')
        .has_headers(false)
        .from_reader(io::stdin());

    let mut writer = ascii_table_writer::new(io::stdout());

    for result in reader.records() {
        if let Err(error) = result {
            println!("failed to read TSV: {}", error);
            process::exit(1);
        }

        let record = result.unwrap();

        for field in record.iter() {
            writer.write(field.as_bytes())?;
        }

        writer.write(b"\n")?;
    }

    writer.flush()
}
<commit_msg>Print error message to stderr<commit_after>use csv;
use io::Write;
use std::env;
use std::io;
use std::process;
use table::ascii_table_writer;

const HELP_MESSAGE: &str = r#"
Usage:
  table -h | --help
  table -v | --version

Options:
  -h --help     Print help message
  -v --version  Print version
"#;

const VERSION: &str = "0.3.0";

fn main() {
    for (i, arg) in env::args().enumerate() {
        if i == 0 {
            continue;
        }

        match &*arg {
            "-h" | "--help" => {
                println!("{}", HELP_MESSAGE.trim());
                process::exit(0);
            }
            "-v" | "--version" => {
                println!("{}", VERSION);
                process::exit(0);
            }
            _ => eprintln!("TODO: implement other flags"),
        }
    }

    if let Err(error) = start() {
        eprintln!("{}", error);
        process::exit(0);
    }
}

fn start() -> io::Result<()> {
    let mut reader = csv::ReaderBuilder::new()
        .delimiter(b'\t')
        .has_headers(false)
        .from_reader(io::stdin());

    let mut writer = ascii_table_writer::new(io::stdout());

    for result in reader.records() {
        if let Err(error) = result {
            eprintln!("failed to read TSV: {}", error);
            process::exit(1);
        }

        let record = result.unwrap();

        for field in record.iter() {
            writer.write(field.as_bytes())?;
        }

        writer.write(b"\n")?;
    }

    writer.flush()
}
<|endoftext|>


<commit_before>// src/main.rs

#[macro_use]
extern crate nickel;

extern crate rustc_serialize;
extern crate jwt;
extern crate hyper;
extern crate crypto;
extern crate chrono;

#[macro_use(bson, doc)]
extern crate bson;
extern crate mongodb;

// Money Map Crate
extern crate money_map;

//Logging
#[macro_use]
extern crate log;
extern crate log4rs;

// Import
// External
use crypto::sha2::Sha256;
use hyper::header::{self, Authorization, Bearer};
use jwt::{Header, Registered, Token};
use nickel::{MiddlewareResult, Nickel, Response, Request};
use nickel::status::StatusCode::{Forbidden};
// Common Utilities
use money_map::common::data_access::ServerData;
use money_map::common::database::DB;
use money_map::common::config::Config;
use money_map::common::routes;
//DAO
use money_map::dao::dao_manager::{DAOManager};
//Controllers
use money_map::controllers::controller_manager::ControllerManager;
use money_map::controllers::test_controller::TestController;
use money_map::controllers::users_controller::UsersController;

fn main() {
    //Setup logging
    log4rs::init_file("config/log.toml", Default::default()).unwrap();
    info!("Initializing API");

    //Load Configuration
    let configuration = Config::new();

    //Initialize Database Connection
    let db = match DB::new(configuration.clone()){
        Ok(db) => db,
        Err(e) => {
            //Cannot create database connection
            panic!("{}", e);
        }
    };

    //Initialize DAO Manager
    let dao_manager = DAOManager::new(db);

    //Initialize Controllers
    let controller_manager = ControllerManager{
        test_controller: TestController::new(dao_manager.clone()),
        users_controller: UsersController::new(dao_manager.clone(), configuration.clone())
    };

    //Initialize Data Access object
    let server_data = ServerData{
        config: configuration,
        controller_manager: controller_manager
    };

    let mut server = Nickel::with_data(server_data);

    server.utilize(authenticator);
    server.utilize(routes::get_routes());

    server.listen("0.0.0.0:6767");
}

//TODO: Use the auth secret set in config by passing Config to a new data object passed to Nickel
static AUTH_SECRET: &'static str = "B@4GWjJZ6bKHa1o99Bmv@nWMNh7tNR";
fn authenticator<'mw>(request: &mut Request<ServerData>, response: Response<'mw, ServerData> ) ->MiddlewareResult<'mw, ServerData> {
  // Check if we are getting an OPTIONS request
  if request.origin.method.to_string() == "OPTIONS".to_string() {
      // The middleware should not be used for OPTIONS, so continue
      response.next_middleware()
  } else {
    // We do not want to apply the middleware to the login route
    if request.origin.uri.to_string() == "/users/login".to_string() {
        response.next_middleware()
    } else {
        // Get the full Authorization header from the incoming request headers
        let auth_header = match request.origin.headers.get::<Authorization<Bearer>>() {
            Some(header) => header,
            None => {
                return response.error(Forbidden, "Access denied. Authentication required.");
            }
        };

        // Format the header to only take the value
        let jwt = header::HeaderFormatter(auth_header).to_string();

        // We don't need the Bearer part,
        // so get whatever is after an index of 7
        let jwt_slice = &jwt[7..];

        // Parse the token
        if let Ok(token) = Token::<Header, Registered>::parse(jwt_slice){
            // Get the secret key as bytes
            let secret = AUTH_SECRET.as_bytes();

            // Verify the token
            if token.verify(&secret, Sha256::new()) {
                response.next_middleware()
            } else {
                response.error(Forbidden, "Access denied. Invalid token.")
            }
        }else{
            response.error(Forbidden, "Access denied. Invalid token format.")
        }

    }
  }

}
<commit_msg>Use config auth_secret to verify authentication tokens in authenticator<commit_after>// src/main.rs

#[macro_use]
extern crate nickel;

extern crate rustc_serialize;
extern crate jwt;
extern crate hyper;
extern crate crypto;
extern crate chrono;

#[macro_use(bson, doc)]
extern crate bson;
extern crate mongodb;

// Money Map Crate
extern crate money_map;

//Logging
#[macro_use]
extern crate log;
extern crate log4rs;

// Import
// External
use crypto::sha2::Sha256;
use hyper::header::{self, Authorization, Bearer};
use jwt::{Header, Registered, Token};
use nickel::{MiddlewareResult, Nickel, Response, Request};
use nickel::status::StatusCode::{Forbidden};
// Common Utilities
use money_map::common::data_access::ServerData;
use money_map::common::database::DB;
use money_map::common::config::Config;
use money_map::common::routes;
//DAO
use money_map::dao::dao_manager::{DAOManager};
//Controllers
use money_map::controllers::controller_manager::ControllerManager;
use money_map::controllers::test_controller::TestController;
use money_map::controllers::users_controller::UsersController;

fn main() {
    //Setup logging
    log4rs::init_file("config/log.toml", Default::default()).unwrap();
    info!("Initializing API");

    //Load Configuration
    let configuration = Config::new();

    //Initialize Database Connection
    let db = match DB::new(configuration.clone()){
        Ok(db) => db,
        Err(e) => {
            //Cannot create database connection
            panic!("{}", e);
        }
    };

    //Initialize DAO Manager
    let dao_manager = DAOManager::new(db);

    //Initialize Controllers
    let controller_manager = ControllerManager{
        test_controller: TestController::new(dao_manager.clone()),
        users_controller: UsersController::new(dao_manager.clone(), configuration.clone())
    };

    //Initialize Data Access object
    let server_data = ServerData{
        config: configuration,
        controller_manager: controller_manager
    };

    let mut server = Nickel::with_data(server_data);

    server.utilize(authenticator);
    server.utilize(routes::get_routes());

    server.listen("0.0.0.0:6767");
}

fn authenticator<'mw>(request: &mut Request<ServerData>, response: Response<'mw, ServerData> ) ->MiddlewareResult<'mw, ServerData> {
    let server_data: &ServerData = request.server_data();

    // Check if we are getting an OPTIONS request
    if request.origin.method.to_string() == "OPTIONS".to_string() {
        // The middleware should not be used for OPTIONS, so continue
        response.next_middleware()
    } else {
        // We do not want to apply the middleware to the login route
        if request.origin.uri.to_string() == "/users/login".to_string() {
            response.next_middleware()
        } else {
            // Get the full Authorization header from the incoming request headers
            let auth_header = match request.origin.headers.get::<Authorization<Bearer>>() {
                Some(header) => header,
                None => {
                    return response.error(Forbidden, "Access denied. Authentication required.");
                }
            };

            // Format the header to only take the value
            let jwt = header::HeaderFormatter(auth_header).to_string();

            // We don't need the Bearer part,
            // so get whatever is after an index of 7
            let jwt_slice = &jwt[7..];

            // Parse the token
            if let Ok(token) = Token::<Header, Registered>::parse(jwt_slice){
                if let Some(ref auth_secret) = server_data.config.auth.auth_secret{
                    let secret = auth_secret.as_bytes();

                    // Verify the token
                    if token.verify(&secret, Sha256::new()) {
                        return response.next_middleware();
                    } else {
                        return response.error(Forbidden, "Access denied. Invalid token.");
                    }
                }
                error!("Authentication failure. Unable to verify JWT Toke. No auth_secret key.");
            }
            response.error(Forbidden, "Access denied. Invalid token format.")
        }
    }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

extern crate devicemapper;
#[macro_use]
extern crate clap;

use std::io::Result;
#[allow(unused_imports)]
use std::io::Write;
use std::error::Error;
use std::process::exit;

use devicemapper as devm;
use clap::{App, Arg, SubCommand, ArgMatches};

static mut debug: bool = false;

macro_rules! dbgp {
    ($($arg:tt)*) => (
        unsafe {
            if debug {
                println!($($arg)*)
            }
        })
}

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

fn list(args: &ArgMatches) -> Result<()> {
    println!("hello from list()");
    Ok(())
}

fn add(args: &ArgMatches) -> Result<()> {
    println!("hello from add()");
    Ok(())
}

fn main() {

    let matches = App::new("froyo")
        .version(&crate_version!())
        .author("Andy Grover <andy@groveronline.com>")
        .about("Drobo + Free + YOLO")
        .arg(Arg::with_name("debug")
             .short("d")
             .help("Print additional output for debugging")
             )
        .subcommand(SubCommand::with_name("list")
                    .about("List all froyodevs")
                    .arg(Arg::with_name("long")
                         .short("l")
                         .help("Use a long listing format"))
                    )
        .subcommand(SubCommand::with_name("status")
                    .about("Get the status of a single froyodev")
                    .arg(Arg::with_name("froyodevname")
                         .required(true)
                         .help("Froyodev to get info on")
                         .index(1))
                    )
        .subcommand(SubCommand::with_name("add")
                    .about("Add one or more additional block devices to a froyodev")
                    .arg(Arg::with_name("froyodevname")
                         .help("Froyodev to add the device to")
                         .required(true)
                         .index(1))
                    .arg(Arg::with_name("devices")
                         .help("device to add")
                         .multiple(true)
                         .required(true)
                         .index(2))
                    )
        .subcommand(SubCommand::with_name("remove")
                    .about("Remove a block device from a froyodev")
                    .arg(Arg::with_name("froyodevname")
                         .help("Froyodev to remove the device from")
                         .required(true)
                         .index(1))
                    .arg(Arg::with_name("device")
                         .help("Block device to remove")
                         .required(true)
                         .index(2))
                    )
        .subcommand(SubCommand::with_name("create")
                    .about("Create a new froyodev")
                    .arg(Arg::with_name("froyodevname")
                         .help("Name of the new froyodev")
                         .required(true)
                         .index(1))
                    .arg(Arg::with_name("devices")
                         .help("Initial block device(s) to use")
                         .multiple(true)
                         .required(true)
                         .index(2))
                    )
        .get_matches();

    if matches.is_present("debug") {
        // must use unsafe to change a mut static, sigh
        unsafe { debug = true };
    }

    let r = match matches.subcommand() {
        ("list", Some(matches)) => list(matches),
        ("add", Some(matches)) => add(matches),
        ("", None) => {
            println!("No command given, try \"help\"");
            Ok(())
        }
        _ => unreachable!(),
    };

    if let Err(r) = r {
        println!("there was an error: {}", r.description());
        exit(1);
    };
}
<commit_msg>Stub out more subcommands<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

extern crate devicemapper;
#[macro_use]
extern crate clap;

use std::io::Result;
#[allow(unused_imports)]
use std::io::Write;
use std::error::Error;
use std::process::exit;

use devicemapper as devm;
use clap::{App, Arg, SubCommand, ArgMatches};

static mut debug: bool = false;

macro_rules! dbgp {
    ($($arg:tt)*) => (
        unsafe {
            if debug {
                println!($($arg)*)
            }
        })
}

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

fn list(args: &ArgMatches) -> Result<()> {
    println!("hello from list()");
    Ok(())
}

fn status(args: &ArgMatches) -> Result<()> {
    println!("hello from status()");
    Ok(())
}

fn add(args: &ArgMatches) -> Result<()> {
    println!("hello from add()");
    Ok(())
}

fn remove(args: &ArgMatches) -> Result<()> {
    println!("hello from remove()");
    Ok(())
}

fn create(args: &ArgMatches) -> Result<()> {
    let name = args.value_of("froyodev").unwrap();
    let devs = args.values_of("devices").unwrap();
    dbgp!("Creating {}", name);
    Ok(())
}

fn main() {

    let matches = App::new("froyo")
        .version(&crate_version!())
        .author("Andy Grover <andy@groveronline.com>")
        .about("Drobo + Free + YOLO")
        .arg(Arg::with_name("debug")
             .short("d")
             .help("Print additional output for debugging")
             )
        .subcommand(SubCommand::with_name("list")
                    .about("List all froyodevs")
                    .arg(Arg::with_name("long")
                         .short("l")
                         .help("Use a long listing format"))
                    )
        .subcommand(SubCommand::with_name("status")
                    .about("Get the status of a single froyodev")
                    .arg(Arg::with_name("froyodevname")
                         .required(true)
                         .help("Froyodev to get info on")
                         .index(1))
                    )
        .subcommand(SubCommand::with_name("add")
                    .about("Add one or more additional block devices to a froyodev")
                    .arg(Arg::with_name("froyodevname")
                         .help("Froyodev to add the device to")
                         .required(true)
                         .index(1))
                    .arg(Arg::with_name("devices")
                         .help("device(s) to add")
                         .multiple(true)
                         .required(true)
                         .index(2))
                    )
        .subcommand(SubCommand::with_name("remove")
                    .about("Remove a block device from a froyodev")
                    .arg(Arg::with_name("froyodevname")
                         .help("Froyodev to remove the device from")
                         .required(true)
                         .index(1))
                    .arg(Arg::with_name("devices")
                         .help("Block device(s) to remove")
                         .multiple(true)
                         .required(true)
                         .index(2))
                    )
        .subcommand(SubCommand::with_name("create")
                    .about("Create a new froyodev")
                    .arg(Arg::with_name("froyodevname")
                         .help("Name of the new froyodev")
                         .required(true)
                         .index(1))
                    .arg(Arg::with_name("devices")
                         .help("Initial block device(s) to use")
                         .multiple(true)
                         .required(true)
                         .index(2))
                    )
        .get_matches();

    if matches.is_present("debug") {
        // must use unsafe to change a mut static, sigh
        unsafe { debug = true };
    }

    let r = match matches.subcommand() {
        ("list", Some(matches)) => list(matches),
        ("status", Some(matches)) => status(matches),
        ("add", Some(matches)) => add(matches),
        ("remove", Some(matches)) => remove(matches),
        ("create", Some(matches)) => create(matches),
        ("", None) => {
            println!("No command given, try \"help\"");
            Ok(())
        }
        _ => unreachable!(),
    };

    if let Err(r) = r {
        println!("there was an error: {}", r.description());
        exit(1);
    };
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Nikita Pekin and the smexybot contributors
// See the README.md file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![deny(missing_docs)]
#![deny(non_camel_case_types)]
#![cfg_attr(feature = "nightly", feature(proc_macro))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![warn(missing_copy_implementations,
        missing_debug_implementations,
        missing_docs,
        trivial_numeric_casts,
        unsafe_code,
        unused_extern_crates,
        unused_import_braces,
        unused_qualifications)]
#![cfg_attr(feature="clippy", warn(cast_possible_truncation))]
#![cfg_attr(feature="clippy", warn(cast_possible_wrap))]
#![cfg_attr(feature="clippy", warn(cast_precision_loss))]
#![cfg_attr(feature="clippy", warn(cast_sign_loss))]
#![cfg_attr(feature="clippy", warn(mut_mut))]
// This allows us to use `unwrap` on `Option` values when compiling in test mode
// (because using it in tests is idiomatic).
#![cfg_attr(all(not(test), feature="clippy"), warn(result_unwrap_used))]
#![cfg_attr(feature="clippy", warn(wrong_pub_self_convention))]

//! Smexybot is a general-purpose [Discord](https://discordapp.com/) bot written
//! in [Rust](https://www.rust-lang.org/). It is built upon the
//! [serenity.rs](https://github.com/zeyla/serenity.rs) Discord API.

extern crate env_logger;
extern crate hyper;
#[cfg(any(feature = "roll", feature = "wolfram", feature = "xkcd"))]
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate rand;
extern crate serde;
#[cfg(feature = "nightly")]
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serenity;
extern crate url;

mod command;
mod error;
mod util;

use std::env;

use serenity::Client;
use serenity::client::{Context, LoginType};
use serenity::ext::framework::Framework;
use serenity::model::Message;

use util::check_msg;

// The prefix to search for when looking for commands in messages.
const COMMAND_PREFIX: &'static str = "!";
// The ID of the author of the bot.
const AUTHOR_ID: u64 = 117530756263182344;

fn main() {
    // Initialize the `env_logger` to provide logging output.
    env_logger::init().expect("Failed to initialize env_logger");

    // Create a client for a user.
    let (_, mut client) = login();

    client.on_ready(|_context, ready| {
        println!(
            "[Ready] {} is serving {} guilds!",
            ready.user.name,
            ready.guilds.len(),
        );
    });

    client.with_framework(build_framework);

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

// Configures the `Framework` used by serenity, and registers the handlers for
// any enabled commands.
fn build_framework(framework: Framework) -> Framework {
    let mut framework = framework.configure(|c| c
        .prefix(COMMAND_PREFIX))
    .before(|_context, message, command_name| {
        debug!(
            "Got command '{}' from user '{}'",
            command_name,
            message.author.name,
        );

        true
    })
    .after(|context, _message, command_name, error| {
        if let Err(err) = error {
            check_msg(context.say(&err));
        } else {
            debug!("Processed command '{}'", command_name);
        }
    });

    #[cfg(feature = "fuyu")]
    {
        framework = framework.on("fuyu", command::fuyu::handler);
    }
    #[cfg(feature = "ping")]
    {
        framework = framework.command("ping", |c| c
            .check(owner_check)
            .exec_str("Pong!")
        );
    }
    #[cfg(feature = "roll")]
    {
        framework = framework.on("roll", command::roll::handler);
    }
    #[cfg(feature = "tag")]
    {
        framework = framework.on("tag", command::tag::handler);
    }
    #[cfg(feature = "wolfram")]
    {
        framework = framework.on("wolfram", command::wolfram_alpha::handler);
    }
    #[cfg(feature = "xkcd")]
    {
        framework = framework.on("xkcd", command::xkcd::handler);
    }

    framework
}

fn owner_check(_: &Context, message: &Message) -> bool {
    message.author.id == AUTHOR_ID
}

// Creates a `Client`.
fn login() -> (LoginType, Client) {
    debug!("Attempting to login");

    if let Ok(bot_token) = env::var("DISCORD_BOT_TOKEN") {
        debug!("Performing bot token login");
        return (
            LoginType::Bot,
            Client::login_bot(&bot_token),
        )
    }
    debug!("Skipping bot token login");

    if let Ok(user_token) = env::var("DISCORD_USER_TOKEN") {
        debug!("Performing user token login");
        return (
            LoginType::User,
            Client::login_user(&user_token),
        )
    }
    debug!("Skipping user token login");

    panic!("No suitable authentication method found");
}
<commit_msg>impr: change command prefix to `;`<commit_after>// Copyright (c) 2016 Nikita Pekin and the smexybot contributors
// See the README.md file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![deny(missing_docs)]
#![deny(non_camel_case_types)]
#![cfg_attr(feature = "nightly", feature(proc_macro))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![warn(missing_copy_implementations,
        missing_debug_implementations,
        missing_docs,
        trivial_numeric_casts,
        unsafe_code,
        unused_extern_crates,
        unused_import_braces,
        unused_qualifications)]
#![cfg_attr(feature="clippy", warn(cast_possible_truncation))]
#![cfg_attr(feature="clippy", warn(cast_possible_wrap))]
#![cfg_attr(feature="clippy", warn(cast_precision_loss))]
#![cfg_attr(feature="clippy", warn(cast_sign_loss))]
#![cfg_attr(feature="clippy", warn(mut_mut))]
// This allows us to use `unwrap` on `Option` values when compiling in test mode
// (because using it in tests is idiomatic).
#![cfg_attr(all(not(test), feature="clippy"), warn(result_unwrap_used))]
#![cfg_attr(feature="clippy", warn(wrong_pub_self_convention))]

//! Smexybot is a general-purpose [Discord](https://discordapp.com/) bot written
//! in [Rust](https://www.rust-lang.org/). It is built upon the
//! [serenity.rs](https://github.com/zeyla/serenity.rs) Discord API.

extern crate env_logger;
extern crate hyper;
#[cfg(any(feature = "roll", feature = "wolfram", feature = "xkcd"))]
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate rand;
extern crate serde;
#[cfg(feature = "nightly")]
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serenity;
extern crate url;

mod command;
mod error;
mod util;

use std::env;

use serenity::Client;
use serenity::client::{Context, LoginType};
use serenity::ext::framework::Framework;
use serenity::model::Message;

use util::check_msg;

// The prefix to search for when looking for commands in messages.
const COMMAND_PREFIX: &'static str = ";";
// The ID of the author of the bot.
const AUTHOR_ID: u64 = 117530756263182344;

fn main() {
    // Initialize the `env_logger` to provide logging output.
    env_logger::init().expect("Failed to initialize env_logger");

    // Create a client for a user.
    let (_, mut client) = login();

    client.on_ready(|_context, ready| {
        println!(
            "[Ready] {} is serving {} guilds!",
            ready.user.name,
            ready.guilds.len(),
        );
    });

    client.with_framework(build_framework);

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

// Configures the `Framework` used by serenity, and registers the handlers for
// any enabled commands.
fn build_framework(framework: Framework) -> Framework {
    let mut framework = framework.configure(|c| c
        .prefix(COMMAND_PREFIX))
    .before(|_context, message, command_name| {
        debug!(
            "Got command '{}' from user '{}'",
            command_name,
            message.author.name,
        );

        true
    })
    .after(|context, _message, command_name, error| {
        if let Err(err) = error {
            check_msg(context.say(&err));
        } else {
            debug!("Processed command '{}'", command_name);
        }
    });

    #[cfg(feature = "fuyu")]
    {
        framework = framework.on("fuyu", command::fuyu::handler);
    }
    #[cfg(feature = "ping")]
    {
        framework = framework.command("ping", |c| c
            .check(owner_check)
            .exec_str("Pong!")
        );
    }
    #[cfg(feature = "roll")]
    {
        framework = framework.on("roll", command::roll::handler);
    }
    #[cfg(feature = "tag")]
    {
        framework = framework.on("tag", command::tag::handler);
    }
    #[cfg(feature = "wolfram")]
    {
        framework = framework.on("wolfram", command::wolfram_alpha::handler);
    }
    #[cfg(feature = "xkcd")]
    {
        framework = framework.on("xkcd", command::xkcd::handler);
    }

    framework
}

fn owner_check(_: &Context, message: &Message) -> bool {
    message.author.id == AUTHOR_ID
}

// Creates a `Client`.
fn login() -> (LoginType, Client) {
    debug!("Attempting to login");

    if let Ok(bot_token) = env::var("DISCORD_BOT_TOKEN") {
        debug!("Performing bot token login");
        return (
            LoginType::Bot,
            Client::login_bot(&bot_token),
        )
    }
    debug!("Skipping bot token login");

    if let Ok(user_token) = env::var("DISCORD_USER_TOKEN") {
        debug!("Performing user token login");
        return (
            LoginType::User,
            Client::login_user(&user_token),
        )
    }
    debug!("Skipping user token login");

    panic!("No suitable authentication method found");
}
<|endoftext|>


<commit_before>#[macro_use(crate_version, crate_authors)]
extern crate clap;

extern crate api_server;
extern crate devices;
extern crate sys_util;
extern crate vmm;

use clap::{App, Arg};

use sys_util::syslog;

fn main() {
    if let Err(e) = syslog::init() {
        println!("failed to initialize syslog: {:?}", e);
        return;
    }

    let cmd_arguments = App::new("firecracker")
        .version(crate_version!())
        .author(crate_authors!())
        .about("Launch a microvm.")
        .arg(
            Arg::with_name("kill_api")
                .long("kill-api")
                .help("Kill the REST API server on vmm exit")
                .takes_value(false),
        )
        .arg(
            Arg::with_name("api_port")
                .short("p")
                .long("api-port")
                .help("The TCP listen port for the REST API")
                .required(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("kernel_path")
                .short("k")
                .long("kernel-path")
                .help("The kernel's file path (vmlinux.bin)")
                .required(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("kernel_cmdline")
                .long("kernel-cmdline")
                .help("The kernel's command line")
                .default_value("console=ttyS0 noapic reboot=k panic=1 pci=off")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("mem_size")
                .long("mem-size")
                .default_value("128")
                .help("Virtual Machine Memory Size in MiB")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("vcpu_count")
                .long("vcpu-count")
                .default_value("1")
                .help("Number of VCPUs")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("root_blk_file")
                .short("r")
                .long("root-blk")
                .help("File to serve as root block device")
                .takes_value(true)
        )
        .arg(
            Arg::with_name("host_ip")
                .long("host-ip")
                .help("IPv4 address of the host interface")
                .takes_value(true)
        )
        .arg(
            Arg::with_name("subnet_mask")
                .long("subnet-mask")
                .default_value("255.255.255.0")
                .help("Subnet mask for the IP address of host interface")
                .takes_value(true)
        )
        /*
        The mac address option is not currently implemented; the L2 addresses for both the
        host interface and the guest interface take some implicit (possibly random) values
        .arg(
            Arg::with_name("mac_address")
                .long("mac-addr")
                .help("MAC address for the VM")
                .takes_value(true)
        )*/
        .get_matches();

    api_server::start_api_server(&cmd_arguments).expect("cannot start api server");
}
<commit_msg>main: Disable module loading at boot time<commit_after>#[macro_use(crate_version, crate_authors)]
extern crate clap;

extern crate api_server;
extern crate devices;
extern crate sys_util;
extern crate vmm;

use clap::{App, Arg};

use sys_util::syslog;

fn main() {
    if let Err(e) = syslog::init() {
        println!("failed to initialize syslog: {:?}", e);
        return;
    }

    let cmd_arguments = App::new("firecracker")
        .version(crate_version!())
        .author(crate_authors!())
        .about("Launch a microvm.")
        .arg(
            Arg::with_name("kill_api")
                .long("kill-api")
                .help("Kill the REST API server on vmm exit")
                .takes_value(false),
        )
        .arg(
            Arg::with_name("api_port")
                .short("p")
                .long("api-port")
                .help("The TCP listen port for the REST API")
                .required(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("kernel_path")
                .short("k")
                .long("kernel-path")
                .help("The kernel's file path (vmlinux.bin)")
                .required(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("kernel_cmdline")
                .long("kernel-cmdline")
                .help("The kernel's command line")
                .default_value("console=ttyS0 noapic reboot=k panic=1 pci=off nomodules")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("mem_size")
                .long("mem-size")
                .default_value("128")
                .help("Virtual Machine Memory Size in MiB")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("vcpu_count")
                .long("vcpu-count")
                .default_value("1")
                .help("Number of VCPUs")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("root_blk_file")
                .short("r")
                .long("root-blk")
                .help("File to serve as root block device")
                .takes_value(true)
        )
        .arg(
            Arg::with_name("host_ip")
                .long("host-ip")
                .help("IPv4 address of the host interface")
                .takes_value(true)
        )
        .arg(
            Arg::with_name("subnet_mask")
                .long("subnet-mask")
                .default_value("255.255.255.0")
                .help("Subnet mask for the IP address of host interface")
                .takes_value(true)
        )
        /*
        The mac address option is not currently implemented; the L2 addresses for both the
        host interface and the guest interface take some implicit (possibly random) values
        .arg(
            Arg::with_name("mac_address")
                .long("mac-addr")
                .help("MAC address for the VM")
                .takes_value(true)
        )*/
        .get_matches();

    api_server::start_api_server(&cmd_arguments).expect("cannot start api server");
}
<|endoftext|>


<commit_before>extern crate tempfile;
extern crate rustyline;

mod lexer;
mod parser;
mod evaluator;
mod error;
mod constants;
mod function;

use rustyline::error::ReadlineError;
use rustyline::Editor;
use tempfile::NamedTempFile;
use constants::VERSION;
use lexer::lexer;
use parser::Parser;
use evaluator::Evaluator;
use error::{LexerError, ParserError, EvaluatorError};

fn prelude() {
    println!("bspl {}", VERSION);
    println!("Bit-Shift-Print Loop");
    println!("Type 'help', 'license', or 'version' for more information.");
}

fn error_message(width: usize, msg: &str) {
    println!("{caret:>width$}\n.. {}", msg, caret = "^", width = width);
}

fn display_results(results: Vec<String>) {
    let mut result_iter = results.iter();
    while let Some(result) = result_iter.next() {
        println!(".. {}", result);
    }

    if let Some(final_result) = results.last() {
        let parsed_final_result = final_result.parse::<u32>();
        if parsed_final_result.is_ok() {
            let parsed_final_result = parsed_final_result.unwrap();
            println!("D: {}", parsed_final_result);
            println!("H: {:#x}", parsed_final_result);
            println!("B: {:#b}", parsed_final_result);
        }
    }
}

fn repl() {
    let mut repl = Editor::<()>::new();
    let prompt = "=> ";
    let prompt_len = prompt.len() + 1;
    let tmp_file = NamedTempFile::new().unwrap();
    let _ = repl.load_history(tmp_file.path());

    let mut parser = Parser::default();
    let evaluator = Evaluator::default();

    loop {
        match repl.readline(prompt) {
            Ok(line) => {
                repl.add_history_entry(&line);
                match lexer(&line) {
                    Ok(tokens) => {
                        match parser.parse(tokens) {
                            Ok(parsed_tokens) => {
                                match evaluator.evaluate(parsed_tokens) {
                                    Ok(result) => {
                                        display_results(result);
                                    }
                                    Err(EvaluatorError::MissingArgument(position)) => {
                                        error_message(position + prompt_len,
                                                      "Missing argument from expression");
                                    }
                                    Err(EvaluatorError::TooManyArguments) => {
                                        error_message(prompt_len,
                                                      "Too many arguments in expression");
                                    }
                                    Err(EvaluatorError::OverflowShift(position)) => {
                                        error_message(position + prompt_len,
                                                      "Shift overflow error");
                                    }
                                    Err(EvaluatorError::UnknownKeyword(position)) => {
                                        error_message(position + prompt_len, "Not a valid keyword");
                                    }
                                    Err(EvaluatorError::Exit) => break,
                                }
                            }
                            Err(ParserError::MissingOpeningBracket(position)) => {
                                error_message(position + prompt_len, "Missing an opening bracket");
                            }
                            Err(ParserError::MissingClosingBracket(position)) => {
                                error_message(position + prompt_len, "Missing a closing bracket");
                            }
                            Err(ParserError::KeywordError(position)) => {
                                error_message(position + prompt_len,
                                              "Cannot use keyword in expression");
                            }
                        }
                    }
                    Err(LexerError::RadixError(position)) => {
                        error_message(position + prompt_len,
                                      "Not a valid decimal, hexadecimal, or keyword");
                    }
                    Err(LexerError::UnknownOperator(position)) => {
                        error_message(position + prompt_len, "Not a valid operator");
                    }
                }
            }
            Err(ReadlineError::Eof) => break,
            Err(ReadlineError::Interrupted) => {
                println!("Type 'exit' or press Ctrl-D to leave bspl");
                continue;
            }
            Err(err) => {
                println!("Error: {:?}", err);
                break;
            }

        }
        repl.save_history(tmp_file.path()).unwrap();
    }
}

pub fn main() {
    prelude();
    repl();
}
<commit_msg>Deduplicate final result<commit_after>extern crate tempfile;
extern crate rustyline;

mod lexer;
mod parser;
mod evaluator;
mod error;
mod constants;
mod function;

use rustyline::error::ReadlineError;
use rustyline::Editor;
use tempfile::NamedTempFile;
use constants::VERSION;
use lexer::lexer;
use parser::Parser;
use evaluator::Evaluator;
use error::{LexerError, ParserError, EvaluatorError};

fn prelude() {
    println!("bspl {}", VERSION);
    println!("Bit-Shift-Print Loop");
    println!("Type 'help', 'license', or 'version' for more information.");
}

fn error_message(width: usize, msg: &str) {
    println!("{caret:>width$}\n.. {}", msg, caret = "^", width = width);
}

fn display_results(results: Vec<String>) {
    if let Some((final_result, results)) = results.split_last(){
        for result in results {
            println!(".. {}", result);
        }

        let parsed_final_result = final_result.parse::<u32>().unwrap();
        println!("D: {}", parsed_final_result);
        println!("H: {:#x}", parsed_final_result);
        println!("B: {:#b}", parsed_final_result);
    }
}

fn repl() {
    let mut repl = Editor::<()>::new();
    let prompt = "=> ";
    let prompt_len = prompt.len() + 1;
    let tmp_file = NamedTempFile::new().unwrap();
    let _ = repl.load_history(tmp_file.path());

    let mut parser = Parser::default();
    let evaluator = Evaluator::default();

    loop {
        match repl.readline(prompt) {
            Ok(line) => {
                repl.add_history_entry(&line);
                match lexer(&line) {
                    Ok(tokens) => {
                        match parser.parse(tokens) {
                            Ok(parsed_tokens) => {
                                match evaluator.evaluate(parsed_tokens) {
                                    Ok(result) => {
                                        display_results(result);
                                    }
                                    Err(EvaluatorError::MissingArgument(position)) => {
                                        error_message(position + prompt_len,
                                                      "Missing argument from expression");
                                    }
                                    Err(EvaluatorError::TooManyArguments) => {
                                        error_message(prompt_len,
                                                      "Too many arguments in expression");
                                    }
                                    Err(EvaluatorError::OverflowShift(position)) => {
                                        error_message(position + prompt_len,
                                                      "Shift overflow error");
                                    }
                                    Err(EvaluatorError::UnknownKeyword(position)) => {
                                        error_message(position + prompt_len, "Not a valid keyword");
                                    }
                                    Err(EvaluatorError::Exit) => break,
                                }
                            }
                            Err(ParserError::MissingOpeningBracket(position)) => {
                                error_message(position + prompt_len, "Missing an opening bracket");
                            }
                            Err(ParserError::MissingClosingBracket(position)) => {
                                error_message(position + prompt_len, "Missing a closing bracket");
                            }
                            Err(ParserError::KeywordError(position)) => {
                                error_message(position + prompt_len,
                                              "Cannot use keyword in expression");
                            }
                        }
                    }
                    Err(LexerError::RadixError(position)) => {
                        error_message(position + prompt_len,
                                      "Not a valid decimal, hexadecimal, or keyword");
                    }
                    Err(LexerError::UnknownOperator(position)) => {
                        error_message(position + prompt_len, "Not a valid operator");
                    }
                }
            }
            Err(ReadlineError::Eof) => break,
            Err(ReadlineError::Interrupted) => {
                println!("Type 'exit' or press Ctrl-D to leave bspl");
                continue;
            }
            Err(err) => {
                println!("Error: {:?}", err);
                break;
            }

        }
        repl.save_history(tmp_file.path()).unwrap();
    }
}

pub fn main() {
    prelude();
    repl();
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>Lace implemented<commit_after>use std::env;
use std::fs::File;
use std::io::{Read, copy, stdin, stdout};
use std::process::Command;

extern crate tempfile;

use tempfile::NamedTempFile;

fn lookup_program() -> String {
    match env::var_os("VISUAL") {
        Some(val) => val,
        None => env::var_os("EDITOR").expect("Set $VISUAL or $EDITOR to use edfp")
    }.into_string().unwrap()
}

fn edfp<I: Read>(mut input: I) -> File {
    let mut tmp: NamedTempFile = NamedTempFile::new().expect("failed to create temporary file");
    copy(&mut input, &mut tmp).unwrap();

    let editor_program = lookup_program();
    let tmp_path_str = tmp.path().to_str().expect("failed to parse tmp path");
    let editor = Command::new(editor_program.as_str()).arg(tmp_path_str).spawn();

    let success = editor
        .ok()
        .expect(format!("failed to launch {}", editor_program).as_str())
        .wait()
        .expect(format!("failed to wait for {}", editor_program).as_str())
        .success();

    if !success {
        panic!(format!("{} exited non-zero", editor_program));
    }

    tmp.reopen().ok().expect("failed to re-open")
}

fn main() {
    let input = stdin();
    let mut output = stdout();
    copy(&mut edfp(input), &mut output).unwrap();
}
<|endoftext|>


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

extern crate getopts;
extern crate ihex;
extern crate regex;

use std::env;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::process;

use getopts::Options;

pub mod assembler;
use assembler::assembler::*;
use assembler::data_range;
use assembler::ihex_writer;
use assembler::parser::*;
use assembler::scanner::Scanner;

// MARK: - Assembler

fn assemble_file<F>(input_path: &str, output_path: &str, log_error: F) where F : Fn(&str) -> () {

  // Open the input file (read-only).
  let mut input_file = File::open(input_path).unwrap_or_else(|reason| {
    log_error(&format!("Unable to open input file '{}'", input_path));
    log_error(&reason.to_string());
    process::exit(1);
  });

  let mut buffer = String::new();

  // Read the contents of the input file into the buffer.
  input_file.read_to_string(&mut buffer).unwrap_or_else(|reason| {
    log_error(&format!("Unable to read contents of input file '{}'", input_path));
    log_error(&reason.to_string());
    process::exit(1);
  });

  // Create a scanner over the input.
  let scanner = Scanner::new(input_path, &buffer);

  // Parse the input into an abstract syntax list form. Errors are pre-formatted.
  let syntax_list = parse(scanner).unwrap_or_else(|message| {
    println!("{}", message);
    process::exit(1);
  });

  // Assemble the syntax list into data ranges. Errors are pre-formatted.
  let data_ranges = assemble(syntax_list).unwrap_or_else(|message| {
    println!("{}", message);
    process::exit(1);
  });

  // Verify no overlapping data ranges exist in the result.
  let overlapping_ranges = data_range::find_overlapping_ranges(&data_ranges);
  if overlapping_ranges.len() > 0 {
    log_error("Input file specifies overlapping data ranges.");
    log_error("Data from one section has overflowed into the adjacent.");

    // Emit overlapping data range information.
    for (a, b) in overlapping_ranges {
      log_error(&format!("  range {} overlaps with:", a));
      log_error(&format!("  range {}", b));
    }

    process::exit(1);
  }

  // Convert the data ranges to Intel I8HEX format.
  let result = ihex_writer::ihex_representation_of_data_ranges(&data_ranges);

  // Open the output file for writing (truncate) or use stdout if the specified path is `-`.
  let mut output_file: Box<io::Write> = match output_path {
    "-" => Box::new(io::stdout()),
    path @ _ => {
      Box::new(
        File::create(output_path).unwrap_or_else(|reason| {
          log_error(&format!("Unable to create output file '{}'", path));
          log_error(&reason.to_string());
          process::exit(1);
        })
      )
    }
  };

  // Write the result to the output file.
  output_file.write_all(result.as_bytes()).unwrap_or_else(|reason| {
    log_error(&format!("Unable to write result to output file '{}'", output_path));
    log_error(&reason.to_string());
    process::exit(1);
  });
}

// MARK: - Option Processing

/**
 Displays usage information for the tool.
 @param program The path to the executable as invoked (argv[0]).
 @param options A fully-constructed options bundle for the tool.
 */
fn print_usage(program: &str, options: Options) {
  let brief = format!("USAGE: {} [options] <input>", program);
  print!("{}", options.usage(&brief));
}

/**
 Displays the program name and version information.
 */
fn print_version() {
  println!("c8s version {}", env!("CARGO_PKG_VERSION"));
}

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

  let mut options = Options::new();
  options.optopt ("o", "output",  "Write output to <file>", "<file>");
  options.optflag("h", "help",    "Display available options");
  options.optflag("v", "version", "Display version information");

  // Parse the command-line arguments and exit in the event an invalid argument is encountered.
  let matches = options.parse(&arguments[1..]).unwrap_or_else(|reason| {
    println!("{}: error: {}", program, reason.to_string());
    process::exit(1);
  });

  // Help requested.
  if matches.opt_present("h") {
    print_usage(&program, options);
    return;
  }

  // Version information requested.
  if matches.opt_present("v") {
    print_version();
    return;
  }

  // Extract the output file name, and default to 'a.hex' if not specified.
  let output_path = &matches.opt_str("o").unwrap_or(String::from("a.hex"));

  // Allow one single input file name parameter.
  let input_path = match matches.free.len() {
    1 => &matches.free[0],
    _ => {
      print_usage(&program, options);
      process::exit(1);
    }
  };

  // Execute the assembler, in the event of failure, log an error and exit.
  assemble_file(input_path, output_path, |reason| {
    println!("{}: error: {}", program, reason);
  });
}
<commit_msg>Extra clarity around main wrapper.<commit_after>
#[macro_use] extern crate lazy_static;
#[macro_use] extern crate twelve_bit;

extern crate getopts;
extern crate ihex;
extern crate regex;

use std::env;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::process;

use getopts::Options;

pub mod assembler;
use assembler::assembler::*;
use assembler::data_range;
use assembler::ihex_writer;
use assembler::parser::*;
use assembler::scanner::Scanner;

// MARK: - Assembler

fn assemble_file<F>(input_path: &str, output_path: &str, log_program_error: F) where F : Fn(&str) -> () {

  // Open the input file (read-only).
  let mut input_file = File::open(input_path).unwrap_or_else(|reason| {
    log_program_error(&format!("Unable to open input file '{}'", input_path));
    log_program_error(&reason.to_string());
    process::exit(1);
  });

  let mut buffer = String::new();

  // Read the contents of the input file into the buffer.
  input_file.read_to_string(&mut buffer).unwrap_or_else(|reason| {
    log_program_error(&format!("Unable to read contents of input file '{}'", input_path));
    log_program_error(&reason.to_string());
    process::exit(1);
  });

  // Create a scanner over the input.
  let scanner = Scanner::new(input_path, &buffer);

  // Parse the input into an abstract syntax list form. Errors are pre-formatted.
  let syntax_list = parse(scanner).unwrap_or_else(|message| {
    println!("{}", message);
    process::exit(1);
  });

  // Assemble the syntax list into data ranges. Errors are pre-formatted.
  let data_ranges = assemble(syntax_list).unwrap_or_else(|message| {
    println!("{}", message);
    process::exit(1);
  });

  // Verify no overlapping data ranges exist in the result.
  let overlapping_ranges = data_range::find_overlapping_ranges(&data_ranges);
  if overlapping_ranges.len() > 0 {
    log_program_error("Input file specifies overlapping data ranges.");
    log_program_error("Data from one section has overflowed into the adjacent.");

    // Emit overlapping data range information.
    for (a, b) in overlapping_ranges {
      log_program_error(&format!("  range {} overlaps with:", a));
      log_program_error(&format!("  range {}", b));
    }

    process::exit(1);
  }

  // Convert the data ranges to Intel I8HEX format.
  let result = ihex_writer::ihex_representation_of_data_ranges(&data_ranges);

  // Open the output file for writing (truncate) or use stdout if the specified path is `-`.
  let mut output_file: Box<io::Write> = match output_path {
    "-" => Box::new(io::stdout()),
    path @ _ => {
      Box::new(
        File::create(output_path).unwrap_or_else(|reason| {
          log_program_error(&format!("Unable to create output file '{}'", path));
          log_program_error(&reason.to_string());
          process::exit(1);
        })
      )
    }
  };

  // Write the result to the output file.
  output_file.write_all(result.as_bytes()).unwrap_or_else(|reason| {
    log_program_error(&format!("Unable to write result to output file '{}'", output_path));
    log_program_error(&reason.to_string());
    process::exit(1);
  });
}

// MARK: - Option Processing

/**
 Displays usage information for the tool.
 @param program The path to the executable as invoked (argv[0]).
 @param options A fully-constructed options bundle for the tool.
 */
fn print_usage(program: &str, options: Options) {
  let brief = format!("USAGE: {} [options] <input>", program);
  print!("{}", options.usage(&brief));
}

/**
 Displays the program name and version information.
 */
fn print_version() {
  println!("c8s version {}", env!("CARGO_PKG_VERSION"));
}

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

  let mut options = Options::new();
  options.optopt ("o", "output",  "Write output to <file>", "<file>");
  options.optflag("h", "help",    "Display available options");
  options.optflag("v", "version", "Display version information");

  // Parse the command-line arguments and exit in the event an invalid argument is encountered.
  let matches = options.parse(&arguments[1..]).unwrap_or_else(|reason| {
    println!("{}: error: {}", program, reason.to_string());
    process::exit(1);
  });

  // Help requested.
  if matches.opt_present("h") {
    print_usage(&program, options);
    return;
  }

  // Version information requested.
  if matches.opt_present("v") {
    print_version();
    return;
  }

  // Extract the output file name, and default to 'a.hex' if not specified.
  let output_path = &matches.opt_str("o").unwrap_or(String::from("a.hex"));

  // Allow one single input file name parameter.
  let input_path = match matches.free.len() {
    1 => &matches.free[0],
    _ => {
      print_usage(&program, options);
      process::exit(1);
    }
  };

  // Execute the assembler, in the event of failure, log an error and exit.
  assemble_file(input_path, output_path, |reason| {
    println!("{}: error: {}", program, reason);
  });
}
<|endoftext|>


<commit_before>// Copyright © 2014, Peter Atashian

#![feature(slicing_syntax, tuple_indexing)]

extern crate core;
extern crate image;
extern crate lodepng;
extern crate serialize;

use core::slice::{Found, NotFound};
use serialize::json::{decode};
use std::cell::{Cell};
use std::cmp::{max};
use std::collections::{PriorityQueue};
use std::io::{File};
use std::iter::{AdditiveIterator};
use std::num::{Zero};

#[deriving(Show, Clone)]
struct TermColor(Pixel, u8);
impl PartialEq for TermColor {
    fn eq(&self, o: &TermColor) -> bool {
        self.0 == o.0
    }
}

#[deriving(Show)]
struct Coverage(char, f32);
impl PartialEq for Coverage {
    fn eq(&self, o: &Coverage) -> bool {
        self.1 == o.1
    }
}

#[deriving(Show, PartialEq, PartialOrd, Clone)]
struct Pixel(f32, f32, f32);
impl Pixel {
    fn gray(&self) -> f32 {
        (self.0 + self.1 + self.2) / 3.
    }
    fn abs(&self) -> Pixel {
        Pixel(self.0.abs(), self.1.abs(), self.2.abs())
    }
    fn sqsum(&self) -> f32 {
        self.0 * self.0 + self.1 * self.1 + self.2 * self.2
    }
    fn magnitude(&self) -> f32 {
        self.sqsum().sqrt()
    }
    fn dot(&self, o: &Pixel) -> f32 {
        self.0 * o.0 + self.1 * o.1 + self.2 * o.2
    }
}
impl Add<Pixel, Pixel> for Pixel {
    fn add(&self, o: &Pixel) -> Pixel {
        Pixel(self.0 + o.0, self.1 + o.1, self.2 + o.2)
    }
}
impl Sub<Pixel, Pixel> for Pixel {
    fn sub(&self, o: &Pixel) -> Pixel {
        Pixel(self.0 - o.0, self.1 - o.1, self.2 - o.2)
    }
}
impl Zero for Pixel {
    fn zero() -> Pixel {
        Pixel(0., 0., 0.)
    }
    fn is_zero(&self) -> bool {
        *self == Zero::zero()
    }
}
impl Mul<Pixel, Pixel> for Pixel {
    fn mul(&self, o: &Pixel) -> Pixel {
        Pixel(self.0 * o.0, self.1 * o.1, self.2 * o.2)
    }
}
impl Div<Pixel, Pixel> for Pixel {
    fn div(&self, o: &Pixel) -> Pixel {
        Pixel(self.0 / o.0, self.1 / o.1, self.2 / o.2)
    }
}

#[deriving(Show)]
struct Image {
    pixels: Vec<Cell<Pixel>>,
    width: u32,
    height: u32,
}
impl Image {
    fn get(&self, x: u32, y: u32) -> Pixel {
        self.pixels[(y * self.width + x) as uint].get()
    }
    fn resize(&self, width: u32, height: u32) -> Image {
        let (rw, rh) = (self.width as f32 / (width as f32), self.height as f32 / (height as f32));
        let mut pixels = Vec::with_capacity((width * height) as uint);
        for y in range(0, height) {
            for x in range(0, width) {
                let (x1, x2) = ((x as f32 * rw) as u32, ((x + 1) as f32 * rw) as u32);
                let (y1, y2) = ((y as f32 * rh) as u32, ((y + 1) as f32 * rh) as u32);
                let (x2, y2) = (max(x2, x1 + 1), max(y2, y1 + 1));
                let c = range(x1, x2).map(|x| {
                    range(y1, y2).map(|y| {
                        self.get(x, y)
                    }).sum()
                }).sum();
                let m = 1. / (((x2 - x1) * (y2 - y1)) as f32);
                pixels.push(Cell::new(c * Pixel(m, m, m)));
            }
        }
        assert!(pixels.len() as u32 == width * height);
        Image {
            pixels: pixels,
            width: width,
            height: height,
        }
    }
}

#[deriving(Decodable, Show)]
struct Config {
    winwidth: u32,
    winheight: u32,
    charwidth: u32,
    charheight: u32,
    offsetx: u32,
    offsety: u32,
    chars: String,
    fullcolor: bool,
}
impl Config {
    fn load() -> Config {
        let mut file = File::open(&Path::new("config.json")).unwrap();
        let data = file.read_to_string().unwrap();
        decode(data.as_slice()).unwrap()
    }
}

#[deriving(Show)]
struct Ascii {
    config: Config,
    table: Vec<f32>,
    colors: Vec<TermColor>,
    chars: Vec<Coverage>,
}
impl Ascii {
    fn new() -> Ascii {
        let config = Config::load();
        Ascii {
            config: config,
            table: Vec::new(),
            colors: Vec::new(),
            chars: Vec::new(),
        }
    }
    #[allow(dead_code)]
    fn print_chars(&self) {
        for x in range(0u16, 256) {
            bg(x as u8);
            print!(" ");
        }
        println!("");
        fg(15);
        bg(0);
        println!("{}", self.config.chars);
        let lines = 256 / self.config.winwidth;
        let lines = lines + self.config.chars[].chars().count() as u32 / self.config.winwidth;
        for _ in range(lines + 5, self.config.winheight) {
            println!("");
        }
    }
    fn build_table(&mut self) {
        fn decode(x: f32) -> f32 {
            if x <= 0.04045 {
                x / 12.92
            } else {
                ((x + 0.055) / (1. + 0.055)).powf(2.4)
            }
        }
        self.table = range(0u32, 256).map(|x| decode(x as f32 * (1. / 255.))).collect();
    }
    fn load(&self, p: &Path) -> Image {
        use image::GenericImage;
        assert!(self.table.len() == 256);
        let img = match lodepng::load(p) {
            Ok(x) => x,
            Err(_) => image::open(p).unwrap().to_rgba(),
        };
        let (w, h) = img.dimensions();
        let pixels = img.into_vec();
        let pixels = pixels.iter().map(|p| {
            let (&r, &g, &b, &a) = unsafe {(
                self.table[].unsafe_get(p.0 as uint),
                self.table[].unsafe_get(p.1 as uint),
                self.table[].unsafe_get(p.2 as uint),
                self.table[].unsafe_get(p.3 as uint),
            )};
            Cell::new(Pixel(r * a, g * a, b * a))
        }).collect();
        Image {
            pixels: pixels,
            width: w,
            height: h,
        }
    }
    fn calc_colors(&mut self) {
        let img = self.load(&Path::new("colors.png"));
        self.colors = range(0u32, if self.config.fullcolor { 256 } else { 16 }).map(|i| {
            let x = i % self.config.winwidth * self.config.charwidth + self.config.offsetx;
            let y = i / self.config.winwidth * self.config.charheight + self.config.offsety;
            TermColor(img.get(x, y), i as u8)
        }).collect();
        let offset = (256 / self.config.winwidth + 1) * self.config.charheight
            + self.config.offsety;
        let (lo, hi) = (self.colors[0].0.gray(), self.colors[15].0.gray());
        self.chars = self.config.chars[].chars().enumerate().map(|(i, c)| {
            let x = i as u32 % self.config.winwidth * self.config.charwidth + self.config.offsetx;
            let y = i as u32 / self.config.winwidth * self.config.charheight + offset;
            let p = range(x, x + self.config.charwidth).map(|x| {
                range(y, y + self.config.charheight).map(|y| {
                    img.get(x, y).gray()
                }).sum()
            }).sum() / (self.config.charwidth * self.config.charheight) as f32;
            Coverage(c, (p - lo) / (hi - lo))
        }).collect();
        self.colors.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
        self.colors.dedup();
        self.chars.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
        self.chars.dedup();
        self.chars.retain(|x| x.1 <= 0.5);
    }
    fn prepare(&mut self) {
        self.build_table();
        self.calc_colors();
    }
    fn fit_window(&self, img: &Image) -> Image {
        let (ww, wh) = (self.config.winwidth - 1, self.config.winheight - 3);
        let (cw, ch) = (self.config.charwidth, self.config.charheight);
        let fw = (cw * ww) as f32;
        let fh = (ch * wh) as f32;
        let ratio = fh / fw;
        let imgratio = img.height as f32 / img.width as f32;
        if ratio > imgratio {
            let h = (fw * imgratio / ch as f32) as u32;
            img.resize(ww, h)
        } else {
            let w = (fh / imgratio / cw as f32) as u32;
            img.resize(w, wh)
        }
    }
    fn get_closest(&self, p: &Pixel) -> Vec<TermColor> {
        struct Entry(Pixel, u8, f32);
        impl Ord for Entry {
            fn cmp(&self, o: &Entry) -> Ordering {
                self.partial_cmp(o).unwrap()
            }
        }
        impl PartialOrd for Entry {
            fn partial_cmp(&self, o: &Entry) -> Option<Ordering> {
                self.2.partial_cmp(&o.2).map(|x| x.reverse())
            }
        }
        impl Eq for Entry {}
        impl PartialEq for Entry {
            fn eq(&self, o: &Entry) -> bool {
                self.2 == o.2
            }
        }
        if self.config.fullcolor {
            let mut colors: PriorityQueue<_> = self.colors.iter().map(|c| {
                let d = (c.0 - *p).abs().gray();
                Entry(c.0, c.1, d)
            }).collect();
            range(0, 20u).map(|_| {
                let e = colors.pop().unwrap();
                TermColor(e.0, e.1)
            }).collect()
        } else {
            self.colors.clone()
        }
    }
    fn closest(&self, p: &Pixel) -> (u8, u8, char, Pixel) {
        let colors = self.get_closest(p);
        let mut bestdiff = 100f32;
        let mut best = (0, colors[0].1, ' ', p - colors[0].0);
        for c1 in colors.iter() {
            for c2 in colors.iter() {
                let (v1, v2) = (p - c1.0, c2.0 - c1.0);
                let cover = if v2.abs().gray() < 0.0001 {
                    0.
                } else {
                    v1.dot(&v2) / v2.sqsum()
                };
                if cover < 0. || cover > 0.5 { continue }
                let Coverage(ch, n) = match self.chars[].binary_search(|x| {
                    x.1.partial_cmp(&cover).unwrap()
                }) {
                    Found(x) => self.chars[x],
                    NotFound(x) => self.chars[x - 1],
                };
                let color = c1.0 * Pixel(1. - n, 1. - n, 1. - n) + c2.0 * Pixel(n, n, n);
                let diff = *p - color;
                let sdiff = c2.0 - c1.0;
                let d = diff.abs().magnitude() + sdiff.abs().magnitude() * 0.2;
                if d < bestdiff {
                    bestdiff = d;
                    best = (c2.1, c1.1, ch, diff);
                }
            }
        }
        best
    }
    fn convert(&self, p: &Path) {
        let img = self.load(p);
        let mut img = self.fit_window(&img);
        let width = img.width;
        img.pixels.reserve_additional(width as uint * 2);
        let pixels = img.pixels[];
        let mut fg = 15;
        let mut bg = 0;
        let set = |f: u8, b: u8| {
            if f == fg && b == bg { return }
            if f == fg {
                print!("\x1b[48;5;{}m", b);
            } else if b == bg {
                print!("\x1b[38;5;{}m", f);
            } else {
                print!("\x1b[38;5;{};48;5;{}m", f, b);
            }
            fg = f;
            bg = b;
        };
        for (y, chunk) in pixels.chunks(img.width as uint).enumerate() {
            for (x, p) in chunk.iter().enumerate() {
                let (f, b, c, diff) = self.closest(&p.get());
                let adjust = |ox, oy, mult| {
                    let cell = unsafe { pixels.unsafe_get((y + oy) * (width as uint) + x + ox) };
                    cell.set(cell.get() + diff * Pixel(mult, mult, mult));
                };
                adjust( 1, 0, 5. / 32.);
                adjust( 2, 0, 3. / 32.);
                adjust( 2, 1, 2. / 32.);
                adjust(-1, 1, 4. / 32.);
                adjust(-0, 1, 5. / 32.);
                adjust( 1, 1, 4. / 32.);
                adjust( 2, 1, 2. / 32.);
                adjust(-1, 2, 2. / 32.);
                adjust( 0, 2, 3. / 32.);
                adjust( 1, 2, 2. / 32.);
                set(f, b);
                print!("{}", c);
            }
            set(15, 0);
            println!("");
        }
    }
}

fn fg(x: u8) {
    print!("\x1b[38;5;{}m", x);
}
fn bg(x: u8) {
    print!("\x1b[48;5;{}m", x);
}

fn main() {
    let mut ascii = Ascii::new();
    let args = std::os::args();
    if args.len() <= 1 {
        ascii.print_chars();
    } else {
        ascii.prepare();
        ascii.convert(&Path::new(args[1][]));
    }
}
<commit_msg>Make colors more customizable.<commit_after>// Copyright © 2014, Peter Atashian

#![feature(slicing_syntax, tuple_indexing)]

extern crate core;
extern crate image;
extern crate lodepng;
extern crate serialize;

use core::slice::{Found, NotFound};
use serialize::json::{decode};
use std::cell::{Cell};
use std::cmp::{max};
use std::collections::{PriorityQueue};
use std::io::{File};
use std::iter::{AdditiveIterator};
use std::num::{Zero};

#[deriving(Show, Clone)]
struct TermColor(Pixel, u8);
impl PartialEq for TermColor {
    fn eq(&self, o: &TermColor) -> bool {
        self.0 == o.0
    }
}

#[deriving(Show)]
struct Coverage(char, f32);
impl PartialEq for Coverage {
    fn eq(&self, o: &Coverage) -> bool {
        self.1 == o.1
    }
}

#[deriving(Show, PartialEq, PartialOrd, Clone)]
struct Pixel(f32, f32, f32);
impl Pixel {
    fn gray(&self) -> f32 {
        (self.0 + self.1 + self.2) * (1. / 3.)
    }
    fn abs(&self) -> Pixel {
        Pixel(self.0.abs(), self.1.abs(), self.2.abs())
    }
    fn sqsum(&self) -> f32 {
        self.0 * self.0 + self.1 * self.1 + self.2 * self.2
    }
    fn magnitude(&self) -> f32 {
        self.sqsum().sqrt()
    }
    fn dot(&self, o: &Pixel) -> f32 {
        self.0 * o.0 + self.1 * o.1 + self.2 * o.2
    }
}
impl Add<Pixel, Pixel> for Pixel {
    fn add(&self, o: &Pixel) -> Pixel {
        Pixel(self.0 + o.0, self.1 + o.1, self.2 + o.2)
    }
}
impl Sub<Pixel, Pixel> for Pixel {
    fn sub(&self, o: &Pixel) -> Pixel {
        Pixel(self.0 - o.0, self.1 - o.1, self.2 - o.2)
    }
}
impl Zero for Pixel {
    fn zero() -> Pixel {
        Pixel(0., 0., 0.)
    }
    fn is_zero(&self) -> bool {
        *self == Zero::zero()
    }
}
impl Mul<Pixel, Pixel> for Pixel {
    fn mul(&self, o: &Pixel) -> Pixel {
        Pixel(self.0 * o.0, self.1 * o.1, self.2 * o.2)
    }
}
impl Div<Pixel, Pixel> for Pixel {
    fn div(&self, o: &Pixel) -> Pixel {
        Pixel(self.0 / o.0, self.1 / o.1, self.2 / o.2)
    }
}

#[deriving(Show)]
struct Image {
    pixels: Vec<Cell<Pixel>>,
    width: u32,
    height: u32,
}
impl Image {
    fn get(&self, x: u32, y: u32) -> Pixel {
        self.pixels[(y * self.width + x) as uint].get()
    }
    fn resize(&self, width: u32, height: u32) -> Image {
        let (rw, rh) = (self.width as f32 / (width as f32), self.height as f32 / (height as f32));
        let mut pixels = Vec::with_capacity((width * height) as uint);
        for y in range(0, height) {
            for x in range(0, width) {
                let (x1, x2) = ((x as f32 * rw) as u32, ((x + 1) as f32 * rw) as u32);
                let (y1, y2) = ((y as f32 * rh) as u32, ((y + 1) as f32 * rh) as u32);
                let (x2, y2) = (max(x2, x1 + 1), max(y2, y1 + 1));
                let c = range(x1, x2).map(|x| {
                    range(y1, y2).map(|y| {
                        self.get(x, y)
                    }).sum()
                }).sum();
                let m = 1. / (((x2 - x1) * (y2 - y1)) as f32);
                pixels.push(Cell::new(c * Pixel(m, m, m)));
            }
        }
        assert!(pixels.len() as u32 == width * height);
        Image {
            pixels: pixels,
            width: width,
            height: height,
        }
    }
}

#[deriving(Decodable, Show)]
struct Config {
    winwidth: u32,
    winheight: u32,
    charwidth: u32,
    charheight: u32,
    offsetx: u32,
    offsety: u32,
    chars: String,
    colors: Vec<u8>,
    smoothness: f32,
    choices: u8,
}
impl Config {
    fn load() -> Config {
        let mut file = File::open(&Path::new("config.json")).unwrap();
        let data = file.read_to_string().unwrap();
        decode(data.as_slice()).unwrap()
    }
}

struct Ascii {
    config: Config,
    table: Vec<f32>,
    colors: Vec<TermColor>,
    chars: Vec<Coverage>,
}
impl Ascii {
    fn new() -> Ascii {
        let config = Config::load();
        Ascii {
            config: config,
            table: Vec::new(),
            colors: Vec::new(),
            chars: Vec::new(),
        }
    }
    #[allow(dead_code)]
    fn print_chars(&self) {
        for x in range(0u16, 256) {
            bg(x as u8);
            print!(" ");
        }
        println!("");
        fg(15);
        bg(0);
        println!("{}", self.config.chars);
        let lines = 256 / self.config.winwidth;
        let lines = lines + self.config.chars[].chars().count() as u32 / self.config.winwidth;
        for _ in range(lines + 5, self.config.winheight) {
            println!("");
        }
    }
    fn build_table(&mut self) {
        fn decode(x: f32) -> f32 {
            if x <= 0.04045 {
                x / 12.92
            } else {
                ((x + 0.055) / (1. + 0.055)).powf(2.4)
            }
        }
        self.table = range(0u32, 256).map(|x| decode(x as f32 * (1. / 255.))).collect();
    }
    fn load(&self, p: &Path) -> Image {
        use image::GenericImage;
        assert!(self.table.len() == 256);
        let img = match lodepng::load(p) {
            Ok(x) => x,
            Err(_) => image::open(p).unwrap().to_rgba(),
        };
        let (w, h) = img.dimensions();
        let pixels = img.into_vec();
        let pixels = pixels.iter().map(|p| {
            let (&r, &g, &b, &a) = unsafe {(
                self.table[].unsafe_get(p.0 as uint),
                self.table[].unsafe_get(p.1 as uint),
                self.table[].unsafe_get(p.2 as uint),
                self.table[].unsafe_get(p.3 as uint),
            )};
            Cell::new(Pixel(r * a, g * a, b * a))
        }).collect();
        Image {
            pixels: pixels,
            width: w,
            height: h,
        }
    }
    fn calc_colors(&mut self) {
        let img = self.load(&Path::new("colors.png"));
        self.colors = range(0u32, 256).map(|i| {
            let x = i % self.config.winwidth * self.config.charwidth + self.config.offsetx;
            let y = i / self.config.winwidth * self.config.charheight + self.config.offsety;
            TermColor(img.get(x, y), i as u8)
        }).collect();
        let offset = (256 / self.config.winwidth + 1) * self.config.charheight
            + self.config.offsety;
        let (lo, hi) = (self.colors[0].0.gray(), self.colors[15].0.gray());
        self.chars = self.config.chars[].chars().enumerate().map(|(i, c)| {
            let x = i as u32 % self.config.winwidth * self.config.charwidth + self.config.offsetx;
            let y = i as u32 / self.config.winwidth * self.config.charheight + offset;
            let p = range(x, x + self.config.charwidth).map(|x| {
                range(y, y + self.config.charheight).map(|y| {
                    img.get(x, y).gray()
                }).sum()
            }).sum() / (self.config.charwidth * self.config.charheight) as f32;
            Coverage(c, (p - lo) / (hi - lo))
        }).collect();
        self.colors.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
        self.colors.dedup();
        if !self.config.colors.is_empty() {
            let colors = self.config.colors.clone();
            self.colors.retain(|x| colors.contains(&x.1));
        }
        self.chars.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
        self.chars.dedup();
        self.chars.retain(|x| x.1 <= 0.5);
    }
    fn prepare(&mut self) {
        self.build_table();
        self.calc_colors();
    }
    fn fit_window(&self, img: &Image) -> Image {
        let (ww, wh) = (self.config.winwidth - 1, self.config.winheight - 3);
        let (cw, ch) = (self.config.charwidth, self.config.charheight);
        let fw = (cw * ww) as f32;
        let fh = (ch * wh) as f32;
        let ratio = fh / fw;
        let imgratio = img.height as f32 / img.width as f32;
        if ratio > imgratio {
            let h = (fw * imgratio / ch as f32) as u32;
            img.resize(ww, h)
        } else {
            let w = (fh / imgratio / cw as f32) as u32;
            img.resize(w, wh)
        }
    }
    fn get_closest(&self, p: &Pixel) -> Vec<TermColor> {
        struct Entry(Pixel, u8, f32);
        impl Ord for Entry {
            fn cmp(&self, o: &Entry) -> Ordering {
                self.partial_cmp(o).unwrap()
            }
        }
        impl PartialOrd for Entry {
            fn partial_cmp(&self, o: &Entry) -> Option<Ordering> {
                self.2.partial_cmp(&o.2).map(|x| x.reverse())
            }
        }
        impl Eq for Entry {}
        impl PartialEq for Entry {
            fn eq(&self, o: &Entry) -> bool {
                self.2 == o.2
            }
        }
        if self.colors.len() as u8 > self.config.choices {
            let mut colors: PriorityQueue<_> = self.colors.iter().map(|c| {
                let d = (c.0 - *p).abs().magnitude();
                Entry(c.0, c.1, d)
            }).collect();
            range(0, self.config.choices).map(|_| {
                let e = colors.pop().unwrap();
                TermColor(e.0, e.1)
            }).collect()
        } else {
            self.colors.clone()
        }
    }
    fn closest(&self, p: &Pixel) -> (u8, u8, char, Pixel) {
        let colors = self.get_closest(p);
        let mut bestdiff = 9001f32;
        let mut best = (0, colors[0].1, ' ', p - colors[0].0);
        for c1 in colors.iter() {
            for c2 in colors.iter() {
                let (v1, v2) = (p - c1.0, c2.0 - c1.0);
                let cover = if v2.abs().gray() < 0.00001 {
                    0.
                } else {
                    v1.dot(&v2) / v2.sqsum()
                };
                if cover < 0. || cover > 0.5 { continue }
                let Coverage(ch, n) = match self.chars[].binary_search(|x| {
                    x.1.partial_cmp(&cover).unwrap()
                }) {
                    Found(x) => self.chars[x],
                    NotFound(x) => self.chars[x - 1],
                };
                let color = c1.0 * Pixel(1. - n, 1. - n, 1. - n) + c2.0 * Pixel(n, n, n);
                let diff = *p - color;
                let sdiff = (c2.0 - color).magnitude() + (c1.0 - color).magnitude();
                let d = diff.magnitude() + sdiff * self.config.smoothness;
                if d < bestdiff {
                    bestdiff = d;
                    best = (c2.1, c1.1, ch, diff);
                }
            }
        }
        best
    }
    fn convert(&self, p: &Path) {
        let img = self.load(p);
        let mut img = self.fit_window(&img);
        let width = img.width;
        img.pixels.reserve_additional(width as uint * 2);
        let pixels = img.pixels[];
        let mut fg = 15;
        let mut bg = 0;
        let set = |f: u8, b: u8| {
            if f == fg && b == bg { return }
            if f == fg {
                print!("\x1b[48;5;{}m", b);
            } else if b == bg {
                print!("\x1b[38;5;{}m", f);
            } else {
                print!("\x1b[38;5;{};48;5;{}m", f, b);
            }
            fg = f;
            bg = b;
        };
        for (y, chunk) in pixels.chunks(img.width as uint).enumerate() {
            for (x, p) in chunk.iter().enumerate() {
                let (f, b, c, diff) = self.closest(&p.get());
                let adjust = |ox, oy, mult| {
                    let cell = unsafe { pixels.unsafe_get((y + oy) * (width as uint) + x + ox) };
                    cell.set(cell.get() + diff * Pixel(mult, mult, mult));
                };
                // Sierra dithering
                adjust( 1, 0, 5. / 32.);
                adjust( 2, 0, 3. / 32.);
                adjust( 2, 1, 2. / 32.);
                adjust(-1, 1, 4. / 32.);
                adjust(-0, 1, 5. / 32.);
                adjust( 1, 1, 4. / 32.);
                adjust( 2, 1, 2. / 32.);
                adjust(-1, 2, 2. / 32.);
                adjust( 0, 2, 3. / 32.);
                adjust( 1, 2, 2. / 32.);
                set(f, b);
                print!("{}", c);
            }
            set(15, 0);
            println!("");
        }
    }
}

fn fg(x: u8) {
    print!("\x1b[38;5;{}m", x);
}
fn bg(x: u8) {
    print!("\x1b[48;5;{}m", x);
}

fn main() {
    let mut ascii = Ascii::new();
    let args = std::os::args();
    if args.len() <= 1 {
        ascii.print_chars();
    } else {
        ascii.prepare();
        ascii.convert(&Path::new(args[1][]));
    }
}
<|endoftext|>