<commit_before>/*
 *  This source code is subject to the terms of the 2-clause BSD license (FreeBSD License).
 *  If a copy of the 2-clause BSD license was not included with this file,
 *  you can refer to http://en.wikipedia.org/wiki/BSD_licenses#2-clause_license_.28.22Simplified_BSD_License.22_or_.22FreeBSD_License.22.29
 *  or http://opensource.org/licenses/BSD-2-Clause
 * */

#![feature(fs_walk)]
#![feature(path_ext)]

extern crate rustc_serialize;

use std::env;
use std::process;
use std::fs;
use std::path::Path;
use std::fs::PathExt;
use std::fs::File;
use std::io::Write;
use std::io::Read;
use std::str::FromStr;

use rustc_serialize::json;

const URL : &'static str = "http://uguu.se/api.php?d=upload";

#[derive(RustcDecodable, RustcEncodable)]
pub struct Config {
    links_only: bool,
}

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

    let config = first_run();

    if args.len() == 1 {
        panic!("\n\n    Not enough arguments were supplied!\n\n")
    }

    handle_arguments(args, config);
}

fn first_run() -> Config {
    let home = env::home_dir().unwrap();
    let home_dir = Path::new(&home);

    let config_dir = home_dir.join(".uguupload");
    let config_dir_path = Path::new(&config_dir);

    let config_file = config_dir.join("config");

    if config_dir_path.is_dir() == false {
        // Create the initial config directory and then the config file
        match fs::create_dir(config_dir_path) {
            Ok(_)   => (),
            Err(e)  => panic!("Failed to create ~/.uguupload! Error: {}", e),
        }

        let default_config = Config {
            links_only: false,
        };

        save_config(default_config);
    }

    load_config()
}

fn handle_arguments(args: Vec<String>, config: Config) {
    // Handles command-line arguments

    let arg = args[1].clone();

    match arg.as_ref() {
        "-h"  | "--help"        => help(),
        "-f"  | "--filename"    => upload_f(args, config),
        "-r"  | "--random"      => upload_r(args, config),
        "-d"  | "--dir"         => upload_d(args, config),
        "-dr" | "--dir-rec"     => upload_dr(args, config),
        "-c"  | "--config"      => change_config(&args),
        "-lc" | "--list-config" => list_config(),
        _                       => upload_n(args, config),
    }
}

fn change_config(args: &Vec<String>) {
    if args.len() != 4 {
        panic!("Too many or too little arguments were supplied!");
    }

    let ref config_parameter = args[2];
    let ref config_value = args[3];

    let mut current_config: Config = load_config();

    let links_only = "links_only".to_string();

    match config_value {
        links_only  => current_config.links_only = match FromStr::from_str(config_value.as_ref()) {
            Ok(o)   => o,
            Err(e)  => panic!("HELP: {}", e),
        },
    }

    save_config(current_config);
}

fn load_config() -> Config {
    let home = env::home_dir().unwrap();
    let home_dir = Path::new(&home);

    let config_dir = home_dir.join(".uguupload");

    let config_file = config_dir.join("config");

    let mut boop = File::open(&config_file).unwrap();
    let mut output_from_config = String::new();

    let content = match File::read_to_string(&mut boop, &mut output_from_config) {
        Ok(o)   => o,
        Err(e)  => panic!("HELP: {}", e),
    };

    json::decode::<Config>(&output_from_config).unwrap();
}

fn save_config(new_config: Config) {
    let home = env::home_dir().unwrap();
    let home_dir = Path::new(&home);

    let config_dir = home_dir.join(".uguupload");

    let config_file = config_dir.join("config");

    let conf_file = File::create(&config_file);

    conf_file.unwrap().write_all(json::encode(&new_config).unwrap().as_bytes());
}

fn list_config() {
    // This is really shitty.
    // Use the serde crate to do this in a better way.
    let config: Config = load_config();

    println!("links_only : {}", config.links_only);
}

fn upload(f: &String, file: String, filename: String, random: bool, config: &Config) {
    // Handles the uploading of files.

    let mut curl = process::Command::new("curl");
            curl.args(&["-F", filename.as_ref()]);
            curl.args(&["-F", file.as_ref()]);
            if random == true {
                curl.args(&["-F", "randomname=true"]);
            }
            curl.arg(URL);

    match curl.output() {
        Ok(r)   => {
            if String::from_utf8_lossy(r.stdout.as_ref()) == "" {
                println!("Failed to upload: {}", f);
            } else {
                if config.links_only == true {
                    println!("{}", String::from_utf8_lossy(r.stdout.as_ref()));
                } else {
                    println!("{}\n{}", f, String::from_utf8_lossy(r.stdout.as_ref()));
                }
            }
        },
        Err(e)  => panic!("Failed to upload: {}", e),
    }
}

fn upload_n(args: Vec<String>, config: Config) {
    // NORMAL
    // Handles what files should be uploaded along with what filename the file should have.

    let files = &args[1..args.len()];

    for f in files {
        let filename = format!("name={}", f);
        let file = format!("file=@{}", f);

        upload(f, file, filename, false, &config);
    }
}

fn upload_f(args: Vec<String>, config: Config) {
    // FILENAME
    // Handles what files should be uploaded along with that filename the file should have.
    // -f was used here.
    let files = &args[2..args.len()];
    let mut counter = 0;

    for x in 0..files.len() {
        if x + 1 + counter < files.len() {
            let filename = format!("name={}", files[x + 1 + counter]);
            let file = format!("file=@{}", files[x + counter]);

            upload(&files[x + counter], file, filename, false, &config);
        }

        counter += 1;
    }
}

fn upload_r(args: Vec<String>, config: Config) {
    // RANDOM
    // Handles what files should be uploaded. Filenames are random.
    // -r was used here
    let files = &args[2..args.len()];

    for f in files {
        let filename = format!("name={}", f);
        let file = format!("file=@{}", f);

        upload(f, file, filename, true, &config);
    }
}

fn upload_d(args: Vec<String>, config: Config) {
    // DIRECTORY
    // Handles what files in the directory should be uploaded.
    // -d was used here.

    let directories = &args[2..args.len()];

    for d in directories {
        let path = Path::new(d);
        let mut fls: Vec<_> = vec!();

        if path.is_dir() == true {
            match fs::read_dir(&path) {
                Err(why) => println!("! {:?}", why.kind()),
                Ok(paths) => for path in paths {
                    fls.push(path.unwrap().path());
                },
            }

            for x in fls {
                let filename_processed = x.as_path().file_name().unwrap().to_str().unwrap().to_string();
                let file_processed = x.as_path().to_str().unwrap().to_string();

                let filename = format!("name={}", filename_processed);
                let file = format!("file=@{}", file_processed);

                upload(&file_processed, file, filename, false, &config);
            }
        }
    }
}

fn upload_dr(args: Vec<String>, config: Config) {
    // DIRECTORY
    // Handles what files in the directory should be uploaded.
    // -d was used here.

    let directories = &args[2..args.len()];

    for d in directories {
        let path = Path::new(d);
        let mut fls: Vec<_> = vec!();

        if path.is_dir() == true {
            match fs::walk_dir(&path) {
                Err(why) => println!("! {:?}", why.kind()),
                Ok(paths) => for path in paths {
                    fls.push(path.unwrap().path());
                },
            }

            for x in fls {
                let filename_processed = x.as_path().file_name().unwrap().to_str().unwrap().to_string();
                let file_processed = x.as_path().to_str().unwrap().to_string();

                let filename = format!("name={}", filename_processed);
                let file = format!("file=@{}", file_processed);

                upload(&file_processed, file, filename, false, &config);
            }
        }
    }
}

fn help() {
    println!("Usage: ./uguupload [option] [FILE]

[FILE] is the path to the file you want to upload.

OPTIONS
    -h, --help
        Prints out this help message.

    -f, --filename
        Allows you to specify custom filenames for files.
        See Example 2.

    -r, --random
        Gives files random filenames.
        See Example 3.

    -d, --dir
        Uploads everything in the specified directory.
        This is not recursive.
        See Example 4.

    -dr, --dir-rec
        Uploads everything in the specified directory.
        This is recursive. Files in sub-directories will be uploaded.
        See Example 4. This works exactly like -d.

    -c, --config
        Changes config values
        See Example 5

    -lc, --list-config
        Lists config options

EXAMPLES
    Example 1:
        ./uguupload [FILE]
        ./uguupload foo.txt

        You can also upload several files.
        ./uguupload foo.txt bar.txt foobar.txt

    Example 2:
        ./uguupload -f [FILE] [FILENAME]
        ./uguupload -f foo.txt foo.txt bar.txt foo.txt foobar.txt foo.txt

        The first argument, foo.txt is the filename and the second argument, foo.txt, is the file and so on.
        bar.txt is the filename and foo.txt is the file. Same for foobar.txt and foo.txt

    Example 3:
        ./uguupload -r [FILE]
        ./uguupload -r foo.txt

        This will return http://a.uguu.se/asdfghjkl.ext where .ext is the file extension/type

    Example 4:
        ./uguupload -d [DIRECTORY]
        This will upload everything in the specified directory. You can add several directories

    Example 5:
        ./uguupload -c [PARAMETER] [VALUE]
        ./uguupload -c links_only true
        This will change the config option links_only to true.

CONFIGURATION
    links_only:
        Type: boolean. This can be either true or false. Nothing else.

        If true, only links will be outputted, no filename.
        If false, the filename and the uguu.se link will outputted.

        Default is false.");

    return;
}
<commit_msg>Fixed a bug where the result wouldn't be returned in the load_config function<commit_after>/*
 *  This source code is subject to the terms of the 2-clause BSD license (FreeBSD License).
 *  If a copy of the 2-clause BSD license was not included with this file,
 *  you can refer to http://en.wikipedia.org/wiki/BSD_licenses#2-clause_license_.28.22Simplified_BSD_License.22_or_.22FreeBSD_License.22.29
 *  or http://opensource.org/licenses/BSD-2-Clause
 * */

#![feature(fs_walk)]
#![feature(path_ext)]

extern crate rustc_serialize;

use std::env;
use std::process;
use std::fs;
use std::path::Path;
use std::fs::PathExt;
use std::fs::File;
use std::io::Write;
use std::io::Read;
use std::str::FromStr;

use rustc_serialize::json;

const URL : &'static str = "http://uguu.se/api.php?d=upload";

#[derive(RustcDecodable, RustcEncodable)]
pub struct Config {
    links_only: bool,
}

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

    let config = first_run();

    if args.len() == 1 {
        panic!("\n\n    Not enough arguments were supplied!\n\n")
    }

    handle_arguments(args, config);
}

fn first_run() -> Config {
    let home = env::home_dir().unwrap();
    let home_dir = Path::new(&home);

    let config_dir = home_dir.join(".uguupload");
    let config_dir_path = Path::new(&config_dir);

    let config_file = config_dir.join("config");

    if config_dir_path.is_dir() == false {
        // Create the initial config directory and then the config file
        match fs::create_dir(config_dir_path) {
            Ok(_)   => (),
            Err(e)  => panic!("Failed to create ~/.uguupload! Error: {}", e),
        }

        let default_config = Config {
            links_only: false,
        };

        save_config(default_config);
    }

    load_config()
}

fn handle_arguments(args: Vec<String>, config: Config) {
    // Handles command-line arguments

    let arg = args[1].clone();

    match arg.as_ref() {
        "-h"  | "--help"        => help(),
        "-f"  | "--filename"    => upload_f(args, config),
        "-r"  | "--random"      => upload_r(args, config),
        "-d"  | "--dir"         => upload_d(args, config),
        "-dr" | "--dir-rec"     => upload_dr(args, config),
        "-c"  | "--config"      => change_config(&args),
        "-lc" | "--list-config" => list_config(),
        _                       => upload_n(args, config),
    }
}

fn change_config(args: &Vec<String>) {
    if args.len() != 4 {
        panic!("Too many or too little arguments were supplied!");
    }

    let ref config_parameter = args[2];
    let ref config_value = args[3];

    let mut current_config: Config = load_config();

    let links_only = "links_only".to_string();

    match config_value {
        links_only  => current_config.links_only = match FromStr::from_str(config_value.as_ref()) {
            Ok(o)   => o,
            Err(e)  => panic!("HELP: {}", e),
        },
    }

    save_config(current_config);
}

fn load_config() -> Config {
    let home = env::home_dir().unwrap();
    let home_dir = Path::new(&home);

    let config_dir = home_dir.join(".uguupload");

    let config_file = config_dir.join("config");

    let mut boop = File::open(&config_file).unwrap();
    let mut output_from_config = String::new();

    let content = match File::read_to_string(&mut boop, &mut output_from_config) {
        Ok(o)   => o,
        Err(e)  => panic!("HELP: {}", e),
    };

    json::decode::<Config>(&output_from_config).unwrap()
}

fn save_config(new_config: Config) {
    let home = env::home_dir().unwrap();
    let home_dir = Path::new(&home);

    let config_dir = home_dir.join(".uguupload");

    let config_file = config_dir.join("config");

    let conf_file = File::create(&config_file);

    conf_file.unwrap().write_all(json::encode(&new_config).unwrap().as_bytes());
}

fn list_config() {
    // This is really shitty.
    // Use the serde crate to do this in a better way.
    let config: Config = load_config();

    println!("links_only : {}", config.links_only);
}

fn upload(f: &String, file: String, filename: String, random: bool, config: &Config) {
    // Handles the uploading of files.

    let mut curl = process::Command::new("curl");
            curl.args(&["-F", filename.as_ref()]);
            curl.args(&["-F", file.as_ref()]);
            if random == true {
                curl.args(&["-F", "randomname=true"]);
            }
            curl.arg(URL);

    match curl.output() {
        Ok(r)   => {
            if String::from_utf8_lossy(r.stdout.as_ref()) == "" {
                println!("Failed to upload: {}", f);
            } else {
                if config.links_only == true {
                    println!("{}", String::from_utf8_lossy(r.stdout.as_ref()));
                } else {
                    println!("{}\n{}", f, String::from_utf8_lossy(r.stdout.as_ref()));
                }
            }
        },
        Err(e)  => panic!("Failed to upload: {}", e),
    }
}

fn upload_n(args: Vec<String>, config: Config) {
    // NORMAL
    // Handles what files should be uploaded along with what filename the file should have.

    let files = &args[1..args.len()];

    for f in files {
        let filename = format!("name={}", f);
        let file = format!("file=@{}", f);

        upload(f, file, filename, false, &config);
    }
}

fn upload_f(args: Vec<String>, config: Config) {
    // FILENAME
    // Handles what files should be uploaded along with that filename the file should have.
    // -f was used here.
    let files = &args[2..args.len()];
    let mut counter = 0;

    for x in 0..files.len() {
        if x + 1 + counter < files.len() {
            let filename = format!("name={}", files[x + 1 + counter]);
            let file = format!("file=@{}", files[x + counter]);

            upload(&files[x + counter], file, filename, false, &config);
        }

        counter += 1;
    }
}

fn upload_r(args: Vec<String>, config: Config) {
    // RANDOM
    // Handles what files should be uploaded. Filenames are random.
    // -r was used here
    let files = &args[2..args.len()];

    for f in files {
        let filename = format!("name={}", f);
        let file = format!("file=@{}", f);

        upload(f, file, filename, true, &config);
    }
}

fn upload_d(args: Vec<String>, config: Config) {
    // DIRECTORY
    // Handles what files in the directory should be uploaded.
    // -d was used here.

    let directories = &args[2..args.len()];

    for d in directories {
        let path = Path::new(d);
        let mut fls: Vec<_> = vec!();

        if path.is_dir() == true {
            match fs::read_dir(&path) {
                Err(why) => println!("! {:?}", why.kind()),
                Ok(paths) => for path in paths {
                    fls.push(path.unwrap().path());
                },
            }

            for x in fls {
                let filename_processed = x.as_path().file_name().unwrap().to_str().unwrap().to_string();
                let file_processed = x.as_path().to_str().unwrap().to_string();

                let filename = format!("name={}", filename_processed);
                let file = format!("file=@{}", file_processed);

                upload(&file_processed, file, filename, false, &config);
            }
        }
    }
}

fn upload_dr(args: Vec<String>, config: Config) {
    // DIRECTORY
    // Handles what files in the directory should be uploaded.
    // -d was used here.

    let directories = &args[2..args.len()];

    for d in directories {
        let path = Path::new(d);
        let mut fls: Vec<_> = vec!();

        if path.is_dir() == true {
            match fs::walk_dir(&path) {
                Err(why) => println!("! {:?}", why.kind()),
                Ok(paths) => for path in paths {
                    fls.push(path.unwrap().path());
                },
            }

            for x in fls {
                let filename_processed = x.as_path().file_name().unwrap().to_str().unwrap().to_string();
                let file_processed = x.as_path().to_str().unwrap().to_string();

                let filename = format!("name={}", filename_processed);
                let file = format!("file=@{}", file_processed);

                upload(&file_processed, file, filename, false, &config);
            }
        }
    }
}

fn help() {
    println!("Usage: ./uguupload [option] [FILE]

[FILE] is the path to the file you want to upload.

OPTIONS
    -h, --help
        Prints out this help message.

    -f, --filename
        Allows you to specify custom filenames for files.
        See Example 2.

    -r, --random
        Gives files random filenames.
        See Example 3.

    -d, --dir
        Uploads everything in the specified directory.
        This is not recursive.
        See Example 4.

    -dr, --dir-rec
        Uploads everything in the specified directory.
        This is recursive. Files in sub-directories will be uploaded.
        See Example 4. This works exactly like -d.

    -c, --config
        Changes config values
        See Example 5

    -lc, --list-config
        Lists config options

EXAMPLES
    Example 1:
        ./uguupload [FILE]
        ./uguupload foo.txt

        You can also upload several files.
        ./uguupload foo.txt bar.txt foobar.txt

    Example 2:
        ./uguupload -f [FILE] [FILENAME]
        ./uguupload -f foo.txt foo.txt bar.txt foo.txt foobar.txt foo.txt

        The first argument, foo.txt is the filename and the second argument, foo.txt, is the file and so on.
        bar.txt is the filename and foo.txt is the file. Same for foobar.txt and foo.txt

    Example 3:
        ./uguupload -r [FILE]
        ./uguupload -r foo.txt

        This will return http://a.uguu.se/asdfghjkl.ext where .ext is the file extension/type

    Example 4:
        ./uguupload -d [DIRECTORY]
        This will upload everything in the specified directory. You can add several directories

    Example 5:
        ./uguupload -c [PARAMETER] [VALUE]
        ./uguupload -c links_only true
        This will change the config option links_only to true.

CONFIGURATION
    links_only:
        Type: boolean. This can be either true or false. Nothing else.

        If true, only links will be outputted, no filename.
        If false, the filename and the uguu.se link will outputted.

        Default is false.");

    return;
}
<|endoftext|>


<commit_before>extern crate orbclient;

use orbclient::window::EventIter;

use std::time::Instant;

struct Vertex {
    x: i32,
    y: i32
}

impl Vertex {
    pub fn calc_double_area(&self, v1: &Vertex, v2: &Vertex) -> i32 {

        let x1 = (v1.x - self.x) as i32;
        let y1 = (v1.y - self.y) as i32;
        let x2 = (v2.x - self.x) as i32;
        let y2 = (v2.y - self.y) as i32;

        (x1 * y2 - x2 * y1)
    }
}

struct RenderContext {
    window: Box<orbclient::Window>,
    scan_buffer: Vec<i32> //TODO(dustin): do i need Vec<32> here? [i32]
}

impl RenderContext {
    pub fn new(width: u32, height: u32, title: &str) -> RenderContext {
        let orb_window = orbclient::Window::new_flags(100, 100, width, height, title, true).unwrap();
        RenderContext{scan_buffer: vec![0; (height * 2) as usize], window: orb_window}
    }

    pub fn events(&mut self) -> EventIter {
        self.window.events()
    }

    pub fn clear(&mut self) {
        self.window.set(orbclient::Color { data: 0xFF000000 });
    }

    pub fn sync(&mut self) {
        self.window.sync();
    }

    pub fn draw_triangle(&mut self, v1: &Vertex, v2: &Vertex, v3: &Vertex) {

        let mut min_vert = &v1;
        let mut mid_vert = &v2;
        let mut max_vert = &v3;

        if max_vert.y < mid_vert.y {
            let tmp = max_vert;
            max_vert = mid_vert;
            mid_vert = tmp;
        }

        if mid_vert.y < min_vert.y {
            let tmp = mid_vert;
            mid_vert = min_vert;
            min_vert = tmp;
        }

        if max_vert.y < mid_vert.y {
            let tmp = max_vert;
            max_vert = mid_vert;
            mid_vert = tmp;
        }

        let area = min_vert.calc_double_area(&max_vert, &mid_vert);
        let side = if area >= 0 { 1 } else { 0 };
        self.convert_triangle(&min_vert, &mid_vert, &max_vert, side);
        self.fill_convex_shape(min_vert.y, max_vert.y);
    }

    fn fill_convex_shape(&mut self, y_min: i32, y_max: i32) {

        for y_idx in y_min..y_max {
            let x_min = self.scan_buffer.get((y_idx * 2) as usize).unwrap().clone();
            let x_max = self.scan_buffer.get((y_idx * 2 + 1) as usize).unwrap().clone();

            for x_idx in x_min..x_max {
                self.window.pixel(x_idx, y_idx, orbclient::Color { data: 0xFFFFFFFF });
            }
        }
    }

    fn convert_triangle(&mut self, min_vert: &Vertex, mid_vert: &Vertex, max_vert: &Vertex, side: i32) {
        self.convert_line(min_vert, max_vert, 0 + side);
        self.convert_line(min_vert, mid_vert, 1 - side);
        self.convert_line(mid_vert, max_vert, 1 - side);
    }

    fn convert_line(&mut self, min_vert: &Vertex, max_vert: &Vertex, side: i32) {
        let start_y = min_vert.y;
        let start_x = min_vert.x;
        let end_y = max_vert.y;
        let end_x = max_vert.x;

        let dist_y = end_y - start_y;
        let dist_x = end_x - start_x;

        if dist_y <= 0 {
            return;
        }

        let step_x = dist_x as f32 / dist_y as f32;
        let mut current_x = start_x as f32;

        for y_coord in start_y..end_y {
            self.scan_buffer[((y_coord * 2 + side) as usize)] = current_x as i32;
            current_x += step_x;
        }
    }

}

fn main() {

    let mut render_context = RenderContext::new(500, 400, "pixelcannon");
    let mut start = Instant::now();

    let min_vert = Vertex{x: 250, y: 0};
    let mid_vert = Vertex{x: 0, y: 200};
    let max_vert = Vertex{x: 500, y: 300};

    'event: loop {

        {
            let end = Instant::now();
            let delta = end.duration_since(start);
            let delta_ms = delta.as_secs() * 1000 + (delta.subsec_nanos() as u64)/1000000;
            start = Instant::now();
            // println!("{} ms", delta_ms);

            render_context.clear();
            render_context.draw_triangle(&min_vert, &mid_vert, &max_vert);
            render_context.sync();
        }

        for orbital_event in render_context.events() {
            match orbital_event.to_option() {
                orbclient::EventOption::Quit(_quit_event) => break 'event,
                _ => (),
            };
        }

    }
}
<commit_msg>3d transformation<commit_after>extern crate orbclient;

use orbclient::window::EventIter;

use std::time::Instant;

struct Matrix4f32 {
    pub m: [[f32; 4]; 4]
}

impl Matrix4f32 {
    pub fn new() -> Matrix4f32 {
        Matrix4f32{m: [[0f32; 4]; 4]}
    }

    pub fn init_perspective(&mut self, fov: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> &mut Matrix4f32 {
        let tan_half_fov = (fov / 2f32).tan();
        let z_range = z_near - z_far;

        self.m[0][0] = 1f32 / (tan_half_fov * aspect_ratio);      self.m[0][1] = 0f32;                      self.m[0][2] = 0f32;                            self.m[0][3] = 0f32;
        self.m[1][0] = 0f32;                                      self.m[1][1] = 1f32 / tan_half_fov;       self.m[1][2] = 0f32;                            self.m[1][3] = 0f32;
        self.m[2][0] = 0f32;                                      self.m[2][1] = 0f32;                      self.m[2][2] = (- z_near -z_far) / z_range;     self.m[2][3] = 2f32 * z_far * z_near / z_range;
        self.m[3][0] = 0f32;                                      self.m[3][1] = 0f32;                      self.m[3][2] = 1f32;                            self.m[3][3] = 0f32;

        self
    }

    pub fn init_translation(&mut self, x: f32, y: f32, z: f32) -> &mut Matrix4f32 {
        self.m[0][0] = 1f32;    self.m[0][1] = 0f32;    self.m[0][2] = 0f32;    self.m[0][3] = x;
        self.m[1][0] = 0f32;    self.m[1][1] = 1f32;    self.m[1][2] = 0f32;    self.m[1][3] = y;
        self.m[2][0] = 0f32;    self.m[2][1] = 0f32;    self.m[2][2] = 1f32;    self.m[2][3] = z;
        self.m[3][0] = 0f32;    self.m[3][1] = 0f32;    self.m[3][2] = 0f32;    self.m[3][3] = 1f32;

        self
    }

    pub fn init_rotation(&mut self, x: f32, y: f32, z: f32) -> &mut Matrix4f32 {

        let mut rx = Matrix4f32::new();
        let mut ry = Matrix4f32::new();
        let mut rz = Matrix4f32::new();

        rz.m[0][0] = z.cos();   rz.m[0][1] = -z.sin();  rz.m[0][2] = 0f32;      rz.m[0][3] = 0f32;
        rz.m[1][0] = z.sin();   rz.m[1][1] = z.cos();   rz.m[1][2] = 0f32;      rz.m[1][3] = 0f32;
        rz.m[2][0] = 0f32;      rz.m[2][1] = 0f32;      rz.m[2][2] = 1f32;      rz.m[2][3] = 0f32;
        rz.m[3][0] = 0f32;      rz.m[3][1] = 0f32;      rz.m[3][2] = 0f32;      rz.m[3][3] = 1f32;

        rx.m[0][0] = 1f32;      rx.m[0][1] = 0f32;      rx.m[0][2] = 0f32;      rx.m[0][3] = 0f32;
        rx.m[1][0] = 0f32;      rx.m[1][1] = x.cos();   rx.m[1][2] = -x.sin();  rx.m[1][3] = 0f32;
        rx.m[2][0] = 0f32;      rx.m[2][1] = x.sin();   rx.m[2][2] = x.cos();   rx.m[2][3] = 0f32;
        rx.m[3][0] = 0f32;      rx.m[3][1] = 0f32;      rx.m[3][2] = 0f32;      rx.m[3][3] = 1f32;

        ry.m[0][0] = y.cos();   ry.m[0][1] = 0f32;      ry.m[0][2] = -y.sin();  ry.m[0][3] = 0f32;
        ry.m[1][0] = 0f32;      ry.m[1][1] = 1f32;      ry.m[1][2] = 0f32;      ry.m[1][3] = 0f32;
        ry.m[2][0] = y.sin();   ry.m[2][1] = 0f32;      ry.m[2][2] = y.cos();   ry.m[2][3] = 0f32;
        ry.m[3][0] = 0f32;      ry.m[3][1] = 0f32;      ry.m[3][2] = 0f32;      ry.m[3][3] = 1f32;

        self.m = rz.mul(&ry.mul(&rx)).m;

        self
    }

    pub fn init_sreenspace_transform(&mut self, half_width: f32, half_height: f32) -> &mut Matrix4f32 {
        self.m[0][0] = half_width;  self.m[0][1] = 0f32;            self.m[0][2] = 0f32;    self.m[0][3] = half_width;
        self.m[1][0] = 0f32;        self.m[1][1] = -half_height;    self.m[1][2] = 0f32;    self.m[1][3] = half_height;
        self.m[2][0] = 0f32;        self.m[2][1] = 0f32;            self.m[2][2] = 1f32;    self.m[2][3] = 0f32;
        self.m[3][0] = 0f32;        self.m[3][1] = 0f32;            self.m[3][2] = 0f32;    self.m[3][3] = 1f32;

        self
    }

    pub fn transform(&self, other: &Vector4f32) -> Vector4f32 {
        Vector4f32 {
            x: self.m[0][0] * other.x + self.m[0][1] * other.y + self.m[0][2] * other.z + self.m[0][3] * other.w,
            y: self.m[1][0] * other.x + self.m[1][1] * other.y + self.m[1][2] * other.z + self.m[1][3] * other.w,
            z: self.m[2][0] * other.x + self.m[2][1] * other.y + self.m[2][2] * other.z + self.m[2][3] * other.w,
            w: self.m[3][0] * other.x + self.m[3][1] * other.y + self.m[3][2] * other.z + self.m[3][3] * other.w }
    }

    pub fn mul(&self, other: &Matrix4f32) -> Matrix4f32 {

        let mut ret = Matrix4f32::new();

        for c_idx in 0..4 {
            for r_idx in 0..4 {
                ret.m[c_idx][r_idx] =
                self.m[c_idx][0] * other.m[0][r_idx] +
                self.m[c_idx][1] * other.m[1][r_idx] +
                self.m[c_idx][2] * other.m[2][r_idx] +
                self.m[c_idx][3] * other.m[3][r_idx];
            }
        }

        ret
    }
}

struct Vector4f32 {
    x: f32,
    y: f32,
    z: f32,
    w: f32
}

struct Vertex {
    pos: Vector4f32
}

impl Vertex {

    pub fn new(_x: f32, _y: f32, _z: f32) -> Vertex {
        Vertex{pos: Vector4f32{x: _x, y: _y, z: _z, w: 1f32}}
    }

    pub fn new_with_vector4f32(_pos: Vector4f32) -> Vertex {
        Vertex{pos: _pos}
    }

    pub fn calc_double_area(&self, v1: &Vertex, v2: &Vertex) -> i32 {

        let x1 = (v1.pos.x as i32 - self.pos.x as i32) as i32;
        let y1 = (v1.pos.y as i32 - self.pos.y as i32) as i32;
        let x2 = (v2.pos.x as i32 - self.pos.x as i32) as i32;
        let y2 = (v2.pos.y as i32 - self.pos.y as i32) as i32;

        (x1 * y2 - x2 * y1)
    }

    pub fn transform(&self, transform: &Matrix4f32) -> Vertex {
        Vertex::new_with_vector4f32(transform.transform(&self.pos))
    }

    pub fn perspective_divide(&self) -> Vertex {
        Vertex::new_with_vector4f32(Vector4f32{ x: self.pos.x / self.pos.w, y: self.pos.y / self.pos.w, z: self.pos.z / self.pos.w, w: self.pos.w})
    }

}

struct RenderContext {
    window: Box<orbclient::Window>,
    scan_buffer: Vec<i32> //TODO(dustin): do i need Vec<32> here? [i32]
}

impl RenderContext {
    pub fn new(width: u32, height: u32, title: &str) -> RenderContext {
        let orb_window = orbclient::Window::new_flags(100, 100, width, height, title, true).unwrap();
        RenderContext{scan_buffer: vec![0; (height * 2) as usize], window: orb_window}
    }

    pub fn get_height(&self) -> u32 {
        self.window.height()
    }

    pub fn get_width(&self) -> u32 {
        self.window.width()
    }

    pub fn events(&mut self) -> EventIter {
        self.window.events()
    }

    pub fn clear(&mut self) {
        self.window.set(orbclient::Color { data: 0xFF000000 });
    }

    pub fn sync(&mut self) {
        self.window.sync();
    }

    pub fn draw_triangle(&mut self, v1: &Vertex, v2: &Vertex, v3: &Vertex) {

        let mut inter = Matrix4f32::new(); //TODO(dustin): fix this
        let screen_space_transform = inter.init_sreenspace_transform(self.get_width() as f32 / 2f32, self.get_height() as f32 / 2f32);

        let mut min_vert = v1.transform(screen_space_transform).perspective_divide();
        let mut mid_vert = v2.transform(screen_space_transform).perspective_divide();
        let mut max_vert = v3.transform(screen_space_transform).perspective_divide();

        if max_vert.pos.y < mid_vert.pos.y {
            let tmp = max_vert;
            max_vert = mid_vert;
            mid_vert = tmp;
        }

        if mid_vert.pos.y < min_vert.pos.y {
            let tmp = mid_vert;
            mid_vert = min_vert;
            min_vert = tmp;
        }

        if max_vert.pos.y < mid_vert.pos.y {
            let tmp = max_vert;
            max_vert = mid_vert;
            mid_vert = tmp;
        }

        let area = min_vert.calc_double_area(&max_vert, &mid_vert);
        let side = if area >= 0 { 1 } else { 0 };
        self.convert_triangle(&min_vert, &mid_vert, &max_vert, side);
        self.fill_convex_shape(min_vert.pos.y as i32, max_vert.pos.y as i32);
    }

    fn fill_convex_shape(&mut self, y_min: i32, y_max: i32) {

        for y_idx in y_min..y_max {
            let x_min = self.scan_buffer.get((y_idx * 2) as usize).unwrap().clone();
            let x_max = self.scan_buffer.get((y_idx * 2 + 1) as usize).unwrap().clone();

            for x_idx in x_min..x_max {
                self.window.pixel(x_idx, y_idx, orbclient::Color { data: 0xFFFFFFFF });
            }
        }
    }

    fn convert_triangle(&mut self, min_vert: &Vertex, mid_vert: &Vertex, max_vert: &Vertex, side: i32) {
        self.convert_line(min_vert, max_vert, 0 + side);
        self.convert_line(min_vert, mid_vert, 1 - side);
        self.convert_line(mid_vert, max_vert, 1 - side);
    }

    fn convert_line(&mut self, min_vert: &Vertex, max_vert: &Vertex, side: i32) {
        let start_y = min_vert.pos.y;
        let start_x = min_vert.pos.x;
        let end_y = max_vert.pos.y;
        let end_x = max_vert.pos.x;

        let dist_y = end_y - start_y;
        let dist_x = end_x - start_x;

        if dist_y <= 0f32 {
            return;
        }

        let step_x = dist_x as f32 / dist_y as f32;
        let mut current_x = start_x as f32;

        for y_coord in start_y as i32..end_y as i32 {
            self.scan_buffer[((y_coord * 2 + side) as usize)] = current_x as i32;
            current_x += step_x;
        }
    }

}

fn main() {

    let mut render_context = RenderContext::new(500, 400, "pixelcannon");
    let mut start = Instant::now();

    let min_vert = Vertex::new(-1f32, -1f32, 0f32);
    let mid_vert = Vertex::new( 0f32,  1f32, 0f32);
    let max_vert = Vertex::new( 1f32, -1f32, 0f32);

    let mut inter = Matrix4f32::new();//TODO(dustin): fix this
    let projection = inter.init_perspective(70.0f32.to_radians(), render_context.get_width() as f32 / render_context.get_height() as f32, 0.1f32, 1000f32);

    let mut rot_cnt = 0.0f32;

    'event: loop {

        {
            let end = Instant::now();
            let delta = end.duration_since(start);
            let delta_ms = delta.as_secs() as f32 * 1000f32 + (delta.subsec_nanos() as f32)/1000000000 as f32;
            start = Instant::now();
            // println!("{:?} ms", delta_ms);

            rot_cnt += delta_ms as f32;
            let mut inter2 = Matrix4f32::new();
            let translation = inter2.init_translation(0.0f32, 0.0f32, 3.0f32);
            let mut inter3 = Matrix4f32::new();
            let rotation = inter3.init_rotation(0.0f32, rot_cnt, 0.0f32);
            let transform = &projection.mul(&translation.mul(&rotation));

            render_context.clear();
            render_context.draw_triangle(&min_vert.transform(&transform), &mid_vert.transform(&transform), &max_vert.transform(&transform));
            render_context.sync();

            // break 'event;
        }

        for orbital_event in render_context.events() {
            match orbital_event.to_option() {
                orbclient::EventOption::Quit(_quit_event) => break 'event,
                _ => (),
            };
        }

    }
}
<|endoftext|>


<commit_before>use clap::Clap;
use std::fs::File;

fn normalize_col(col: &str) -> String {
    lazy_static::lazy_static! {
        static ref RE: regex::Regex = regex::Regex::new(r"\(.*?\)").unwrap();
    }
    let mut col = RE
        .replace_all(col, "")
        .to_lowercase()
        .trim()
        .replace(" ", "_")
        .replace(".", "_")
        .replace("-", "_")
        .replace("/", "_")
        .replace("?", "")
        .replace(",", "_")
        .replace("&", "_");
    if !col.chars().next().unwrap().is_alphabetic() {
        col = format!("c_{}", col)
    }
    col
}

fn _create_table(db: &mut rusqlite::Connection, table_name: &str, cols: &[String]) {
    let create_columns = cols
        .iter()
        .map(|c| format!("{} varchar", c))
        .collect::<Vec<String>>()
        .join(", ");
    db.execute(
        &format!("CREATE TABLE {} ({})", table_name, create_columns),
        &[] as &[&dyn rusqlite::types::ToSql],
    )
    .unwrap();
}

fn _load_table_from_path(
    db: &mut rusqlite::Connection,
    table_name: &str,
    path: &str,
    delimiter: u8,
) -> Result<Vec<String>, Box<dyn std::error::Error>> {
    let mut num_rows = 0;
    let f = File::open(path)?;
    let file_size = f.metadata().unwrap().len();
    let mut reader = csv::ReaderBuilder::new()
        .flexible(true)
        .delimiter(delimiter)
        .from_reader(f);

    let normalized_cols =
        reader
            .headers()?
            .iter()
            .map(normalize_col)
            .fold(vec![], |mut v, orig_col| {
                let mut col = orig_col.clone();
                let mut i = 1;
                while v.contains(&col) {
                    col = format!("{}_{}", orig_col, i);
                    i += 1
                }
                v.push(col);
                v
            });
    _create_table(db, table_name, &normalized_cols);

    let insert_query = format!(
        "INSERT INTO {} VALUES ({})",
        table_name,
        normalized_cols
            .iter()
            .map(|_| "?")
            .collect::<Vec<_>>()
            .join(", ")
    );
    let pb = indicatif::ProgressBar::new(file_size);
    pb.set_style(
        indicatif::ProgressStyle::default_bar()
            .template("[{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta})")
            .progress_chars("#>-"),
    );
    let mut records = reader.records();
    let tx = db.transaction().unwrap();
    {
        let mut stmt = tx.prepare(&insert_query).expect("tx.prepare() failed");
        while let Some(row) = records.next() {
            let mut row = row?;
            if row.len() < normalized_cols.len() {
                for _ in 0..normalized_cols.len() - row.len() {
                    row.push_field("");
                }
            }
            stmt.execute(&row).unwrap();

            num_rows += 1;
            if num_rows % 10000 == 0 {
                pb.set_position(records.reader().position().byte())
            }
        }
    }
    tx.commit().unwrap();
    pb.finish();

    println!(
        "Loaded {} rows into {}({})",
        num_rows,
        table_name,
        normalized_cols.join(", "),
    );
    Ok(normalized_cols)
}

struct FromAnySqlType {
    value: String,
}

impl rusqlite::types::FromSql for FromAnySqlType {
    fn column_result(
        value: rusqlite::types::ValueRef<'_>,
    ) -> Result<FromAnySqlType, rusqlite::types::FromSqlError> {
        let result = match value {
            rusqlite::types::ValueRef::Null => "null".to_string(),
            rusqlite::types::ValueRef::Integer(v) => v.to_string(),
            rusqlite::types::ValueRef::Real(v) => v.to_string(),
            rusqlite::types::ValueRef::Blob(v) | rusqlite::types::ValueRef::Text(v) => {
                String::from_utf8(v.to_vec()).unwrap()
            }
        };
        Ok(FromAnySqlType { value: result })
    }
}

fn _prepare_query<'a>(
    conn: &'a mut rusqlite::Connection,
    query: &str,
) -> Result<rusqlite::Statement<'a>, String> {
    conn.prepare(&query).map_err(|e| e.to_string())
}

fn _handle_query(conn: &mut rusqlite::Connection, line: &str) -> Result<(), String> {
    let mut stmt = _prepare_query(conn, line)?;

    let mut table = comfy_table::Table::new();
    table.load_preset("││──╞═╪╡┆    ┬┴┌┐└┘");
    table.set_content_arrangement(comfy_table::ContentArrangement::Dynamic);
    let mut title_row = comfy_table::Row::new();
    for col in stmt.column_names() {
        title_row.add_cell(comfy_table::Cell::new(col));
    }
    table.set_header(title_row);

    let mut results = stmt.query(&[] as &[&dyn rusqlite::types::ToSql]).unwrap();
    while let Ok(Some(r)) = results.next() {
        let mut row = comfy_table::Row::new();
        for i in 0..r.column_count() {
            let cell: FromAnySqlType = r.get(i).unwrap();
            row.add_cell(comfy_table::Cell::new(&cell.value));
        }
        table.add_row(row);
    }
    println!("{}", table);
    Ok(())
}

fn _handle_export(conn: &mut rusqlite::Connection, line: &str) -> Result<(), String> {
    lazy_static::lazy_static! {
        static ref RE: regex::Regex = regex::Regex::new(r"^\.export\(([\w_\-\./]+)\) (.*)").unwrap();
    }
    let caps = RE
        .captures(line)
        .ok_or_else(|| "Must match `.export(file-name) SQL`".to_owned())?;
    let destination_path = &caps[1];
    let query = &caps[2];

    let mut stmt = _prepare_query(conn, query)?;

    let mut writer = csv::Writer::from_path(destination_path).unwrap();
    writer.write_record(stmt.column_names()).unwrap();

    let mut results = stmt.query(&[] as &[&dyn rusqlite::types::ToSql]).unwrap();
    while let Ok(Some(r)) = results.next() {
        writer
            .write_record((0..r.column_count()).map(|i| {
                let cell: FromAnySqlType = r.get(i).unwrap();
                cell.value
            }))
            .unwrap();
    }

    Ok(())
}

fn _process_query(conn: &mut rusqlite::Connection, line: &str) {
    let result = if line.starts_with(".export") {
        _handle_export(conn, line)
    } else {
        _handle_query(conn, line)
    };
    if let Err(e) = result {
        println!("{}", e);
    }
}

struct SimpleWordCompleter {
    words: Vec<String>,
}

static BREAK_CHARS: [u8; 4] = [b' ', b'(', b')', b','];
impl SimpleWordCompleter {
    fn new(words: Vec<String>) -> SimpleWordCompleter {
        SimpleWordCompleter { words }
    }
}

impl rustyline::Helper for SimpleWordCompleter {}

impl rustyline::hint::Hinter for SimpleWordCompleter {
    fn hint(&self, _line: &str, _pos: usize, _ctx: &rustyline::Context<'_>) -> Option<String> {
        None
    }
}

impl rustyline::highlight::Highlighter for SimpleWordCompleter {}

impl rustyline::validate::Validator for SimpleWordCompleter {}

impl rustyline::completion::Completer for SimpleWordCompleter {
    type Candidate = String;

    fn complete(
        &self,
        line: &str,
        pos: usize,
        _ctx: &rustyline::Context<'_>,
    ) -> rustyline::Result<(usize, Vec<String>)> {
        let (start, word) = rustyline::completion::extract_word(line, pos, None, &BREAK_CHARS);

        let matches = self
            .words
            .iter()
            .filter(|w| w.starts_with(word))
            .cloned()
            .collect();
        Ok((start, matches))
    }
}

#[derive(Clap)]
struct Opts {
    #[clap(long, about = "Use ',' as the delimiter for the CSV")]
    comma: bool,
    #[clap(long, about = "Use '|' as the delimiter for the CSV")]
    pipe: bool,
    #[clap(long, about = "Use '\\t' as the delimiter for the CSV")]
    tab: bool,

    #[clap()]
    paths: Vec<String>,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let opts = Opts::parse();

    let delim = match (opts.comma, opts.pipe, opts.tab) {
        (true, false, false) | (false, false, false) => b',',
        (false, true, false) => b'|',
        (false, false, true) => b'\t',
        _ => {
            eprintln!("Can't pass more than one of --comma, --pipe, and --tab");
            std::process::exit(1);
        }
    };

    let mut conn = rusqlite::Connection::open_in_memory().unwrap();

    let mut base_words = [
        "distinct", "select", "from", "group", "by", "order", "where", "count", "limit", "offset",
        ".export",
    ]
    .iter()
    .map(|&s| s.to_string())
    .collect::<Vec<String>>();

    if opts.paths.len() == 1 {
        let mut col_names = _load_table_from_path(&mut conn, "t", &opts.paths[0], delim)?;
        base_words.append(&mut col_names);
    } else {
        for (idx, path) in opts.paths.iter().enumerate() {
            let mut col_names =
                _load_table_from_path(&mut conn, &format!("t{}", idx + 1), path, delim)?;
            base_words.append(&mut col_names);
        }
    }

    let completer = SimpleWordCompleter::new(base_words);
    let mut rl = rustyline::Editor::new();
    rl.set_helper(Some(completer));
    loop {
        match rl.readline("> ") {
            Ok(line) => {
                if line.trim().is_empty() {
                    continue;
                }
                _process_query(&mut conn, &line);
                rl.add_history_entry(line);
            }
            Err(rustyline::error::ReadlineError::Interrupted) => {
                println!("Interrupted");
                continue;
            }
            Err(rustyline::error::ReadlineError::Eof) => {
                break;
            }
            Err(err) => {
                println!("Error: {}", err);
                break;
            }
        }
    }

    Ok(())
}

#[cfg(test)]
mod test {
    use super::normalize_col;

    #[test]
    fn test_normalize_col() {
        for (value, expected) in &[
            ("abc", "abc"),
            ("abc (123)", "abc"),
            ("2/6/2000", "c_2_6_2000"),
        ] {
            assert_eq!(&&normalize_col(value), expected);
        }
    }
}
<commit_msg>octothorpes<commit_after>use clap::Clap;
use std::fs::File;

fn normalize_col(col: &str) -> String {
    lazy_static::lazy_static! {
        static ref RE: regex::Regex = regex::Regex::new(r"\(.*?\)").unwrap();
    }
    let mut col = RE
        .replace_all(col, "")
        .to_lowercase()
        .trim()
        .replace(" ", "_")
        .replace(".", "_")
        .replace("-", "_")
        .replace("/", "_")
        .replace("?", "")
        .replace(",", "_")
        .replace("&", "_")
        .replace("#", "");
    if !col.chars().next().unwrap().is_alphabetic() {
        col = format!("c_{}", col)
    }
    col
}

fn _create_table(db: &mut rusqlite::Connection, table_name: &str, cols: &[String]) {
    let create_columns = cols
        .iter()
        .map(|c| format!("{} varchar", c))
        .collect::<Vec<String>>()
        .join(", ");
    db.execute(
        &format!("CREATE TABLE {} ({})", table_name, create_columns),
        &[] as &[&dyn rusqlite::types::ToSql],
    )
    .unwrap();
}

fn _load_table_from_path(
    db: &mut rusqlite::Connection,
    table_name: &str,
    path: &str,
    delimiter: u8,
) -> Result<Vec<String>, Box<dyn std::error::Error>> {
    let mut num_rows = 0;
    let f = File::open(path)?;
    let file_size = f.metadata().unwrap().len();
    let mut reader = csv::ReaderBuilder::new()
        .flexible(true)
        .delimiter(delimiter)
        .from_reader(f);

    let normalized_cols =
        reader
            .headers()?
            .iter()
            .map(normalize_col)
            .fold(vec![], |mut v, orig_col| {
                let mut col = orig_col.clone();
                let mut i = 1;
                while v.contains(&col) {
                    col = format!("{}_{}", orig_col, i);
                    i += 1
                }
                v.push(col);
                v
            });
    _create_table(db, table_name, &normalized_cols);

    let insert_query = format!(
        "INSERT INTO {} VALUES ({})",
        table_name,
        normalized_cols
            .iter()
            .map(|_| "?")
            .collect::<Vec<_>>()
            .join(", ")
    );
    let pb = indicatif::ProgressBar::new(file_size);
    pb.set_style(
        indicatif::ProgressStyle::default_bar()
            .template("[{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta})")
            .progress_chars("#>-"),
    );
    let mut records = reader.records();
    let tx = db.transaction().unwrap();
    {
        let mut stmt = tx.prepare(&insert_query).expect("tx.prepare() failed");
        while let Some(row) = records.next() {
            let mut row = row?;
            if row.len() < normalized_cols.len() {
                for _ in 0..normalized_cols.len() - row.len() {
                    row.push_field("");
                }
            }
            stmt.execute(&row).unwrap();

            num_rows += 1;
            if num_rows % 10000 == 0 {
                pb.set_position(records.reader().position().byte())
            }
        }
    }
    tx.commit().unwrap();
    pb.finish();

    println!(
        "Loaded {} rows into {}({})",
        num_rows,
        table_name,
        normalized_cols.join(", "),
    );
    Ok(normalized_cols)
}

struct FromAnySqlType {
    value: String,
}

impl rusqlite::types::FromSql for FromAnySqlType {
    fn column_result(
        value: rusqlite::types::ValueRef<'_>,
    ) -> Result<FromAnySqlType, rusqlite::types::FromSqlError> {
        let result = match value {
            rusqlite::types::ValueRef::Null => "null".to_string(),
            rusqlite::types::ValueRef::Integer(v) => v.to_string(),
            rusqlite::types::ValueRef::Real(v) => v.to_string(),
            rusqlite::types::ValueRef::Blob(v) | rusqlite::types::ValueRef::Text(v) => {
                String::from_utf8(v.to_vec()).unwrap()
            }
        };
        Ok(FromAnySqlType { value: result })
    }
}

fn _prepare_query<'a>(
    conn: &'a mut rusqlite::Connection,
    query: &str,
) -> Result<rusqlite::Statement<'a>, String> {
    conn.prepare(&query).map_err(|e| e.to_string())
}

fn _handle_query(conn: &mut rusqlite::Connection, line: &str) -> Result<(), String> {
    let mut stmt = _prepare_query(conn, line)?;

    let mut table = comfy_table::Table::new();
    table.load_preset("││──╞═╪╡┆    ┬┴┌┐└┘");
    table.set_content_arrangement(comfy_table::ContentArrangement::Dynamic);
    let mut title_row = comfy_table::Row::new();
    for col in stmt.column_names() {
        title_row.add_cell(comfy_table::Cell::new(col));
    }
    table.set_header(title_row);

    let mut results = stmt.query(&[] as &[&dyn rusqlite::types::ToSql]).unwrap();
    while let Ok(Some(r)) = results.next() {
        let mut row = comfy_table::Row::new();
        for i in 0..r.column_count() {
            let cell: FromAnySqlType = r.get(i).unwrap();
            row.add_cell(comfy_table::Cell::new(&cell.value));
        }
        table.add_row(row);
    }
    println!("{}", table);
    Ok(())
}

fn _handle_export(conn: &mut rusqlite::Connection, line: &str) -> Result<(), String> {
    lazy_static::lazy_static! {
        static ref RE: regex::Regex = regex::Regex::new(r"^\.export\(([\w_\-\./]+)\) (.*)").unwrap();
    }
    let caps = RE
        .captures(line)
        .ok_or_else(|| "Must match `.export(file-name) SQL`".to_owned())?;
    let destination_path = &caps[1];
    let query = &caps[2];

    let mut stmt = _prepare_query(conn, query)?;

    let mut writer = csv::Writer::from_path(destination_path).unwrap();
    writer.write_record(stmt.column_names()).unwrap();

    let mut results = stmt.query(&[] as &[&dyn rusqlite::types::ToSql]).unwrap();
    while let Ok(Some(r)) = results.next() {
        writer
            .write_record((0..r.column_count()).map(|i| {
                let cell: FromAnySqlType = r.get(i).unwrap();
                cell.value
            }))
            .unwrap();
    }

    Ok(())
}

fn _process_query(conn: &mut rusqlite::Connection, line: &str) {
    let result = if line.starts_with(".export") {
        _handle_export(conn, line)
    } else {
        _handle_query(conn, line)
    };
    if let Err(e) = result {
        println!("{}", e);
    }
}

struct SimpleWordCompleter {
    words: Vec<String>,
}

static BREAK_CHARS: [u8; 4] = [b' ', b'(', b')', b','];
impl SimpleWordCompleter {
    fn new(words: Vec<String>) -> SimpleWordCompleter {
        SimpleWordCompleter { words }
    }
}

impl rustyline::Helper for SimpleWordCompleter {}

impl rustyline::hint::Hinter for SimpleWordCompleter {
    fn hint(&self, _line: &str, _pos: usize, _ctx: &rustyline::Context<'_>) -> Option<String> {
        None
    }
}

impl rustyline::highlight::Highlighter for SimpleWordCompleter {}

impl rustyline::validate::Validator for SimpleWordCompleter {}

impl rustyline::completion::Completer for SimpleWordCompleter {
    type Candidate = String;

    fn complete(
        &self,
        line: &str,
        pos: usize,
        _ctx: &rustyline::Context<'_>,
    ) -> rustyline::Result<(usize, Vec<String>)> {
        let (start, word) = rustyline::completion::extract_word(line, pos, None, &BREAK_CHARS);

        let matches = self
            .words
            .iter()
            .filter(|w| w.starts_with(word))
            .cloned()
            .collect();
        Ok((start, matches))
    }
}

#[derive(Clap)]
struct Opts {
    #[clap(long, about = "Use ',' as the delimiter for the CSV")]
    comma: bool,
    #[clap(long, about = "Use '|' as the delimiter for the CSV")]
    pipe: bool,
    #[clap(long, about = "Use '\\t' as the delimiter for the CSV")]
    tab: bool,

    #[clap()]
    paths: Vec<String>,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let opts = Opts::parse();

    let delim = match (opts.comma, opts.pipe, opts.tab) {
        (true, false, false) | (false, false, false) => b',',
        (false, true, false) => b'|',
        (false, false, true) => b'\t',
        _ => {
            eprintln!("Can't pass more than one of --comma, --pipe, and --tab");
            std::process::exit(1);
        }
    };

    let mut conn = rusqlite::Connection::open_in_memory().unwrap();

    let mut base_words = [
        "distinct", "select", "from", "group", "by", "order", "where", "count", "limit", "offset",
        ".export",
    ]
    .iter()
    .map(|&s| s.to_string())
    .collect::<Vec<String>>();

    if opts.paths.len() == 1 {
        let mut col_names = _load_table_from_path(&mut conn, "t", &opts.paths[0], delim)?;
        base_words.append(&mut col_names);
    } else {
        for (idx, path) in opts.paths.iter().enumerate() {
            let mut col_names =
                _load_table_from_path(&mut conn, &format!("t{}", idx + 1), path, delim)?;
            base_words.append(&mut col_names);
        }
    }

    let completer = SimpleWordCompleter::new(base_words);
    let mut rl = rustyline::Editor::new();
    rl.set_helper(Some(completer));
    loop {
        match rl.readline("> ") {
            Ok(line) => {
                if line.trim().is_empty() {
                    continue;
                }
                _process_query(&mut conn, &line);
                rl.add_history_entry(line);
            }
            Err(rustyline::error::ReadlineError::Interrupted) => {
                println!("Interrupted");
                continue;
            }
            Err(rustyline::error::ReadlineError::Eof) => {
                break;
            }
            Err(err) => {
                println!("Error: {}", err);
                break;
            }
        }
    }

    Ok(())
}

#[cfg(test)]
mod test {
    use super::normalize_col;

    #[test]
    fn test_normalize_col() {
        for (value, expected) in &[
            ("abc", "abc"),
            ("abc (123)", "abc"),
            ("2/6/2000", "c_2_6_2000"),
            ("COMBO#", "combo"),
        ] {
            assert_eq!(&&normalize_col(value), expected);
        }
    }
}
<|endoftext|>


<commit_before>extern crate editorconfig;
extern crate argparse;

use editorconfig::*;
use argparse::{ArgumentParser, Store, List, Print};
use std::path::Path;

fn main() {
    let mut conf_filename = ".editorconfig".to_string();
    let mut version = "".to_string();
    let mut targets: Vec<String> = vec![];
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Parse .editorconfig files.");
        ap.refer(&mut conf_filename)
            .add_option(&["-f"], Store, "Conf filename");
        ap.refer(&mut version)
            .add_option(&["-b"], Store, "editorconfig version");
        ap.add_option(&["-v", "--version"],
            Print(format!("EditorConfig Rust Core Version {}", env!("CARGO_PKG_VERSION"))), "Show version");
        ap.refer(&mut targets)
            .add_argument("arguments", List, "Files to check");
        ap.parse_args_or_exit();
    }

    let multiple_targets = targets.len() > 1;

    for t in targets {
        if multiple_targets {
            println!("[{}]", t);
        }

        let res = get_config_conffile(Path::new(&t), &conf_filename).unwrap();
        for (k, v) in res.iter() {
            println!("{}={}", *k, *v);
        }
    }
}
<commit_msg>Add workaround for backwards compatibility test<commit_after>extern crate editorconfig;
extern crate argparse;

use editorconfig::*;
use argparse::{ArgumentParser, Store, List, Print};
use std::path::Path;

fn main() {
    let mut conf_filename = ".editorconfig".to_string();
    let mut version = "".to_string();
    let mut targets: Vec<String> = vec![];
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Parse .editorconfig files.");
        ap.refer(&mut conf_filename)
            .add_option(&["-f"], Store, "Conf filename");
        ap.refer(&mut version)
            .add_option(&["-b"], Store, "editorconfig version");
        ap.add_option(&["-v", "--version"],
            Print(format!("EditorConfig Rust Core Version {}", env!("CARGO_PKG_VERSION"))), "Show version");
        ap.refer(&mut targets)
            .add_argument("arguments", List, "Files to check");
        ap.parse_args_or_exit();
    }

    let multiple_targets = targets.len() > 1;

    for t in targets {
        if multiple_targets {
            println!("[{}]", t);
        }

        let res = get_config_conffile(Path::new(&t), &conf_filename).unwrap();
        for (k, v) in res.iter() {
            if version != "0.8.0" || k != "indent_size" {
                println!("{}={}", *k, *v);
            }
        }
    }
}
<|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 "rust-md2" as md2;

use md2::{S, S2, md2_compress};
use std::collections::HashMap;
use std::collections::hash_map::{Occupied, Vacant};
use std::slice::bytes::copy_memory;

type Collision = Vec<Vec<u8>>;
type Collisions = Vec<Collision>;

fn find_collisions(state: [[u8, ..49], ..19], k: uint) -> Collisions {
    let mut state = state;
    let mut bytes = Vec::from_elem(k, 0u8);
    let mut collisions: HashMap<Vec<u8>,Collision> = HashMap::new();

    let rows = 16 - k;

    loop {
        copy_memory(state[rows].slice_mut(17, 17 + k), bytes.as_slice());
        copy_memory(state[rows].slice_mut(17 + 16, 17 + k + 16), bytes.as_slice());

        for row in range(rows + 1, 18) {
            // Fill row.
            for i in range(1, 49) {
                state[row][i] = S[state[row][i - 1] as uint] ^ state[row - 1][i];
            }

            // Next t value.
            state[row + 1][0] = state[row][48] + (row as u8) - 1;
        }

        let key = Vec::from_fn(17 - rows, |row| state[rows + 2 + row][0]);

        match collisions.entry(key) {
            Vacant(entry) => { entry.set(vec!(bytes.clone())); },
            Occupied(mut entry) => { entry.get_mut().push(bytes.clone()); }
        };

        if !increase(bytes.as_mut_slice()) {
            break;
        }
    }

    // Compute original messages for each collision.
    collisions.values().filter(|x| x.len() > 1).map(|collision| {
        collision.iter().map(|bytes| {
            copy_memory(state[rows].slice_mut(17, 17 + k), bytes.as_slice());
            copy_memory(state[rows].slice_mut(17 + 16, 17 + k + 16), bytes.as_slice());

            // Fill upper rectangles.
            for row in range(1, rows + 1).rev() {
                for col in range(17, 32 - row + 2) {
                    state[row - 1][col] = S[state[row][col - 1] as uint] ^ state[row][col];
                }
            }

            state[0].slice(17, 33).to_vec()
        }).collect()
    }).collect()
}

fn create_initial_state(k: uint) -> [[u8, ..49], ..19] {
    let rows = 16 - k;
    let mut values = [[0u8, ..49], ..19];

    for row in range(1, rows + 1) {
        // Fill row of T1.
        for i in range(1, 17) {
            values[row][i] = S[values[row][i - 1] as uint] ^ values[row - 1][i];
        }

        // Last bytes are equal.
        values[row][32] = values[row][16];
        values[row][48] = values[row][16];

        // Next t value.
        values[row + 1][0] = values[row][48] + (row as u8) - 1;
    }

    // Compute triangles.
    for col in range(0, rows) {
        for row in range(2 + col, rows + 1).rev() {
            values[row][32 - col - 1] = S2[(values[row][32 - col] ^ values[row - 1][32 - col]) as uint];
            values[row][48 - col - 1] = S2[(values[row][48 - col] ^ values[row - 1][48 - col]) as uint];
        }
    }

    values
}

fn increase(num: &mut [u8]) -> bool {
    // Iterate bytes starting from the end.
    range(0, num.len()).rev().any(|i| {
        if num[i] == 255 {
            return false;
        }

        // Increase.
        num[i] += 1;

        // Set all bytes right of the current index to zero.
        for i in range(i + 1, num.len()) {
            num[i] = 0;
        }

        true
    })
}

fn check_collision(collision: &Collision) -> bool {
    let empty = [0u8, ..16];
    let mut first_hash: Option<[u8, ..16]> = None;
    let mut hashes = collision.iter().map(|msg| {
        md2_compress(&empty, msg.as_slice())
    });

    hashes.all(|md2| {
        first_hash.map_or_else(|| {
            first_hash = Some(md2);
            true
        }, |v| v == md2)
    })
}

fn main() {
    let k = 2;
    let state = create_initial_state(k);
    let collisions = find_collisions(state, k);

    // Check that the colliding messages we found generate the same hashes.
    if !collisions.iter().all(check_collision) {
        panic!("invalid collision found :(");
    }

    println!("Found {} collisions.", collisions.iter().count());
}
<commit_msg>s/values/state<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 "rust-md2" as md2;

use md2::{S, S2, md2_compress};
use std::collections::HashMap;
use std::collections::hash_map::{Occupied, Vacant};
use std::slice::bytes::copy_memory;

type Collision = Vec<Vec<u8>>;
type Collisions = Vec<Collision>;

fn find_collisions(state: [[u8, ..49], ..19], k: uint) -> Collisions {
    let mut state = state;
    let mut bytes = Vec::from_elem(k, 0u8);
    let mut collisions: HashMap<Vec<u8>,Collision> = HashMap::new();

    let rows = 16 - k;

    loop {
        copy_memory(state[rows].slice_mut(17, 17 + k), bytes.as_slice());
        copy_memory(state[rows].slice_mut(17 + 16, 17 + k + 16), bytes.as_slice());

        for row in range(rows + 1, 18) {
            // Fill row.
            for i in range(1, 49) {
                state[row][i] = S[state[row][i - 1] as uint] ^ state[row - 1][i];
            }

            // Next t value.
            state[row + 1][0] = state[row][48] + (row as u8) - 1;
        }

        let key = Vec::from_fn(17 - rows, |row| state[rows + 2 + row][0]);

        match collisions.entry(key) {
            Vacant(entry) => { entry.set(vec!(bytes.clone())); },
            Occupied(mut entry) => { entry.get_mut().push(bytes.clone()); }
        };

        if !increase(bytes.as_mut_slice()) {
            break;
        }
    }

    // Compute original messages for each collision.
    collisions.values().filter(|x| x.len() > 1).map(|collision| {
        collision.iter().map(|bytes| {
            copy_memory(state[rows].slice_mut(17, 17 + k), bytes.as_slice());
            copy_memory(state[rows].slice_mut(17 + 16, 17 + k + 16), bytes.as_slice());

            // Fill upper rectangles.
            for row in range(1, rows + 1).rev() {
                for col in range(17, 32 - row + 2) {
                    state[row - 1][col] = S[state[row][col - 1] as uint] ^ state[row][col];
                }
            }

            state[0].slice(17, 33).to_vec()
        }).collect()
    }).collect()
}

fn create_initial_state(k: uint) -> [[u8, ..49], ..19] {
    let rows = 16 - k;
    let mut state = [[0u8, ..49], ..19];

    for row in range(1, rows + 1) {
        // Fill row of T1.
        for i in range(1, 17) {
            state[row][i] = S[state[row][i - 1] as uint] ^ state[row - 1][i];
        }

        // Last bytes are equal.
        state[row][32] = state[row][16];
        state[row][48] = state[row][16];

        // Next t value.
        state[row + 1][0] = state[row][48] + (row as u8) - 1;
    }

    // Compute triangles.
    for col in range(0, rows) {
        for row in range(2 + col, rows + 1).rev() {
            state[row][32 - col - 1] = S2[(state[row][32 - col] ^ state[row - 1][32 - col]) as uint];
            state[row][48 - col - 1] = S2[(state[row][48 - col] ^ state[row - 1][48 - col]) as uint];
        }
    }

    state
}

fn increase(num: &mut [u8]) -> bool {
    // Iterate bytes starting from the end.
    range(0, num.len()).rev().any(|i| {
        if num[i] == 255 {
            return false;
        }

        // Increase.
        num[i] += 1;

        // Set all bytes right of the current index to zero.
        for i in range(i + 1, num.len()) {
            num[i] = 0;
        }

        true
    })
}

fn check_collision(collision: &Collision) -> bool {
    let empty = [0u8, ..16];
    let mut first_hash: Option<[u8, ..16]> = None;
    let mut hashes = collision.iter().map(|msg| {
        md2_compress(&empty, msg.as_slice())
    });

    hashes.all(|md2| {
        first_hash.map_or_else(|| {
            first_hash = Some(md2);
            true
        }, |v| v == md2)
    })
}

fn main() {
    let k = 2;
    let state = create_initial_state(k);
    let collisions = find_collisions(state, k);

    // Check that the colliding messages we found generate the same hashes.
    if !collisions.iter().all(check_collision) {
        panic!("invalid collision found :(");
    }

    println!("Found {} collisions.", collisions.iter().count());
}
<|endoftext|>


<commit_before>extern crate unicode_names;
extern crate byteorder;

use std::env;
use std::fmt;
use std::str;
use std::char;

use byteorder::{ByteOrder, BigEndian};

mod ascii;

struct Describable {
    c: char,
}

impl fmt::Display for Describable {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let cp : Codepoint = self.c.into();
        try!(cp.fmt(f));
        let printable : Printable = self.c.into();
        try!(write!(f, "\n{}", printable));
        let unicode_name = unicode_names::name(self.c);
        if let Some(n) = unicode_name.clone() {
            try!(write!(f, "\nUnicode name: {}\n", n));
        }
        if let Some(ascii) = ascii::additional_names(self.c) {
            let mut synonyms = vec!();
            let mut xmls: Option<&str> = None;
            for syn in ascii.synonyms {
                if let Some(unicode) = unicode_name.clone() {
                    if syn.starts_with('&') && syn.ends_with(';') {
                        xmls = Some(syn);
                    } else if format!("{}", unicode).as_str().to_lowercase() != *syn.to_lowercase() {
                        synonyms.push(syn.clone());
                    }
                }
            }
            if synonyms.len() > 0 {
                try!(write!(f, "Also known as: {}", synonyms.join(", ")));
            }
            if let Some(xml) = xmls {
                try!(write!(f, "\nEscapes in XML as: {}", xml));
            }
            if let Some(n) = ascii.note {
                try!(write!(f, "\nNote: {}", n));
            }
        }
        Ok(())
    }
}

impl std::convert::From<char> for Describable {
    fn from(c: char) -> Describable {
        Describable{c: c}
    }
}

struct Printable {
    c: char,
}

impl std::convert::From<char> for Printable {
    fn from(c: char) -> Printable {
        Printable{c: c}
    }
}

impl fmt::Display for Printable {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let quote : String = self.c.escape_default().collect();
        if self.c.is_control() {
            try!(write!(f, "Control character; quotes as {}", quote));
        } else {
            if ! self.c.is_whitespace() {
                try!(write!(f, "Prints as {}", self.c));
            } else {
                try!(write!(f, "Prints as `{}'", self.c));
            }
            // Check if we can up/downcase:
            let mut caseflipped = String::new();
            if self.c.is_uppercase() {
                for c in self.c.to_lowercase() {
                    caseflipped.push(c);
                }
                try!(write!(f, "\nUpper case. Downcases to {}", caseflipped));
            } else if self.c.is_lowercase() {
                for c in self.c.to_uppercase() {
                    caseflipped.push(c);
                }
                try!(write!(f, "\nLower case. Upcases to {}", caseflipped));
            }

            // If we have quotable text, print that too:
            if quote.len() > 1 {
                try!(write!(f, "\nQuotes as {}", quote));
            }
        }
        Ok(())
    }
}

enum Codepoint {
    ASCII7bit(char),
    Latin1(char),
    UnicodeBasic(char),
    UnicodeWide(char)
}

impl std::convert::From<char> for Codepoint {
    fn from(c: char) -> Codepoint {
        match c as u32 {
            0 ... 128 => Codepoint::ASCII7bit(c),
            128 ... 256 => Codepoint::Latin1(c),
            256 ... 65536 => Codepoint::UnicodeBasic(c),
            _ => Codepoint::UnicodeWide(c),
        }
    }
}

impl fmt::Display for Codepoint {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self {
            &Codepoint::ASCII7bit(c) => {
                let num = c as u32;
                write!(f, "ASCII {:1x}/{:1x}, {:3}, 0x{:02x}, 0{:03o}, bits {:08b}",
                       (num & 0xf0) >> 4, num & 0x0f, num, num, num, num)
            }
            &Codepoint::Latin1(c) => {
                let num = c as u32;
                write!(f, "LATIN1 {:02x}, {:3}, 0x{:02x}, 0{:03o}, bits {:08b}",
                       num, num, num, num, num)
            }
            &Codepoint::UnicodeBasic(c) | &Codepoint::UnicodeWide(c) => {
                let num = c as u32;
                let mut string = String::new();
                string.push(c);
                let s = string.as_str();
                let utf8 = ByteRepresentation::from(s.bytes());
                let utf16 = ByteRepresentation::from(s.encode_utf16());
                let width = match self {
                    &Codepoint::UnicodeWide(_) => 8,
                    _ => 4,
                };
                write!(f, "U+{:0width$X}, &#{:}; 0x{:0width$X}, \\0{:o}, UTF-8: {}, UTF-16BE: {}",
                       num, num, num, num, utf8, utf16, width = width)
            }
        }
    }
}

enum ByteRepresentation {
    UTF8(Vec<u8>),
    UTF16BE(Vec<u8>),
}

impl<'a> std::convert::From<str::EncodeUtf16<'a>> for ByteRepresentation {
    fn from(bs: str::EncodeUtf16<'a>) -> ByteRepresentation {
        let words: Vec<u16> = bs.collect();
        let mut buf: Vec<u8> = Vec::with_capacity(words.len() * 2);
        for word in words {
            let mut split_word = [0; 2];
            BigEndian::write_u16(&mut split_word, word);
            buf.extend_from_slice(&split_word);
        }

        ByteRepresentation::UTF16BE(buf)
    }
}

impl<'a> std::convert::From<str::Bytes<'a>> for ByteRepresentation {
    fn from(bs: str::Bytes<'a>) -> ByteRepresentation {
        let bytes: Vec<u8> = bs.collect();
        ByteRepresentation::UTF8(bytes)
    }
}

impl fmt::Display for ByteRepresentation {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self {
            &ByteRepresentation::UTF8(ref bytes) => {
                let mut byte_iter = bytes.iter();
                try!(write!(f, "{:02x}", byte_iter.next().unwrap()));
                for byte in byte_iter {
                    try!(write!(f, " {:02x}", byte));
                }
            },
            &ByteRepresentation::UTF16BE(ref bytes) => {
                for byte in bytes.iter() {
                    try!(write!(f, "{:02x}", byte));
                }
            }
        }
        Ok(())
    }
}

/// Takes a stringly description of a character (the character itself,
/// or a unicode code point name) and returns a Vec of Describable
/// elements that hold the corresponding character. The elements of
/// the vector are sorted by descending numeric code point.
fn from_arg(spec: &str) -> Vec<Describable> {
    let mut chars: Vec<char> = Vec::new();

    // match the character itself, or any of its names:
    if spec.chars().count() == 1 {
        spec.chars().next().map(|c| chars.push(c));
    } else {
        unicode_names::character(spec).map(|c| chars.push(c));
    }
    // Match hex/U+ strings specifically:
    if spec.starts_with("0x") || spec.starts_with("U+") {
        let _ = u32::from_str_radix(&spec[2..], 16).ok().
            map(|num| char::from_u32(num).map(|c| chars.push(c)));
    }

    // Match plain numbers in all bases:
    for base in vec![16, 10, 8, 2] {
        let _ = u32::from_str_radix(spec, base.clone()).ok().
            map(|num| char::from_u32(num).map(|c| chars.push(c)));
    }

    if let Some(ch) = ascii::lookup_by_name(spec) {
        chars.push(ch);
    }

    chars.sort_by(|a, b| b.cmp(a));
    chars.dedup();
    chars.iter().map(|c| c.clone().into()).collect()
}

fn main() {
    let args =
        env::args().skip(1)
        .flat_map(|argument| from_arg(argument.as_ref()));
    for c in args {
        println!("{}", c);
    }
}

#[test]
fn from_arg_translates_chars() {
    assert_eq!('n', from_arg("n")[0].c);
    assert_eq!(']', from_arg("]")[0].c);
}

#[test]
fn from_arg_translates_descriptions() {
    assert_eq!('n', from_arg("latin small letter n")[0].c);
    assert_eq!(']', from_arg("right square bracket")[0].c);
}

#[test]
fn from_arg_translates_numbers() {
    let received = from_arg("60");
    let mut iter = received.iter();
    assert_eq!('`', iter.next().unwrap().c);
    assert_eq!('<', iter.next().unwrap().c);
    assert_eq!('0', iter.next().unwrap().c);

    assert_eq!(2, from_arg("0").len());
    assert_eq!(0x30, from_arg("0").iter().next().unwrap().c as u32);

    assert_eq!(1, from_arg("0x0").len());
    assert_eq!(1, from_arg("0x41").len());
    assert_eq!('A', from_arg("0x41")[0].c);
}
<commit_msg>Improve printing of control characters<commit_after>extern crate unicode_names;
extern crate byteorder;

use std::env;
use std::fmt;
use std::str;
use std::char;

use byteorder::{ByteOrder, BigEndian};

mod ascii;

struct Describable {
    c: char,
}

impl fmt::Display for Describable {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let cp : Codepoint = self.c.into();
        try!(cp.fmt(f));
        let printable : Printable = self.c.into();
        try!(write!(f, "\n{}", printable));
        let unicode_name = unicode_names::name(self.c);
        if let Some(n) = unicode_name.clone() {
            try!(write!(f, "\nUnicode name: {}\n", n));
        }
        if let Some(ascii) = ascii::additional_names(self.c) {
            let mut synonyms = vec!();
            let mut xmls: Option<&str> = None;
            let mnemos: Vec<&str> = ascii.mnemonics.iter().filter(|n| n.len() != 1).map(|s| *s).collect();
            for syn in ascii.synonyms {
                if syn.starts_with('&') && syn.ends_with(';') {
                    xmls = Some(syn);
                } else if let Some(unicode) = unicode_name.clone() {
                    if format!("{}", unicode).as_str().to_lowercase() != *syn.to_lowercase() {
                        synonyms.push(syn.clone());
                    }
                } else {
                    synonyms.push(syn.clone());
                }
            }
            if mnemos.len() > 0 {
                try!(write!(f, "Called: {}\n", mnemos.join(", ")));
            }
            if synonyms.len() > 0 {
                try!(write!(f, "Also known as: {}\n", synonyms.join(", ")));
            }
            if let Some(xml) = xmls {
                try!(write!(f, "Escapes in XML as: {}\n", xml));
            }
            if let Some(n) = ascii.note {
                try!(write!(f, "Note: {}\n", n));
            }
        }
        Ok(())
    }
}

impl std::convert::From<char> for Describable {
    fn from(c: char) -> Describable {
        Describable{c: c}
    }
}

struct Printable {
    c: char,
}

impl std::convert::From<char> for Printable {
    fn from(c: char) -> Printable {
        Printable{c: c}
    }
}

impl fmt::Display for Printable {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let quote : String = self.c.escape_default().collect();
        if self.c.is_control() {
            try!(write!(f, "Control character; quotes as {}\n", quote));
        } else {
            if ! self.c.is_whitespace() {
                try!(write!(f, "Prints as {}", self.c));
            } else {
                try!(write!(f, "Prints as `{}'", self.c));
            }
            // Check if we can up/downcase:
            let mut caseflipped = String::new();
            if self.c.is_uppercase() {
                for c in self.c.to_lowercase() {
                    caseflipped.push(c);
                }
                try!(write!(f, "\nUpper case. Downcases to {}", caseflipped));
            } else if self.c.is_lowercase() {
                for c in self.c.to_uppercase() {
                    caseflipped.push(c);
                }
                try!(write!(f, "\nLower case. Upcases to {}", caseflipped));
            }

            // If we have quotable text, print that too:
            if quote.len() > 1 {
                try!(write!(f, "\nQuotes as {}", quote));
            }
        }
        Ok(())
    }
}

enum Codepoint {
    ASCII7bit(char),
    Latin1(char),
    UnicodeBasic(char),
    UnicodeWide(char)
}

impl std::convert::From<char> for Codepoint {
    fn from(c: char) -> Codepoint {
        match c as u32 {
            0 ... 128 => Codepoint::ASCII7bit(c),
            128 ... 256 => Codepoint::Latin1(c),
            256 ... 65536 => Codepoint::UnicodeBasic(c),
            _ => Codepoint::UnicodeWide(c),
        }
    }
}

impl fmt::Display for Codepoint {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self {
            &Codepoint::ASCII7bit(c) => {
                let num = c as u32;
                write!(f, "ASCII {:1x}/{:1x}, {:3}, 0x{:02x}, 0{:03o}, bits {:08b}",
                       (num & 0xf0) >> 4, num & 0x0f, num, num, num, num)
            }
            &Codepoint::Latin1(c) => {
                let num = c as u32;
                write!(f, "LATIN1 {:02x}, {:3}, 0x{:02x}, 0{:03o}, bits {:08b}",
                       num, num, num, num, num)
            }
            &Codepoint::UnicodeBasic(c) | &Codepoint::UnicodeWide(c) => {
                let num = c as u32;
                let mut string = String::new();
                string.push(c);
                let s = string.as_str();
                let utf8 = ByteRepresentation::from(s.bytes());
                let utf16 = ByteRepresentation::from(s.encode_utf16());
                let width = match self {
                    &Codepoint::UnicodeWide(_) => 8,
                    _ => 4,
                };
                write!(f, "U+{:0width$X}, &#{:}; 0x{:0width$X}, \\0{:o}, UTF-8: {}, UTF-16BE: {}",
                       num, num, num, num, utf8, utf16, width = width)
            }
        }
    }
}

enum ByteRepresentation {
    UTF8(Vec<u8>),
    UTF16BE(Vec<u8>),
}

impl<'a> std::convert::From<str::EncodeUtf16<'a>> for ByteRepresentation {
    fn from(bs: str::EncodeUtf16<'a>) -> ByteRepresentation {
        let words: Vec<u16> = bs.collect();
        let mut buf: Vec<u8> = Vec::with_capacity(words.len() * 2);
        for word in words {
            let mut split_word = [0; 2];
            BigEndian::write_u16(&mut split_word, word);
            buf.extend_from_slice(&split_word);
        }

        ByteRepresentation::UTF16BE(buf)
    }
}

impl<'a> std::convert::From<str::Bytes<'a>> for ByteRepresentation {
    fn from(bs: str::Bytes<'a>) -> ByteRepresentation {
        let bytes: Vec<u8> = bs.collect();
        ByteRepresentation::UTF8(bytes)
    }
}

impl fmt::Display for ByteRepresentation {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self {
            &ByteRepresentation::UTF8(ref bytes) => {
                let mut byte_iter = bytes.iter();
                try!(write!(f, "{:02x}", byte_iter.next().unwrap()));
                for byte in byte_iter {
                    try!(write!(f, " {:02x}", byte));
                }
            },
            &ByteRepresentation::UTF16BE(ref bytes) => {
                for byte in bytes.iter() {
                    try!(write!(f, "{:02x}", byte));
                }
            }
        }
        Ok(())
    }
}

/// Takes a stringly description of a character (the character itself,
/// or a unicode code point name) and returns a Vec of Describable
/// elements that hold the corresponding character. The elements of
/// the vector are sorted by descending numeric code point.
fn from_arg(spec: &str) -> Vec<Describable> {
    let mut chars: Vec<char> = Vec::new();

    // match the character itself, or any of its names:
    if spec.chars().count() == 1 {
        spec.chars().next().map(|c| chars.push(c));
    } else {
        unicode_names::character(spec).map(|c| chars.push(c));
    }
    // Match hex/U+ strings specifically:
    if spec.starts_with("0x") || spec.starts_with("U+") {
        let _ = u32::from_str_radix(&spec[2..], 16).ok().
            map(|num| char::from_u32(num).map(|c| chars.push(c)));
    }

    // Match plain numbers in all bases:
    for base in vec![16, 10, 8, 2] {
        let _ = u32::from_str_radix(spec, base.clone()).ok().
            map(|num| char::from_u32(num).map(|c| chars.push(c)));
    }

    // Match characters by ascii(1) name / alias:
    if let Some(ch) = ascii::lookup_by_name(spec) {
        chars.push(ch);
    }

    chars.sort_by(|a, b| b.cmp(a));
    chars.dedup();
    chars.iter().map(|c| c.clone().into()).collect()
}

fn main() {
    let args =
        env::args().skip(1)
        .flat_map(|argument| from_arg(argument.as_ref()));
    for c in args {
        println!("{}", c);
    }
}

#[test]
fn from_arg_translates_chars() {
    assert_eq!('n', from_arg("n")[0].c);
    assert_eq!(']', from_arg("]")[0].c);
}

#[test]
fn from_arg_translates_descriptions() {
    assert_eq!('n', from_arg("latin small letter n")[0].c);
    assert_eq!(']', from_arg("right square bracket")[0].c);
}

#[test]
fn from_arg_translates_numbers() {
    let received = from_arg("60");
    let mut iter = received.iter();
    assert_eq!('`', iter.next().unwrap().c);
    assert_eq!('<', iter.next().unwrap().c);
    assert_eq!('0', iter.next().unwrap().c);

    assert_eq!(2, from_arg("0").len());
    assert_eq!(0x30, from_arg("0").iter().next().unwrap().c as u32);

    assert_eq!(1, from_arg("0x0").len());
    assert_eq!(1, from_arg("0x41").len());
    assert_eq!('A', from_arg("0x41")[0].c);
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
#[macro_use]
extern crate nom;
#[macro_use]
extern crate quick_error;
extern crate walkdir;

mod error;
mod file;
mod parser;
mod questions;
mod template;
mod template_file;

use clap::{App, AppSettings};

use std::env;
use std::path::{Path, PathBuf};

use error::{Error, Result};
use template_file::{RenderedFile, compile_templates};

fn run() -> Result<()> {
    let yaml = load_yaml!("cli.yaml");
    let matches = App::from_yaml(yaml)
        .setting(AppSettings::ArgRequiredElseHelp)
        .get_matches();

    let source_arg = matches
        .value_of("source")
        .expect("Source is a required argument");
    let dest_arg = matches.value_of("destination").unwrap_or("");

    let source = find_source(source_arg)?;
    let dest = find_destination(dest_arg)?;

    let files = file::read_all_files(&source)?;
    let (templates, vars) = compile_templates(&files);

    println!("Fill in the variable values:");
    let conf = questions::get_vars(&vars)?;

    let rendered = templates
        .iter()
        .map(|t| t.render(&conf))
        .collect::<Result<Vec<RenderedFile>>>()?;

    println!("\nFiles will be saved in {}", dest.to_str().unwrap());

    for f in rendered {
        let path = dest.join(&f.path);
        print!("Writing {}... ", &f.path.to_str().unwrap());
        file::write_file(&path, &f.body)?;
        println!("OK");
    }

    println!("\nDone");

    Ok(())
}

pub fn find_source(source_arg: &str) -> Result<PathBuf> {
    let mut path = Path::new(source_arg).to_owned();
    if path.is_relative() {
        let in_current_dir = env::current_dir()?.join(&path);
        if in_current_dir.exists() {
            return Ok(in_current_dir);
        } else {
            path = env::home_dir()
                .ok_or(Error::HomeDirNotAccessible)?
                .join(".stamps")
                .join(&path);
        }
    }
    if path.exists() {
        Ok(path)
    } else {
        Err(Error::StampNotFound)
    }
}

fn find_destination(dest_arg: &str) -> Result<PathBuf> {
    let path = Path::new(dest_arg).to_owned();
    if path.is_relative() {
        Ok(env::current_dir()?.join(&path))
    } else {
        Ok(path)
    }
}

fn main() {
    run().unwrap()
}
<commit_msg>Add some color<commit_after>#[macro_use]
extern crate clap;
extern crate colored;
#[macro_use]
extern crate nom;
#[macro_use]
extern crate quick_error;
extern crate walkdir;

mod error;
mod file;
mod parser;
mod questions;
mod template;
mod template_file;

use clap::{App, AppSettings};
use colored::*;

use std::env;
use std::path::{Path, PathBuf};

use error::{Error, Result};
use template_file::{RenderedFile, compile_templates};

fn run() -> Result<()> {
    let yaml = load_yaml!("cli.yaml");
    let matches = App::from_yaml(yaml)
        .setting(AppSettings::ArgRequiredElseHelp)
        .get_matches();

    let source_arg = matches
        .value_of("source")
        .expect("Source is a required argument");
    let dest_arg = matches.value_of("destination").unwrap_or("");

    let source = find_source(source_arg)?;
    let dest = find_destination(dest_arg)?;

    let files = file::read_all_files(&source)?;
    let (templates, vars) = compile_templates(&files);

    println!("Fill in the variable values:");
    let conf = questions::get_vars(&vars)?;

    let rendered = templates
        .iter()
        .map(|t| t.render(&conf))
        .collect::<Result<Vec<RenderedFile>>>()?;

    println!("\nFiles will be saved in {}", dest.to_str().unwrap());

    for f in rendered {
        let path = dest.join(&f.path);
        print!("Writing {}... ", &f.path.to_str().unwrap());
        file::write_file(&path, &f.body)?;
        println!("{}", "OK".green());
    }

    println!("\nDone");

    Ok(())
}

pub fn find_source(source_arg: &str) -> Result<PathBuf> {
    let mut path = Path::new(source_arg).to_owned();
    if path.is_relative() {
        let in_current_dir = env::current_dir()?.join(&path);
        if in_current_dir.exists() {
            return Ok(in_current_dir);
        } else {
            path = env::home_dir()
                .ok_or(Error::HomeDirNotAccessible)?
                .join(".stamps")
                .join(&path);
        }
    }
    if path.exists() {
        Ok(path)
    } else {
        Err(Error::StampNotFound)
    }
}

fn find_destination(dest_arg: &str) -> Result<PathBuf> {
    let path = Path::new(dest_arg).to_owned();
    if path.is_relative() {
        Ok(env::current_dir()?.join(&path))
    } else {
        Ok(path)
    }
}

fn main() {
    run().unwrap()
}
<|endoftext|>