<commit_before>extern crate rustc_serialize;
extern crate sdl2;
extern crate sdl2_image;
extern crate sdl2_ttf;
extern crate toml;

use std::collections::BTreeMap;
use std::fs::{self, File};
use std::io::Read;
use std::path::Path;
use std::process::Command;
use std::time::Duration;

use sdl2::controller::{Axis, Button};
use sdl2::event::Event;
use sdl2::keyboard::Scancode;
use sdl2::mouse::Mouse;
use sdl2::pixels::Color;
use sdl2::rect::Rect;
use sdl2::render::{Renderer, Texture};

use sdl2_image::LoadTexture;

struct Cursor {
    pub x: f32,
    pub y: f32,
    texture: Texture,
}

impl Cursor {
    pub fn new(renderer: &Renderer, image: &str) -> Cursor {
        Cursor {
            x: 0.0,
            y: 0.0,
            texture: renderer.load_texture(&Path::new(image)).unwrap(),
        }
    }

    pub fn set(&mut self, renderer: &Renderer, x: f32, y: f32) {
        self.x = x.max(0.0).min(renderer.output_size().unwrap().0 as f32);
        self.y = y.max(0.0).min(renderer.output_size().unwrap().1 as f32);
    }

    pub fn offset(&mut self, renderer: &Renderer, dx: f32, dy: f32) {
        let x = self.x + dx;
        let y = self.y + dy;
        self.set(renderer, x, y);
    }

    pub fn draw(&self, renderer: &mut Renderer) {
        renderer.copy(&self.texture, None, Rect::new((self.x - 26.0) as i32, (self.y - 4.0) as i32, 64, 64).unwrap());
    }
}

struct Font {
    font: sdl2_ttf::Font
}

impl Font {
    pub fn new(font: &str, size: i32) -> Font {
        Font {
            font: sdl2_ttf::Font::from_file(&Path::new(font), size).unwrap()
        }
    }

    pub fn render(&self, renderer: &Renderer, text: &str, color: Color) -> Texture {
        let surface = self.font.render(text, sdl2_ttf::blended(color)).unwrap();
        return renderer.create_texture_from_surface(&surface).unwrap();
    }
}

struct RomConfig {
    pub name: String,
    pub file: String,
    pub image: String,
}

struct Rom {
    name: Texture,
    image: Option<Texture>,
    config: RomConfig,
}

impl Rom {
    pub fn new(renderer: &Renderer, font: &Font, config: RomConfig) -> Rom {
        Rom {
            name: font.render(&renderer, &config.name, Color::RGBA(0, 0, 0, 255)),
            image: renderer.load_texture(&Path::new(&config.image)).ok(),
            config: config
        }
    }

    pub fn draw(&self, renderer: &mut Renderer, x: i32, y: i32, w: u32, h: u32) {
        if let Some(ref image) = self.image {
            let query = image.query();
            let aspect = query.width as f32 / query.height as f32;
    		let w2 = (aspect * h as f32).min(w as f32) as u32;
    		let h2 = (w as f32 / aspect).min(h as f32) as u32;
            let x2 = x + (w - w2) as i32/2;
            let y2 = y + (h - h2) as i32/2;
            renderer.copy(&image, None, Rect::new(x2, y2, w2, h2).unwrap());
        }

        {
            let query = self.name.query();
            let w2 = query.width;
            let h2 = query.height;
            let x2 = x + (w - w2) as i32/2;
            let y2 = y + h as i32;
            renderer.copy(&self.name, None, Rect::new(x2, y2, w2, h2).unwrap());
        }
    }
}

#[derive(RustcDecodable)]
struct EmulatorConfig {
    pub name: String,
    pub image: String,
    pub roms: String,
    pub program: String,
    pub args: Vec<String>,
}

struct Emulator {
    name: Texture,
    image: Texture,
    roms: Vec<Rom>,
    config: EmulatorConfig
}

impl Emulator {
    pub fn new(renderer: &Renderer, font: &Font, config: EmulatorConfig) -> Emulator {
        let mut roms = Vec::new();
        if let Ok(read_dir) = fs::read_dir(&config.roms) {
            for entry_result in read_dir {
                if let Ok(entry) = entry_result {
                    if let Some(path) = entry.path().to_str() {
                        roms.push(Rom::new(renderer, font, RomConfig {
                            name: path.replace(&config.roms, "").trim_matches('/').to_string(),
                            file: path.to_string() + "/rom.bin",
                            image: path.to_string() + "/image.jpg"
                        }))
                    }
                }
            }
        }

        Emulator {
            name: font.render(&renderer, &config.name, Color::RGBA(0, 0, 0, 255)),
            image: renderer.load_texture(&Path::new(&config.image)).unwrap(),
            roms: roms,
            config: config
        }
    }

    pub fn draw(&self, renderer: &mut Renderer, x: i32, y: i32, w: u32, h: u32) {
        {
            let query = self.image.query();
            let aspect = query.width as f32 / query.height as f32;
    		let w2 = (aspect * h as f32).min(w as f32) as u32;
    		let h2 = (w as f32 / aspect).min(h as f32) as u32;
            let x2 = x + (w - w2) as i32/2;
            let y2 = y + (h - h2) as i32/2;
            renderer.copy(&self.image, None, Rect::new(x2, y2, w2, h2).unwrap());
        }

        {
            let query = self.name.query();
            let w2 = query.width;
            let h2 = query.height;
            let x2 = x + (w - w2) as i32/2;
            let y2 = y + h as i32;
            renderer.copy(&self.name, None, Rect::new(x2, y2, w2, h2).unwrap());
        }
    }

    pub fn run(&self, rom: &Rom){
        let mut command = Command::new(&self.config.program);
        for arg in self.config.args.iter() {
            if arg == "%r" {
                command.arg(&rom.config.file);
            }else{
                command.arg(arg);
            }
        }

        println!("status: {}", command.status().unwrap());
    }
}

#[derive(Clone, PartialEq)]
enum View {
    //Rom(String, usize),
    Emulator(String),
    Overview
}

fn main(){
    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();
    let controller_subsystem = sdl_context.game_controller().unwrap();
    let _ttf_context = sdl2_ttf::init();

    let window = video_subsystem.window("emulition", 1024, 768)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();

    let mut controllers = Vec::new();
    for id in 0 .. controller_subsystem.num_joysticks().unwrap() {
        if controller_subsystem.is_game_controller(id) {
            controllers.push(controller_subsystem.open(id).unwrap());
        }
    }

    let mut cursor = Cursor::new(&renderer, "res/cursor.png");

    let font = Font::new("res/DroidSans.ttf", 24);

    let mut emulators = BTreeMap::new();

    if let Ok(mut file) = File::open("res/config.toml") {
        let mut toml = String::new();
        if let Ok(_) = file.read_to_string(&mut toml) {
            if let Some(parsed) = toml::Parser::new(&toml).parse() {
                for (key, value) in parsed {
                    if let Some(config) = toml::decode::<EmulatorConfig>(value) {
                        emulators.insert(key, Emulator::new(&renderer, &font, config));
                    }
                }
            }
        }
    }

    let mut event_pump = sdl_context.event_pump().unwrap();

    let mut view = View::Overview;
    'running: loop {
        let mut forward = false;
        let mut backward = false;

        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { scancode: Some(Scancode::Escape), .. } => break 'running,
                Event::KeyDown { scancode: Some(Scancode::Return), .. } => forward = true,
                Event::KeyDown { scancode: Some(Scancode::Backspace), .. } => backward = true,
                Event::ControllerButtonDown { button: Button::A, .. } => forward = true,
                Event::ControllerButtonDown { button: Button::B, .. } => backward = true,
                Event::MouseButtonDown { mouse_btn: Mouse::Left, .. } => forward = true,
                Event::MouseButtonDown { mouse_btn: Mouse::Right, .. } => backward = true,
                Event::MouseMotion { x, y, .. } => cursor.set(&renderer, x as f32, y as f32),
                _ => {}
            }
        }

        if event_pump.keyboard_state().is_scancode_pressed(Scancode::Left) {
            cursor.offset(&renderer, -8.0, 0.0);
        }
        if event_pump.keyboard_state().is_scancode_pressed(Scancode::Right) {
            cursor.offset(&renderer, 8.0, 0.0);
        }
        if event_pump.keyboard_state().is_scancode_pressed(Scancode::Up) {
            cursor.offset(&renderer, 0.0, -8.0);
        }
        if event_pump.keyboard_state().is_scancode_pressed(Scancode::Down) {
            cursor.offset(&renderer, 0.0, 8.0);
        }

        for controller in controllers.iter() {
            let dx = controller.axis(Axis::LeftX) as f32 / 32768.0;
            let dy = controller.axis(Axis::LeftY) as f32 / 32768.0;
            if (dx.powi(2) + dy.powi(2)).sqrt() > 0.2 {
                cursor.offset(&renderer, dx * 8.0, dy * 8.0);
            }

            if controller.button(Button::DPadLeft) {
                cursor.offset(&renderer, -8.0, 0.0);
            }
            if controller.button(Button::DPadRight) {
                cursor.offset(&renderer, 8.0, 0.0);
            }
            if controller.button(Button::DPadUp) {
                cursor.offset(&renderer, 0.0, -8.0);
            }
            if controller.button(Button::DPadDown) {
                cursor.offset(&renderer, 0.0, 8.0);
            }
        }

        renderer.set_draw_color(Color::RGB(255, 255, 255));
        renderer.clear();

        let mut x = 0;
        let mut y = 0;
        let s = renderer.output_size().unwrap().0 / 4;

        let mut new_view = view.clone();
        match view {
            View::Emulator(ref key) => {
                if let Some(emulator) = emulators.get_mut(key) {
                    emulator.draw(&mut renderer, x + 8, y + 8, s - 16, s - 64);

                    x += s as i32;
                    if x + s as i32 > renderer.output_size().unwrap().0 as i32 {
                        x = 0;
                        y += s as i32;
                    }

                    for rom in emulator.roms.iter() {
                        if cursor.x >= x as f32 && cursor.x < (x + s as i32) as f32 && cursor.y >= y as f32 && cursor.y < (y + s as i32) as f32 {
                            renderer.set_draw_color(Color::RGBA(192, 192, 192, 255));
                            renderer.fill_rect(Rect::new(x, y, s, s).unwrap().unwrap());

                            if forward {
                                emulator.run(rom);
                            }
                        }

                        rom.draw(&mut renderer, x + 8, y + 8, s - 16, s - 64);

                        x += s as i32;
                        if x + s as i32 > renderer.output_size().unwrap().0 as i32 {
                            x = 0;
                            y += s as i32;
                        }
                    }

                    if backward {
                        new_view = View::Overview
                    }
                } else {
                    new_view = View::Overview
                }
            },
            View::Overview => {
                for (key, emulator) in emulators.iter() {
                    if cursor.x >= x as f32 && cursor.x < (x + s as i32) as f32 && cursor.y >= y as f32 && cursor.y < (y + s as i32) as f32 {
                        renderer.set_draw_color(Color::RGBA(192, 192, 192, 255));
                        renderer.fill_rect(Rect::new(x, y, s, s).unwrap().unwrap());

                        if forward {
                            new_view = View::Emulator(key.clone());
                        }
                    }

                    emulator.draw(&mut renderer, x + 8, y + 8, s - 16, s - 64);

                    x += s as i32;
                    if x + s as i32 > renderer.output_size().unwrap().0 as i32 {
                        x = 0;
                        y += s as i32;
                    }
                }
            }
        };

        cursor.draw(&mut renderer);

        renderer.present();

        if new_view != view {
            view = new_view;
        } else {
            std::thread::sleep(Duration::from_millis(1000/60));
        }
    }
}
<commit_msg>Rom screen<commit_after>extern crate rustc_serialize;
extern crate sdl2;
extern crate sdl2_image;
extern crate sdl2_ttf;
extern crate toml;

use std::collections::BTreeMap;
use std::fs::{self, File};
use std::io::Read;
use std::path::Path;
use std::process::Command;
use std::time::Duration;

use sdl2::controller::{Axis, Button};
use sdl2::event::Event;
use sdl2::keyboard::Scancode;
use sdl2::mouse::Mouse;
use sdl2::pixels::Color;
use sdl2::rect::Rect;
use sdl2::render::{Renderer, Texture};

use sdl2_image::LoadTexture;

struct Cursor {
    pub x: f32,
    pub y: f32,
    texture: Texture,
}

impl Cursor {
    pub fn new(renderer: &Renderer, image: &str) -> Cursor {
        Cursor {
            x: 0.0,
            y: 0.0,
            texture: renderer.load_texture(&Path::new(image)).unwrap(),
        }
    }

    pub fn set(&mut self, renderer: &Renderer, x: f32, y: f32) {
        self.x = x.max(0.0).min(renderer.output_size().unwrap().0 as f32);
        self.y = y.max(0.0).min(renderer.output_size().unwrap().1 as f32);
    }

    pub fn offset(&mut self, renderer: &Renderer, dx: f32, dy: f32) {
        let x = self.x + dx;
        let y = self.y + dy;
        self.set(renderer, x, y);
    }

    pub fn draw(&self, renderer: &mut Renderer) {
        renderer.copy(&self.texture, None, Rect::new((self.x - 26.0) as i32, (self.y - 4.0) as i32, 64, 64).unwrap());
    }
}

struct Font {
    font: sdl2_ttf::Font
}

impl Font {
    pub fn new(font: &str, size: i32) -> Font {
        Font {
            font: sdl2_ttf::Font::from_file(&Path::new(font), size).unwrap()
        }
    }

    pub fn render(&self, renderer: &Renderer, text: &str, color: Color) -> Texture {
        let surface = self.font.render(text, sdl2_ttf::blended(color)).unwrap();
        return renderer.create_texture_from_surface(&surface).unwrap();
    }
}

struct RomConfig {
    pub name: String,
    pub file: String,
    pub image: String,
}

struct Rom {
    name: Texture,
    image: Option<Texture>,
    config: RomConfig,
}

impl Rom {
    pub fn new(renderer: &Renderer, font: &Font, config: RomConfig) -> Rom {
        Rom {
            name: font.render(&renderer, &config.name, Color::RGBA(0, 0, 0, 255)),
            image: renderer.load_texture(&Path::new(&config.image)).ok(),
            config: config
        }
    }

    pub fn draw(&self, renderer: &mut Renderer, x: i32, y: i32, w: u32, h: u32) {
        if let Some(ref image) = self.image {
            let query = image.query();
            let aspect = query.width as f32 / query.height as f32;
    		let w2 = (aspect * h as f32).min(w as f32) as u32;
    		let h2 = (w as f32 / aspect).min(h as f32) as u32;
            let x2 = x + (w - w2) as i32/2;
            let y2 = y + (h - h2) as i32/2;
            renderer.copy(&image, None, Rect::new(x2, y2, w2, h2).unwrap());
        }

        {
            let query = self.name.query();
            let w2 = query.width;
            let h2 = query.height;
            let x2 = x + (w - w2) as i32/2;
            let y2 = y + h as i32;
            renderer.copy(&self.name, None, Rect::new(x2, y2, w2, h2).unwrap());
        }
    }
}

#[derive(RustcDecodable)]
struct EmulatorConfig {
    pub name: String,
    pub image: String,
    pub roms: String,
    pub program: String,
    pub args: Vec<String>,
}

struct Emulator {
    name: Texture,
    image: Texture,
    roms: Vec<Rom>,
    config: EmulatorConfig
}

impl Emulator {
    pub fn new(renderer: &Renderer, font: &Font, config: EmulatorConfig) -> Emulator {
        let mut roms = Vec::new();
        if let Ok(read_dir) = fs::read_dir(&config.roms) {
            for entry_result in read_dir {
                if let Ok(entry) = entry_result {
                    if let Some(path) = entry.path().to_str() {
                        roms.push(Rom::new(renderer, font, RomConfig {
                            name: path.replace(&config.roms, "").trim_matches('/').to_string(),
                            file: path.to_string() + "/rom.bin",
                            image: path.to_string() + "/image.jpg"
                        }))
                    }
                }
            }
        }

        roms.sort_by(|a, b| a.config.name.cmp(&b.config.name));

        Emulator {
            name: font.render(&renderer, &config.name, Color::RGBA(0, 0, 0, 255)),
            image: renderer.load_texture(&Path::new(&config.image)).unwrap(),
            roms: roms,
            config: config
        }
    }

    pub fn draw(&self, renderer: &mut Renderer, x: i32, y: i32, w: u32, h: u32) {
        {
            let query = self.image.query();
            let aspect = query.width as f32 / query.height as f32;
    		let w2 = (aspect * h as f32).min(w as f32) as u32;
    		let h2 = (w as f32 / aspect).min(h as f32) as u32;
            let x2 = x + (w - w2) as i32/2;
            let y2 = y + (h - h2) as i32/2;
            renderer.copy(&self.image, None, Rect::new(x2, y2, w2, h2).unwrap());
        }

        {
            let query = self.name.query();
            let w2 = query.width;
            let h2 = query.height;
            let x2 = x + (w - w2) as i32/2;
            let y2 = y + h as i32;
            renderer.copy(&self.name, None, Rect::new(x2, y2, w2, h2).unwrap());
        }
    }

    pub fn run(&self, rom: &Rom){
        let mut command = Command::new(&self.config.program);
        for arg in self.config.args.iter() {
            if arg == "%r" {
                command.arg(&rom.config.file);
            }else{
                command.arg(arg);
            }
        }

        println!("status: {}", command.status().unwrap());
    }
}

#[derive(Clone, PartialEq)]
enum View {
    Rom(String, usize),
    Emulator(String),
    Overview
}

fn main(){
    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();
    let controller_subsystem = sdl_context.game_controller().unwrap();
    let _ttf_context = sdl2_ttf::init();

    let window = video_subsystem.window("emulition", 1024, 768)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();

    let mut controllers = Vec::new();
    for id in 0 .. controller_subsystem.num_joysticks().unwrap() {
        if controller_subsystem.is_game_controller(id) {
            controllers.push(controller_subsystem.open(id).unwrap());
        }
    }

    let mut cursor = Cursor::new(&renderer, "res/cursor.png");

    let font = Font::new("res/DroidSans.ttf", 24);

    let mut emulators = BTreeMap::new();

    if let Ok(mut file) = File::open("res/config.toml") {
        let mut toml = String::new();
        if let Ok(_) = file.read_to_string(&mut toml) {
            if let Some(parsed) = toml::Parser::new(&toml).parse() {
                for (key, value) in parsed {
                    if let Some(config) = toml::decode::<EmulatorConfig>(value) {
                        emulators.insert(key, Emulator::new(&renderer, &font, config));
                    }
                }
            }
        }
    }

    let mut event_pump = sdl_context.event_pump().unwrap();

    let mut view = View::Overview;
    'running: loop {
        let mut forward = false;
        let mut backward = false;

        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { scancode: Some(Scancode::Escape), .. } => break 'running,
                Event::KeyDown { scancode: Some(Scancode::Return), .. } => forward = true,
                Event::KeyDown { scancode: Some(Scancode::Backspace), .. } => backward = true,
                Event::ControllerButtonDown { button: Button::A, .. } => forward = true,
                Event::ControllerButtonDown { button: Button::B, .. } => backward = true,
                Event::MouseButtonDown { mouse_btn: Mouse::Left, .. } => forward = true,
                Event::MouseButtonDown { mouse_btn: Mouse::Right, .. } => backward = true,
                Event::MouseMotion { x, y, .. } => cursor.set(&renderer, x as f32, y as f32),
                _ => {}
            }
        }

        if event_pump.keyboard_state().is_scancode_pressed(Scancode::Left) {
            cursor.offset(&renderer, -8.0, 0.0);
        }
        if event_pump.keyboard_state().is_scancode_pressed(Scancode::Right) {
            cursor.offset(&renderer, 8.0, 0.0);
        }
        if event_pump.keyboard_state().is_scancode_pressed(Scancode::Up) {
            cursor.offset(&renderer, 0.0, -8.0);
        }
        if event_pump.keyboard_state().is_scancode_pressed(Scancode::Down) {
            cursor.offset(&renderer, 0.0, 8.0);
        }

        for controller in controllers.iter() {
            let dx = controller.axis(Axis::LeftX) as f32 / 32768.0;
            let dy = controller.axis(Axis::LeftY) as f32 / 32768.0;
            if (dx.powi(2) + dy.powi(2)).sqrt() > 0.2 {
                cursor.offset(&renderer, dx * 8.0, dy * 8.0);
            }

            if controller.button(Button::DPadLeft) {
                cursor.offset(&renderer, -8.0, 0.0);
            }
            if controller.button(Button::DPadRight) {
                cursor.offset(&renderer, 8.0, 0.0);
            }
            if controller.button(Button::DPadUp) {
                cursor.offset(&renderer, 0.0, -8.0);
            }
            if controller.button(Button::DPadDown) {
                cursor.offset(&renderer, 0.0, 8.0);
            }
        }

        renderer.set_draw_color(Color::RGB(255, 255, 255));
        renderer.clear();

        renderer.set_draw_color(Color::RGB(192, 192, 192));

        let mut x = 0;
        let mut y = 0;
        let mut s = renderer.output_size().unwrap().0 / 4;

        let mut new_view = view.clone();
        match view {
            View::Rom(ref key, index) => {
                if let Some(emulator) = emulators.get(key) {
                    emulator.draw(&mut renderer, x + 8, y + 8, s - 16, s - 64);

                    x = s as i32;
                    y = 0;
                    s = s * 3;
                    if let Some(rom) = emulator.roms.get(index) {
                        if cursor.x >= x as f32 && cursor.x < (x + s as i32) as f32 && cursor.y >= y as f32 && cursor.y < (y + s as i32) as f32 {
                            renderer.fill_rect(Rect::new(x, y, s, s).unwrap().unwrap());

                            if forward {
                                emulator.run(rom);
                            }
                        }

                        rom.draw(&mut renderer, x + 8, y + 8, s - 16, s - 64);

                        x = s as i32;
                        y = 0;

                        if backward {
                            new_view = View::Emulator(key.clone());
                        }
                    } else {
                        new_view = View::Emulator(key.clone());
                    }
                } else {
                    new_view = View::Overview
                }
            },
            View::Emulator(ref key) => {
                if let Some(emulator) = emulators.get(key) {
                    emulator.draw(&mut renderer, x + 8, y + 8, s - 16, s - 64);

                    x = s as i32;
                    y = 0;
                    for index in 0 .. emulator.roms.len() {
                        if let Some(rom) = emulator.roms.get(index) {
                            if cursor.x >= x as f32 && cursor.x < (x + s as i32) as f32 && cursor.y >= y as f32 && cursor.y < (y + s as i32) as f32 {
                                renderer.fill_rect(Rect::new(x, y, s, s).unwrap().unwrap());

                                if forward {
                                    new_view = View::Rom(key.clone(), index);
                                    //emulator.run(rom);
                                }
                            }

                            rom.draw(&mut renderer, x + 8, y + 8, s - 16, s - 64);

                            x += s as i32;
                            if x + s as i32 > renderer.output_size().unwrap().0 as i32 {
                                x = s as i32;
                                y += s as i32;
                            }
                        }
                    }

                    if backward {
                        new_view = View::Overview
                    }
                } else {
                    new_view = View::Overview
                }
            },
            View::Overview => {
                for (key, emulator) in emulators.iter() {
                    if cursor.x >= x as f32 && cursor.x < (x + s as i32) as f32 && cursor.y >= y as f32 && cursor.y < (y + s as i32) as f32 {
                        renderer.fill_rect(Rect::new(x, y, s, s).unwrap().unwrap());

                        if forward {
                            new_view = View::Emulator(key.clone());
                        }
                    }

                    emulator.draw(&mut renderer, x + 8, y + 8, s - 16, s - 64);

                    x += s as i32;
                    if x + s as i32 > renderer.output_size().unwrap().0 as i32 {
                        x = 0;
                        y += s as i32;
                    }
                }
            }
        };

        cursor.draw(&mut renderer);

        renderer.present();

        if new_view != view {
            view = new_view;
        } else {
            std::thread::sleep(Duration::from_millis(1000/60));
        }
    }
}
<|endoftext|>


<commit_before>extern crate crypto;
extern crate mio;
extern crate num;
extern crate protobuf;
extern crate rustc_serialize;
extern crate time;

use address::Address;
use node::UdpNode;
use std::env;

mod address;
mod messages;
mod network;
mod node;
mod node_bucket;
mod routing_table;
mod transaction;

fn main() {
    let args: Vec<String> = env::args().collect();
    let secret = args[1].clone();
    let address = Address::for_content(secret.as_str());
    let port = args[2].clone().parse::<u16>().unwrap();
    let self_node = node::UdpNode::new(address, ("127.0.0.1", port));

    let bootstrap_address = ("127.0.0.1", args[3].clone().parse::<u16>().unwrap());
    let bootstrap_node = Box::new(UdpNode::new(Address::null(), bootstrap_address));

    let handler = network::Handler::new(self_node, port, vec![bootstrap_node]);
    handler.run();
}
<commit_msg>Make bootstrap port optional<commit_after>extern crate crypto;
extern crate mio;
extern crate num;
extern crate protobuf;
extern crate rustc_serialize;
extern crate time;

use address::Address;
use node::UdpNode;
use std::env;

mod address;
mod messages;
mod network;
mod node;
mod node_bucket;
mod routing_table;
mod transaction;

fn main() {
    let args: Vec<String> = env::args().collect();
    let secret = args[1].clone();
    let address = Address::for_content(secret.as_str());
    let port = args[2].clone().parse::<u16>().unwrap();
    let self_node = node::UdpNode::new(address, ("127.0.0.1", port));

    let routers: Vec<Box<node::Node>> = match args.get(3) {
        Some(bootstrap_port) => {
            let bootstrap_address = ("127.0.0.1", bootstrap_port.clone().parse::<u16>().unwrap());
            let bootstrap_node = Box::new(UdpNode::new(Address::null(), bootstrap_address));
            vec![bootstrap_node]
        }
        None => vec![]
    };

    let handler = network::Handler::new(self_node, port, routers);
    handler.run();
}
<|endoftext|>


<commit_before>fn insertion_sort(array_A: &mut [int, ..6]) {
	// Implementation of the traditional insertion sort algorithm in Rust
	// The idea is to both learn the language and re visit classic (and not so much)
	// algorithms.
	// This algorithm source has been extracted from "Introduction to Algorithms" - Cormen
	let mut i: int;

	//utility variable. Uggly hack to avoid casting back and foward from int to uint
	let mut i_u: uint;
	let mut key: int;

	// It is not necessary to explicitly declare j
	for j in range(1u, array_A.len()) { //arrays only work with uint (unsigned)
		key = array_A[j];
		i_u = j - 1;
		i = i_u as int;

		while i >= 0 && array_A[i_u] > key {
			array_A[i_u + 1] = array_A[i_u];

			i = i - 1;
			i_u = i as uint;
		};
		array_A[i_u + 1]  = key;

	};

}

fn main() {
	//This should be replaced eventually by the unit test framework.

	let mut array_A = [31i, 41, 59, 26, 41, 58];
	// let mut array_A = [5i,2,4,6,1,3];

	// Need to pass a reference, so the sorting function can modify the
	// array being sorted (this is very similar to C lang).
	insertion_sort(&mut array_A);

	//Just for printing purposes
	for j in range(0u, array_A.len()) {
		println!("{}", array_A[j]);
	};

}<commit_msg>fix some typos<commit_after>fn insertion_sort(array_A: &mut [int, ..6]) {
	// Implementation of the traditional insertion sort algorithm in Rust
	// The idea is to both learn the language and re visit classic (and not so much)
	// algorithms.
	// This algorithm source has been extracted from "Introduction to Algorithms" - Cormen
	let mut i: int;

	//utility variable. Ugly hack to avoid casting back and forward from int to uint
	let mut i_u: uint;
	let mut key: int;

	// It is not necessary to explicitly declare j
	for j in range(1u, array_A.len()) { //arrays only work with uint (unsigned)
		key = array_A[j];
		i_u = j - 1;
		i = i_u as int;

		while i >= 0 && array_A[i_u] > key {
			array_A[i_u + 1] = array_A[i_u];

			i = i - 1;
			i_u = i as uint;
		};
		array_A[i_u + 1]  = key;

	};

}

fn main() {
	//This should be replaced eventually by the unit test framework.

	let mut array_A = [31i, 41, 59, 26, 41, 58];
	// let mut array_A = [5i,2,4,6,1,3];

	// Need to pass a reference, so the sorting function can modify the
	// array being sorted (this is very similar to C lang).
	insertion_sort(&mut array_A);

	//Just for printing purposes
	for j in range(0u, array_A.len()) {
		println!("{}", array_A[j]);
	};

}<|endoftext|>


<commit_before>#![cfg_attr(test, feature(test))]
#[cfg(test)]
extern crate test;

extern crate rand;
extern crate getopts;

use std::io::{self, Read};
use std::fs::File;
use getopts::Options;

const DEFAULT_DICT_FILE: &'static str = "/usr/share/dict/words";

struct Config {
    min: usize,
    max: usize,
    number: usize,
    count: usize,
    filename: String,
    downcase: bool,
}

impl Config {
    fn new() -> Config {
        Config {
            min: 4,
            max: 6,
            number: 4,
            count: 1,
            filename: DEFAULT_DICT_FILE.to_string(),
            downcase: true,
        }
    }
}

fn read_wordlist(cfg: &Config) -> io::Result<String> {
    let mut dict = File::open(&cfg.filename).unwrap();
    let mut buf = String::new();
    try!(dict.read_to_string(&mut buf));
    Ok(buf)
}

fn split_wordlist<'a>(buf: &'a String, cfg: &Config) -> Vec<&'a str> {
    buf.lines()
       .filter(|x| x.len() >= cfg.min && x.len() <= cfg.max)
       .collect()
}

fn select_words<'a>(words: &'a Vec<&'a str>, cfg: &Config) -> Vec<&'a &'a str> {
    let mut rng = rand::thread_rng();
    rand::sample(&mut rng, words.iter(), cfg.number)
}

fn usage(opts: &Options, err: Option<String>) {
    if let Some(e) = err {
        println!("{}\n", e);
    }
    let brief = "Usage: pwrs [options]";
    println!("{}", opts.usage(&brief));
}

fn config() -> Option<Config> {
    let mut cfg = Config::new();
    let args: Vec<_> = std::env::args().collect();
    let mut opts = Options::new();
    opts.optflag("h", "help", "Print this help");
    opts.optopt("m", "min", "Minimum number of characters in words", "MIN");
    opts.optopt("M", "max", "Maximum number of characters in words", "MAX");
    opts.optopt("c", "count", "Count of passphrases to print", "COUNT");
    opts.optopt("n", "number", "Number of words to include in passphrases", "NUMBER");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            usage(&opts, Some(f.to_string()));
            // This is only in nightlies and for once I'm writing a thing that works on stable rust
            // ::std::env::set_exit_status(1);
            return None;
        }
    };

    if matches.opt_present("help") {
        usage(&opts, None);
        return None;
    }

    macro_rules! unpack_opt(
        ($name:ident) => {
            if let Some(s) = matches.opt_str(stringify!($name)) {
                match s.parse() {
                    Ok(i) => cfg.$name = i,
                    Err(e) => {
                        usage(&opts, Some(e.to_string()));
                        return None;
                    }
                }
            }
        }
    );

    unpack_opt!(min);
    unpack_opt!(max);
    unpack_opt!(count);
    unpack_opt!(number);

    Some(cfg)
}

fn main() {
    let cfg = match config() {
        Some(c) => c,
        None => return,
    };
    let wordlist = read_wordlist(&cfg).unwrap();
    let words = split_wordlist(&wordlist, &cfg);

    for _ in (0..cfg.count) {
        let selected = select_words(&words, &cfg);

        let inter: Vec<&str> = selected.iter()
                                       .map(|x| **x)
                                       .collect();
        let out = inter.connect(" ");
        if cfg.downcase {
            println!("{}",  out.to_lowercase());
        } else {
            println!("{}", out);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use test::Bencher;

    #[bench]
    fn with_defaults(b: &mut Bencher) {
        let cfg = ::Config::new();
        let buf = ::read_wordlist(&cfg).unwrap();
        let words = ::split_wordlist(&buf, &cfg);
        b.iter(|| {
            let _ = ::select_words(&words, &cfg);
        })
    }
}
<commit_msg>Clean up warnings in test<commit_after>#![cfg_attr(test, feature(test))]
#![cfg_attr(test, allow(dead_code))]
#[cfg(test)]
extern crate test;

extern crate rand;
extern crate getopts;

use std::io::{self, Read};
use std::fs::File;
use getopts::Options;

const DEFAULT_DICT_FILE: &'static str = "/usr/share/dict/words";

struct Config {
    min: usize,
    max: usize,
    number: usize,
    count: usize,
    filename: String,
    downcase: bool,
}

impl Config {
    fn new() -> Config {
        Config {
            min: 4,
            max: 6,
            number: 4,
            count: 1,
            filename: DEFAULT_DICT_FILE.to_string(),
            downcase: true,
        }
    }
}

fn read_wordlist(cfg: &Config) -> io::Result<String> {
    let mut dict = File::open(&cfg.filename).unwrap();
    let mut buf = String::new();
    try!(dict.read_to_string(&mut buf));
    Ok(buf)
}

fn split_wordlist<'a>(buf: &'a String, cfg: &Config) -> Vec<&'a str> {
    buf.lines()
       .filter(|x| x.len() >= cfg.min && x.len() <= cfg.max)
       .collect()
}

fn select_words<'a>(words: &'a Vec<&'a str>, cfg: &Config) -> Vec<&'a &'a str> {
    let mut rng = rand::thread_rng();
    rand::sample(&mut rng, words.iter(), cfg.number)
}

fn usage(opts: &Options, err: Option<String>) {
    if let Some(e) = err {
        println!("{}\n", e);
    }
    let brief = "Usage: pwrs [options]";
    println!("{}", opts.usage(&brief));
}

fn config() -> Option<Config> {
    let mut cfg = Config::new();
    let args: Vec<_> = std::env::args().collect();
    let mut opts = Options::new();
    opts.optflag("h", "help", "Print this help");
    opts.optopt("m", "min", "Minimum number of characters in words", "MIN");
    opts.optopt("M", "max", "Maximum number of characters in words", "MAX");
    opts.optopt("c", "count", "Count of passphrases to print", "COUNT");
    opts.optopt("n", "number", "Number of words to include in passphrases", "NUMBER");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            usage(&opts, Some(f.to_string()));
            // This is only in nightlies and for once I'm writing a thing that works on stable rust
            // ::std::env::set_exit_status(1);
            return None;
        }
    };

    if matches.opt_present("help") {
        usage(&opts, None);
        return None;
    }

    macro_rules! unpack_opt(
        ($name:ident) => {
            if let Some(s) = matches.opt_str(stringify!($name)) {
                match s.parse() {
                    Ok(i) => cfg.$name = i,
                    Err(e) => {
                        usage(&opts, Some(e.to_string()));
                        return None;
                    }
                }
            }
        }
    );

    unpack_opt!(min);
    unpack_opt!(max);
    unpack_opt!(count);
    unpack_opt!(number);

    Some(cfg)
}

fn main() {
    let cfg = match config() {
        Some(c) => c,
        None => return,
    };
    let wordlist = read_wordlist(&cfg).unwrap();
    let words = split_wordlist(&wordlist, &cfg);

    for _ in (0..cfg.count) {
        let selected = select_words(&words, &cfg);

        let inter: Vec<&str> = selected.iter()
                                       .map(|x| **x)
                                       .collect();
        let out = inter.connect(" ");
        if cfg.downcase {
            println!("{}",  out.to_lowercase());
        } else {
            println!("{}", out);
        }
    }
}

#[cfg(test)]
mod tests {
    use test::Bencher;

    #[bench]
    fn with_defaults(b: &mut Bencher) {
        let cfg = ::Config::new();
        let buf = ::read_wordlist(&cfg).unwrap();
        let words = ::split_wordlist(&buf, &cfg);
        b.iter(|| {
            let _ = ::select_words(&words, &cfg);
        })
    }
}
<|endoftext|>


<commit_before>#![feature(plugin, collections, into_cow, debug_builders)]
#![plugin(regex_macros, docopt_macros)]

extern crate regex;
extern crate rustc_serialize;
extern crate docopt;

pub mod interpreter;

use interpreter::synth::Synth;

docopt!(Args, "
Usage:
  synthizer [--tokens] [--idmap] <file>
  synthizer --help

Options:
  -h, --help       Show this message.
  -t, --tokens     Show tokens
  -i, --idmap      Show identifier map
");

fn main() {
    let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());
    let filename = args.arg_file;

    let mut synth = Synth::new(&filename).unwrap();
    if synth.compile() {
        println!("OK!");
    }
}
<commit_msg>remove old command line options<commit_after>#![feature(plugin, collections, into_cow, debug_builders)]
#![plugin(regex_macros, docopt_macros)]

extern crate regex;
extern crate rustc_serialize;
extern crate docopt;

pub mod interpreter;

use interpreter::synth::Synth;

docopt!(Args, "
Usage:
  synthizer [--tokens] [--idmap] <file>
  synthizer --help

Options:
  -h, --help       Show this message.
");

fn main() {
    let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());
    let filename = args.arg_file;

    let mut synth = Synth::new(&filename).unwrap();
    if synth.compile() {
        println!("OK!");
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! Alacritty - The GPU Enhanced Terminal
#![feature(question_mark)]
#![feature(range_contains)]
#![feature(inclusive_range_syntax)]
#![feature(drop_types_in_const)]
#![feature(unicode)]
#![feature(zero_one)]
#![feature(step_trait)]
#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]

extern crate cgmath;
extern crate errno;
extern crate font;
extern crate glutin;
extern crate libc;
extern crate notify;
extern crate parking_lot;
extern crate serde;
extern crate serde_yaml;

#[macro_use]
extern crate bitflags;

#[macro_use]
mod macros;

mod renderer;
pub mod grid;
mod meter;
pub mod config;
mod input;
mod index;
mod tty;
pub mod ansi;
mod term;
mod util;
mod io;
mod sync;

use std::io::{Write, BufWriter, Read};
use std::sync::{mpsc, Arc};

use sync::PriorityMutex;

use config::Config;
use font::FontDesc;
use meter::Meter;
use renderer::{QuadRenderer, GlyphCache};
use term::Term;
use tty::process_should_exit;
use util::thread;

use io::{Utf8Chars, Utf8CharsError};

/// Channel used by resize handling on mac
static mut resize_sender: Option<mpsc::Sender<(u32, u32)>> = None;

/// Resize handling for Mac
fn window_resize_handler(width: u32, height: u32) {
    unsafe {
        if let Some(ref tx) = resize_sender {
            let _ = tx.send((width, height));
        }
    }
}

#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
pub struct Rgb {
    r: u8,
    g: u8,
    b: u8,
}

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

fn main() {
    // Load configuration
    let config = match Config::load() {
        Err(err) => match err {
            // Use default config when not found
            config::Error::NotFound => Config::default(),
            // Exit when there's a problem with it
            _ => die!("{}", err),
        },
        Ok(config) => config,
    };

    let font = config.font();
    let dpi = config.dpi();
    let render_timer = config.render_timer();

    let mut window = glutin::WindowBuilder::new()
                                           .with_vsync()
                                           .with_title("Alacritty")
                                           .build().unwrap();
    window.set_window_resize_callback(Some(window_resize_handler as fn(u32, u32)));

    gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
    let (width, height) = window.get_inner_size_pixels().unwrap();
    let dpr = window.hidpi_factor();

    println!("device_pixel_ratio: {}", dpr);

    let _ = unsafe { window.make_current() };
    unsafe {
        gl::Viewport(0, 0, width as i32, height as i32);
        gl::Enable(gl::BLEND);
        gl::BlendFunc(gl::SRC1_COLOR, gl::ONE_MINUS_SRC1_COLOR);
        gl::Enable(gl::MULTISAMPLE);
    }

    let desc = FontDesc::new(font.family(), font.style());
    let mut rasterizer = font::Rasterizer::new(dpi.x(), dpi.y(), dpr);

    let metrics = rasterizer.metrics(&desc, font.size());
    let cell_width = (metrics.average_advance + font.offset().x() as f64) as u32;
    let cell_height = (metrics.line_height + font.offset().y() as f64) as u32;

    println!("Cell Size: ({} x {})", cell_width, cell_height);

    let terminal = Term::new(width as f32, height as f32, cell_width as f32, cell_height as f32);

    let mut reader = terminal.tty().reader();
    let writer = terminal.tty().writer();

    let mut glyph_cache = GlyphCache::new(rasterizer, desc, font.size());

    let (tx, rx) = mpsc::channel();
    unsafe {
        resize_sender = Some(tx.clone());
    }

    let terminal = Arc::new(PriorityMutex::new(terminal));
    let term_ref = terminal.clone();
    let term_updater = terminal.clone();

    // Rendering thread
    //
    // Holds lock only when updating terminal
    let reader_thread = thread::spawn_named("TTY Reader", move || {
        let mut buf = [0u8; 4096];
        let mut start = 0;
        let mut pty_parser = ansi::Parser::new();

        'reader: loop {
            let got = reader.read(&mut buf[start..]).expect("pty fd active");
            let mut remain = 0;

            // if `start` is nonzero, then actual bytes in buffer is > `got` by `start` bytes.
            let end = start + got;
            let mut terminal = term_updater.lock_low();
            for c in Utf8Chars::new(&buf[..end]) {
                match c {
                    Ok(c) => pty_parser.advance(&mut *terminal, c),
                    Err(err) => match err {
                        Utf8CharsError::IncompleteUtf8(unused) => {
                            remain = unused;
                            break;
                        },
                        _ => panic!("{}", err),
                    }
                }
            }

            // Move any leftover bytes to front of buffer
            for i in 0..remain {
                buf[i] = buf[end - (remain - i)];
            }
            start = remain;
        }
    });

    let mut meter = Meter::new();

    let window = Arc::new(window);
    let window_ref = window.clone();

    // Create renderer
    let mut renderer = QuadRenderer::new(width, height);

    // Initialize glyph cache
    {
        let init_start = ::std::time::Instant::now();
        println!("Initializing glyph cache");
        let terminal = term_ref.lock_high();
        renderer.with_api(terminal.size_info(), |mut api| {
            glyph_cache.init(&mut api);
        });

        let stop = init_start.elapsed();
        let stop_f = stop.as_secs() as f64 + stop.subsec_nanos() as f64 / 1_000_000_000f64;
        println!("Finished initializing glyph cache in {}", stop_f);
    }

    let mut input_processor = input::Processor::new();

    'main_loop: loop {

        // Scope ensures terminal lock isn't held when calling swap_buffers
        {
            // Acquire term lock
            let mut terminal = term_ref.lock_high();

            // Resize events new_size and are handled outside the poll_events
            // iterator. This has the effect of coalescing multiple resize
            // events into one.
            let mut new_size = None;

            // Process input events
            {
                let mut writer = BufWriter::new(&writer);
                for event in window_ref.poll_events() {
                    match event {
                        glutin::Event::Closed => break 'main_loop,
                        glutin::Event::ReceivedCharacter(c) => {
                            match c {
                                // Ignore BACKSPACE and DEL. These are handled specially.
                                '\u{8}' | '\u{7f}' => (),
                                _ => {
                                    let encoded = c.encode_utf8();
                                    writer.write(encoded.as_slice()).unwrap();
                                }
                            }
                        },
                        glutin::Event::Resized(w, h) => {
                            terminal.resize(w as f32, h as f32);
                            new_size = Some((w, h));
                        },
                        glutin::Event::KeyboardInput(state, _code, key) => {
                            input_processor.process(state,
                                                    key,
                                                    &mut input::WriteNotifier(&mut writer),
                                                    *terminal.mode())
                        },
                        _ => (),
                    }
                }
            }

            unsafe {
                gl::ClearColor(0.0, 0.0, 0.00, 1.0);
                gl::Clear(gl::COLOR_BUFFER_BIT);
            }

            // Check for any out-of-band resize events (mac only)
            while let Ok(sz) = rx.try_recv() {
                new_size = Some(sz);
            }

            // Receive any resize events; only call gl::Viewport on last
            // available
            if let Some((w, h)) = new_size.take() {
                renderer.resize(w as i32, h as i32);
            }

            {
                // Draw grid + cursor
                {
                    let _sampler = meter.sampler();

                    renderer.with_api(terminal.size_info(), |mut api| {
                        // Draw the grid
                        api.render_grid(terminal.grid(), &mut glyph_cache);

                        // Also draw the cursor
                        if terminal.mode().contains(term::mode::SHOW_CURSOR) {
                            api.render_cursor(terminal.cursor(), &mut glyph_cache);
                        }
                    })
                }

                // Draw render timer
                if render_timer {
                    let timing = format!("{:.3} usec", meter.average());
                    let color = Rgb { r: 0xd5, g: 0x4e, b: 0x53 };
                    renderer.with_api(terminal.size_info(), |mut api| {
                        api.render_string(&timing[..], &mut glyph_cache, &color);
                    });
                }
            }
        }

        window.swap_buffers().unwrap();

        if process_should_exit() {
            break;
        }
    }

    reader_thread.join().ok();
    println!("Goodbye");
}

<commit_msg>Fix resizing on macOS<commit_after>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! Alacritty - The GPU Enhanced Terminal
#![feature(question_mark)]
#![feature(range_contains)]
#![feature(inclusive_range_syntax)]
#![feature(drop_types_in_const)]
#![feature(unicode)]
#![feature(zero_one)]
#![feature(step_trait)]
#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]

extern crate cgmath;
extern crate errno;
extern crate font;
extern crate glutin;
extern crate libc;
extern crate notify;
extern crate parking_lot;
extern crate serde;
extern crate serde_yaml;

#[macro_use]
extern crate bitflags;

#[macro_use]
mod macros;

mod renderer;
pub mod grid;
mod meter;
pub mod config;
mod input;
mod index;
mod tty;
pub mod ansi;
mod term;
mod util;
mod io;
mod sync;

use std::io::{Write, BufWriter, Read};
use std::sync::{mpsc, Arc};

use sync::PriorityMutex;

use config::Config;
use font::FontDesc;
use meter::Meter;
use renderer::{QuadRenderer, GlyphCache};
use term::Term;
use tty::process_should_exit;
use util::thread;

use io::{Utf8Chars, Utf8CharsError};

/// Channel used by resize handling on mac
static mut resize_sender: Option<mpsc::Sender<(u32, u32)>> = None;

/// Resize handling for Mac
fn window_resize_handler(width: u32, height: u32) {
    unsafe {
        if let Some(ref tx) = resize_sender {
            let _ = tx.send((width, height));
        }
    }
}

#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
pub struct Rgb {
    r: u8,
    g: u8,
    b: u8,
}

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

fn main() {
    // Load configuration
    let config = match Config::load() {
        Err(err) => match err {
            // Use default config when not found
            config::Error::NotFound => Config::default(),
            // Exit when there's a problem with it
            _ => die!("{}", err),
        },
        Ok(config) => config,
    };

    let font = config.font();
    let dpi = config.dpi();
    let render_timer = config.render_timer();

    let mut window = glutin::WindowBuilder::new()
                                           .with_vsync()
                                           .with_title("Alacritty")
                                           .build().unwrap();
    window.set_window_resize_callback(Some(window_resize_handler as fn(u32, u32)));

    gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
    let (width, height) = window.get_inner_size_pixels().unwrap();
    let dpr = window.hidpi_factor();

    println!("device_pixel_ratio: {}", dpr);

    let _ = unsafe { window.make_current() };
    unsafe {
        gl::Viewport(0, 0, width as i32, height as i32);
        gl::Enable(gl::BLEND);
        gl::BlendFunc(gl::SRC1_COLOR, gl::ONE_MINUS_SRC1_COLOR);
        gl::Enable(gl::MULTISAMPLE);
    }

    let desc = FontDesc::new(font.family(), font.style());
    let mut rasterizer = font::Rasterizer::new(dpi.x(), dpi.y(), dpr);

    let metrics = rasterizer.metrics(&desc, font.size());
    let cell_width = (metrics.average_advance + font.offset().x() as f64) as u32;
    let cell_height = (metrics.line_height + font.offset().y() as f64) as u32;

    println!("Cell Size: ({} x {})", cell_width, cell_height);

    let terminal = Term::new(width as f32, height as f32, cell_width as f32, cell_height as f32);

    let mut reader = terminal.tty().reader();
    let writer = terminal.tty().writer();

    let mut glyph_cache = GlyphCache::new(rasterizer, desc, font.size());

    let (tx, rx) = mpsc::channel();
    unsafe {
        resize_sender = Some(tx.clone());
    }

    let terminal = Arc::new(PriorityMutex::new(terminal));
    let term_ref = terminal.clone();
    let term_updater = terminal.clone();

    // Rendering thread
    //
    // Holds lock only when updating terminal
    let reader_thread = thread::spawn_named("TTY Reader", move || {
        let mut buf = [0u8; 4096];
        let mut start = 0;
        let mut pty_parser = ansi::Parser::new();

        'reader: loop {
            let got = reader.read(&mut buf[start..]).expect("pty fd active");
            let mut remain = 0;

            // if `start` is nonzero, then actual bytes in buffer is > `got` by `start` bytes.
            let end = start + got;
            let mut terminal = term_updater.lock_low();
            for c in Utf8Chars::new(&buf[..end]) {
                match c {
                    Ok(c) => pty_parser.advance(&mut *terminal, c),
                    Err(err) => match err {
                        Utf8CharsError::IncompleteUtf8(unused) => {
                            remain = unused;
                            break;
                        },
                        _ => panic!("{}", err),
                    }
                }
            }

            // Move any leftover bytes to front of buffer
            for i in 0..remain {
                buf[i] = buf[end - (remain - i)];
            }
            start = remain;
        }
    });

    let mut meter = Meter::new();

    let window = Arc::new(window);
    let window_ref = window.clone();

    // Create renderer
    let mut renderer = QuadRenderer::new(width, height);

    // Initialize glyph cache
    {
        let init_start = ::std::time::Instant::now();
        println!("Initializing glyph cache");
        let terminal = term_ref.lock_high();
        renderer.with_api(terminal.size_info(), |mut api| {
            glyph_cache.init(&mut api);
        });

        let stop = init_start.elapsed();
        let stop_f = stop.as_secs() as f64 + stop.subsec_nanos() as f64 / 1_000_000_000f64;
        println!("Finished initializing glyph cache in {}", stop_f);
    }

    let mut input_processor = input::Processor::new();

    'main_loop: loop {

        // Scope ensures terminal lock isn't held when calling swap_buffers
        {
            // Acquire term lock
            let mut terminal = term_ref.lock_high();

            // Resize events new_size and are handled outside the poll_events
            // iterator. This has the effect of coalescing multiple resize
            // events into one.
            let mut new_size = None;

            // Process input events
            {
                let mut writer = BufWriter::new(&writer);
                for event in window_ref.poll_events() {
                    match event {
                        glutin::Event::Closed => break 'main_loop,
                        glutin::Event::ReceivedCharacter(c) => {
                            match c {
                                // Ignore BACKSPACE and DEL. These are handled specially.
                                '\u{8}' | '\u{7f}' => (),
                                _ => {
                                    let encoded = c.encode_utf8();
                                    writer.write(encoded.as_slice()).unwrap();
                                }
                            }
                        },
                        glutin::Event::Resized(w, h) => {
                            new_size = Some((w, h));
                        },
                        glutin::Event::KeyboardInput(state, _code, key) => {
                            input_processor.process(state,
                                                    key,
                                                    &mut input::WriteNotifier(&mut writer),
                                                    *terminal.mode())
                        },
                        _ => (),
                    }
                }
            }

            unsafe {
                gl::ClearColor(0.0, 0.0, 0.00, 1.0);
                gl::Clear(gl::COLOR_BUFFER_BIT);
            }

            // Check for any out-of-band resize events (mac only)
            while let Ok(sz) = rx.try_recv() {
                new_size = Some(sz);
            }

            // Receive any resize events; only call gl::Viewport on last
            // available
            if let Some((w, h)) = new_size.take() {
                terminal.resize(w as f32, h as f32);
                renderer.resize(w as i32, h as i32);
            }

            {
                // Draw grid + cursor
                {
                    let _sampler = meter.sampler();

                    renderer.with_api(terminal.size_info(), |mut api| {
                        // Draw the grid
                        api.render_grid(terminal.grid(), &mut glyph_cache);

                        // Also draw the cursor
                        if terminal.mode().contains(term::mode::SHOW_CURSOR) {
                            api.render_cursor(terminal.cursor(), &mut glyph_cache);
                        }
                    })
                }

                // Draw render timer
                if render_timer {
                    let timing = format!("{:.3} usec", meter.average());
                    let color = Rgb { r: 0xd5, g: 0x4e, b: 0x53 };
                    renderer.with_api(terminal.size_info(), |mut api| {
                        api.render_string(&timing[..], &mut glyph_cache, &color);
                    });
                }
            }
        }

        window.swap_buffers().unwrap();

        if process_should_exit() {
            break;
        }
    }

    reader_thread.join().ok();
    println!("Goodbye");
}

<|endoftext|>


<commit_before>extern crate piston_window;
extern crate image;
extern crate rand;

mod cpu;
mod display;
mod instruction;
mod keyboard;

use piston_window::*;
use cpu::Cpu;
use keyboard::{ Keyboard, KeyMapping };
use std::fs::File;
use std::io::Read;
use std::env;

const ENLARGEMENT_FACTOR: u32 = 8;
const WINDOW_WIDTH: u32 = 64;
const WINDOW_HEIGHT: u32 = 32;

fn main() {
    let args: Vec<String> = env::args().collect();
    let debug = args.len() > 1 && args[1] == "debug";
    let step = args.len() > 2 && args[2] == "step";

    let width = WINDOW_WIDTH * ENLARGEMENT_FACTOR;
    let height = WINDOW_HEIGHT * ENLARGEMENT_FACTOR;

    let mut window = create_window(width, height);

    let mut file = File::open("/home/matthew/development/chip8-roms/15puzzle.rom")
        .expect("Unable to open the ROM file.");
    let mut game_data = Vec::new();
    file.read_to_end(&mut game_data).expect(
        "Unable to read the ROM file.",
    );

    let mut cpu = Cpu::new(game_data, debug);
    let keyboard = Keyboard::new(KeyMapping::Improved);

    while let Some(e) = window.next() {

        let mut step_forward = false;

        if let Some(_) = e.render_args() {
            draw_screen(&e, &cpu.get_screen(), &mut window);
        }

        if let Some(button) = e.press_args() {
            if button == Button::Keyboard(Key::Space) && step {
                step_forward = true;
            }

            if let Some(key_val) = keyboard.map_key(button) {
                cpu.set_key(key_val, true);
            }
        }

        if let Some(button) = e.release_args() {
            if let Some(key_val) = keyboard.map_key(button) {
                cpu.set_key(key_val, false);
            }
        }

        // If debugging is enabled, only cycle on space bar presses
        if !step || step_forward {
            cpu.cycle();
        }
    }
}

fn create_window(width: u32, height: u32) -> PistonWindow {
    let opengl = OpenGL::V3_2;

    let mut window: PistonWindow = WindowSettings::new("chip8", (width, height))
        .exit_on_esc(true)
        .opengl(opengl)
        .build()
        .unwrap();

    window.set_max_fps(60);

    window
}

fn draw_screen(event: &Event, screen: &display::Screen, window: &mut PistonWindow) {
    window.draw_2d(event, |context, graphics| {
        piston_window::clear(color::BLACK, graphics);

        for (i, row) in screen.iter().enumerate() {
            for (j, val) in row.iter().enumerate() {
                if *val {
                    let dimensions = [
                        (j * ENLARGEMENT_FACTOR as usize) as f64,
                        (i * ENLARGEMENT_FACTOR as usize) as f64,
                        ENLARGEMENT_FACTOR as f64,
                        ENLARGEMENT_FACTOR as f64,
                    ];
                    Rectangle::new(color::WHITE).draw(
                        dimensions,
                        &context.draw_state,
                        context.transform,
                        graphics,
                    );
                }
            }
        }
    });
}<commit_msg>Updating path to ROM file<commit_after>extern crate piston_window;
extern crate image;
extern crate rand;

mod cpu;
mod display;
mod instruction;
mod keyboard;

use piston_window::*;
use cpu::Cpu;
use keyboard::{ Keyboard, KeyMapping };
use std::fs::File;
use std::io::Read;
use std::env;

const ENLARGEMENT_FACTOR: u32 = 8;
const WINDOW_WIDTH: u32 = 64;
const WINDOW_HEIGHT: u32 = 32;

fn main() {
    let args: Vec<String> = env::args().collect();
    let debug = args.len() > 1 && args[1] == "debug";
    let step = args.len() > 2 && args[2] == "step";

    let width = WINDOW_WIDTH * ENLARGEMENT_FACTOR;
    let height = WINDOW_HEIGHT * ENLARGEMENT_FACTOR;

    let mut window = create_window(width, height);

    let mut file = File::open("/home/matt/Development/chip8/roms/15puzzle.rom")
        .expect("Unable to open the ROM file.");
    let mut game_data = Vec::new();
    file.read_to_end(&mut game_data).expect(
        "Unable to read the ROM file.",
    );

    let mut cpu = Cpu::new(game_data, debug);
    let keyboard = Keyboard::new(KeyMapping::Improved);

    while let Some(e) = window.next() {

        let mut step_forward = false;

        if let Some(_) = e.render_args() {
            draw_screen(&e, &cpu.get_screen(), &mut window);
        }

        if let Some(button) = e.press_args() {
            if button == Button::Keyboard(Key::Space) && step {
                step_forward = true;
            }

            if let Some(key_val) = keyboard.map_key(button) {
                cpu.set_key(key_val, true);
            }
        }

        if let Some(button) = e.release_args() {
            if let Some(key_val) = keyboard.map_key(button) {
                cpu.set_key(key_val, false);
            }
        }

        // If debugging is enabled, only cycle on space bar presses
        if !step || step_forward {
            cpu.cycle();
        }
    }
}

fn create_window(width: u32, height: u32) -> PistonWindow {
    let opengl = OpenGL::V3_2;

    let mut window: PistonWindow = WindowSettings::new("chip8", (width, height))
        .exit_on_esc(true)
        .opengl(opengl)
        .build()
        .unwrap();

    window.set_max_fps(60);

    window
}

fn draw_screen(event: &Event, screen: &display::Screen, window: &mut PistonWindow) {
    window.draw_2d(event, |context, graphics| {
        piston_window::clear(color::BLACK, graphics);

        for (i, row) in screen.iter().enumerate() {
            for (j, val) in row.iter().enumerate() {
                if *val {
                    let dimensions = [
                        (j * ENLARGEMENT_FACTOR as usize) as f64,
                        (i * ENLARGEMENT_FACTOR as usize) as f64,
                        ENLARGEMENT_FACTOR as f64,
                        ENLARGEMENT_FACTOR as f64,
                    ];
                    Rectangle::new(color::WHITE).draw(
                        dimensions,
                        &context.draw_state,
                        context.transform,
                        graphics,
                    );
                }
            }
        }
    });
}<|endoftext|>


<commit_before>extern crate rustc_serialize;
use rustc_serialize::json;

use std::fmt;
use std::env;

use std::fs::File;
use std::io::Read;

use std::thread;
use std::sync::{Mutex, Arc};
use std::process::Command;

extern crate ansi_term;
use ansi_term::Colour;

struct WorkConf {
    project: String,
    operate: String,
    head:    String,
}

impl fmt::Debug for WorkConf {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "WorkConf:{}\"project\": {}, \"operate\": {}, \"head\": {}{}",
            "{", self.project, self.operate, self.head, "}")
    }
}

// Automatically generate `RustcDecodable` and `RustcEncodable` trait
// implementations
#[derive(RustcDecodable, RustcEncodable)]
struct DeployConf {
    user: String,
    path: String,
    hosts_conf: Vec<String>,
}

fn usage(argv_0: &String) {
    println!("\n{}", Colour::Cyan.bold().paint("-----USAGE----"));
    println!("{} {} {}             {}",
        Colour::Green.bold().paint(argv_0.to_string()),
        Colour::Blue.bold().paint("project"),
        Colour::Yellow.bold().paint("deploy"),
        Colour::Red.paint("deploy project with latest <head>."));
    println!("{} {} {} {}    {}\n",
        Colour::Green.bold().paint(argv_0.to_string()),
        Colour::Blue.bold().paint("project"),
        Colour::Yellow.bold().paint("rollback"),
        Colour::Purple.bold().paint("<head>"),
        Colour::Red.paint("rollback with <head>."));
    std::process::exit(0);
}

static DEBUG: bool = false;

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

    if argc < 3 {
        usage(&args[0]);
    }

    // 处理命令行参数
    let project = args[1].to_string();
    let operate = args[2].to_string();
    if ("deploy".to_string() != operate && "rollback".to_string() != operate) || ("rollback".to_string() == operate && argc < 4) {
        usage(&args[0]);
    }

    let head = if argc > 3 { args[3].to_string() } else { "".to_string() };

    let work_conf = WorkConf{
        project: project,
        operate: operate,
        head:    head,
    };
    if DEBUG { println!("{:?}", work_conf); }

    let config_filename = format!("./conf/{}.json", work_conf.project);
    if DEBUG { println!("config_filename: {}", config_filename); }

    let mut data = String::new();
    let mut f = File::open(config_filename)
        .ok()
        .expect("Can NOT open file.");
    f.read_to_string(&mut data)
        .ok()
        .expect("Can NOT read cofing file.");
    if DEBUG { println!("deploy_conf: {}", data)}
    let deploy_conf: DeployConf = json::decode(&data)
        .ok()
        .expect("Can NOT parse JSON config data.");
    if DEBUG { println!("JSON: {}", json::encode(&deploy_conf).unwrap()); }

    let mut hosts_conf = Vec::new();
    let hosts_len = deploy_conf.hosts_conf.len();
    for index in 0 .. hosts_len {
        hosts_conf.push(deploy_conf.hosts_conf[index].clone());
    }
    let mutex_ct = Arc::new(Mutex::new(vec![1]));

    println!("          ===== {} ======\n", work_conf.project);

    let handles: Vec<_> = hosts_conf.into_iter().map(|host| {
        let user = deploy_conf.user.clone();
        let path = deploy_conf.path.clone();
        let operate = work_conf.operate.clone();
        let head    = work_conf.head.clone();
        let mutex_ct= mutex_ct.clone();
        thread::spawn(move || {
            let cmd = if "deploy".to_string() == operate {
                format!("ssh {}@{} \"cd {} && git pull && git log -1 | awk '{{if (\\$1 ~/commit/) {{print \\$2}}}}' 2>&1\"",
                user, host, path)
            } else {
                format!("ssh {}@{} \"cd {} && git reset --hard {} && git log -1 | awk '{{if (\\$1 ~/commit/) {{print \\$2}}}}' 2>&1\"",
                user, host, path, head)
            };
            if DEBUG { println!("CMD: {}", cmd); }
            let output = Command::new("sh")
                .arg("-c")
                .arg(cmd)
                .output()
                .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });

            // 解决多线程穿插输出的问题
            let mut output_buf = "".to_string();
            output_buf = output_buf + &(format!("--- Start {} for {}@{} ---\n", operate, user, host));
            if DEBUG { println!("status: {}", output.status); }
            output_buf = output_buf + &(format!("stdout: {}\n", String::from_utf8_lossy(&output.stdout)));
            output_buf = output_buf + &(format!("stderr: {}\n", String::from_utf8_lossy(&output.stderr)));
            output_buf = output_buf + &(format!("--- End {} for {}@{} ---\n\n", operate, user, host));

            {
                let _ct = mutex_ct.lock().unwrap();
                println!("{}", output_buf);
            }
        })
    }).collect();

    for h in handles {
        h.join().unwrap();
    }
}
<commit_msg>输出加入颜色提示.<commit_after>extern crate rustc_serialize;
use rustc_serialize::json;

use std::fmt;
use std::env;

use std::fs::File;
use std::io::Read;

use std::thread;
use std::sync::{Mutex, Arc};
use std::process::Command;

extern crate ansi_term;
use ansi_term::Colour;

struct WorkConf {
    project: String,
    operate: String,
    head:    String,
}

impl fmt::Debug for WorkConf {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "WorkConf:{}\"project\": {}, \"operate\": {}, \"head\": {}{}",
            "{", self.project, self.operate, self.head, "}")
    }
}

// Automatically generate `RustcDecodable` and `RustcEncodable` trait
// implementations
#[derive(RustcDecodable, RustcEncodable)]
struct DeployConf {
    user: String,
    path: String,
    hosts_conf: Vec<String>,
}

fn usage(argv_0: &String) {
    println!("\n{}", Colour::Cyan.bold().paint("-----USAGE----"));
    println!("{} {} {}             {}",
        Colour::Green.bold().paint(argv_0.to_string()),
        Colour::Blue.bold().paint("project"),
        Colour::Yellow.bold().paint("deploy"),
        Colour::Red.paint("deploy project with latest <head>."));
    println!("{} {} {} {}    {}\n",
        Colour::Green.bold().paint(argv_0.to_string()),
        Colour::Blue.bold().paint("project"),
        Colour::Yellow.bold().paint("rollback"),
        Colour::Purple.bold().paint("<head>"),
        Colour::Red.paint("rollback with <head>."));
    std::process::exit(0);
}

static DEBUG: bool = false;

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

    if argc < 3 {
        usage(&args[0]);
    }

    // 处理命令行参数
    let project = args[1].to_string();
    let operate = args[2].to_string();
    if ("deploy".to_string() != operate && "rollback".to_string() != operate) || ("rollback".to_string() == operate && argc < 4) {
        usage(&args[0]);
    }

    let head = if argc > 3 { args[3].to_string() } else { "".to_string() };

    let work_conf = WorkConf{
        project: project,
        operate: operate,
        head:    head,
    };
    if DEBUG { println!("{:?}", work_conf); }

    let config_filename = format!("./conf/{}.json", work_conf.project);
    if DEBUG { println!("config_filename: {}", config_filename); }

    let mut data = String::new();
    let mut f = File::open(config_filename)
        .ok()
        .expect("Can NOT open file.");
    f.read_to_string(&mut data)
        .ok()
        .expect("Can NOT read cofing file.");
    if DEBUG { println!("deploy_conf: {}", data)}
    let deploy_conf: DeployConf = json::decode(&data)
        .ok()
        .expect("Can NOT parse JSON config data.");
    if DEBUG { println!("JSON: {}", json::encode(&deploy_conf).unwrap()); }

    let mut hosts_conf = Vec::new();
    let hosts_len = deploy_conf.hosts_conf.len();
    for index in 0 .. hosts_len {
        hosts_conf.push(deploy_conf.hosts_conf[index].clone());
    }
    let mutex_ct = Arc::new(Mutex::new(vec![1]));

    println!("          ===== {} ======\n", Colour::Blue.bold().paint(work_conf.project.to_string()));

    let handles: Vec<_> = hosts_conf.into_iter().map(|host| {
        let user = deploy_conf.user.clone();
        let path = deploy_conf.path.clone();
        let operate = work_conf.operate.clone();
        let head    = work_conf.head.clone();
        let mutex_ct= mutex_ct.clone();
        thread::spawn(move || {
            let cmd = if "deploy".to_string() == operate {
                format!("ssh {}@{} \"cd {} && git pull && git log -1 | awk '{{if (\\$1 ~/commit/) {{print \\$2}}}}' 2>&1\"",
                user, host, path)
            } else {
                format!("ssh {}@{} \"cd {} && git reset --hard {} && git log -1 | awk '{{if (\\$1 ~/commit/) {{print \\$2}}}}' 2>&1\"",
                user, host, path, head)
            };
            if DEBUG { println!("CMD: {}", cmd); }
            let output = Command::new("sh")
                .arg("-c")
                .arg(cmd)
                .output()
                .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });

            // 解决多线程穿插输出的问题
            let user_at_host = format!("{}{}{}",
                Colour::Green.bold().paint(user.to_string()),
                Colour::Red.bold().paint("@"),
                Colour::Cyan.bold().paint(host.to_string()));
            let mut output_buf = "".to_string();
            output_buf = output_buf + &(format!("--- {} {} for {} ---\n",
                Colour::Cyan.bold().paint("START"),
                Colour::Purple.bold().paint(operate.to_string()), user_at_host));
            if DEBUG { println!("status: {}", output.status); }
            output_buf = output_buf + &(format!("{} {}\n", Colour::Green.bold().paint("stdout:"), String::from_utf8_lossy(&output.stdout)));
            output_buf = output_buf + &(format!("{} {}\n", Colour::Red.bold().paint("stderr:"),String::from_utf8_lossy(&output.stderr)));
            output_buf = output_buf + &(format!("--- {} ---\n\n", Colour::Cyan.bold().paint("END")));

            {
                let _ct = mutex_ct.lock().unwrap();
                println!("{}", output_buf);
            }
        })
    }).collect();

    for h in handles {
        h.join().unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
extern crate docopt;
use docopt::Docopt;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;

#[macro_use]
extern crate log;
extern crate env_logger;

use std::{process, env};
use std::io::{self, Read, Write};
use std::path::PathBuf;
use std::fs::{self, File};
use std::error::Error;

mod keepasshttp;

const VERSION: &'static str = "0.1.1";
const USAGE: &'static str = "
cmdipass

Usage:
  cmdipass get <search-string>
  cmdipass get-one <search-string> (--index=<index> | --uuid=<uuid>) [--password-only | --username-only]
  cmdipass --version
  cmdipass (-h | --help)

Options:
  -h --help         Show this screen.
  --version         Show version.
  --index=<index>   Select the entry at this 0-indexed location.
  --uuid=<uuid>     Select the entry with this uuid.
  --password-only   Print only the password.
  --username-only   Print only the username.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    cmd_get: bool,
    cmd_get_one: bool,
    flag_version: bool,
    flag_help: bool,
    arg_search_string: String,
    flag_index: Option<usize>,
    flag_uuid: Option<String>,
    flag_password_only: bool,
    flag_username_only: bool
}

fn config_path() -> PathBuf {
    env::var("CMDIPASS_CONFIG").map(|e| PathBuf::from(e)).unwrap_or_else(|_| {
        let mut pathbuf = env::home_dir().unwrap_or(PathBuf::from(""));
        pathbuf.push(".cmdipass");
        pathbuf
    })
}

fn config_exists() -> bool {
    config_path().as_path().exists()
}

#[cfg(any(unix))]
fn ensure_owner_readable_only(f: &File) -> io::Result<()> {
    use std::os::unix::fs::PermissionsExt;
    let metadata = f.metadata()?;
    let mode = metadata.permissions().mode();

    if 0o077 & mode != 0 {
        Err(io::Error::new(io::ErrorKind::Other,
            format!("Permissions {:04o} on '{}' are too open.\nIt is recommended that your cmdipass config file is not accessible to others.", mode, config_path().to_string_lossy())))
    } else {
        Ok(())
    }
}

fn load_config() -> io::Result<keepasshttp::Config> {
    let mut res = File::open(config_path())?;
    if cfg!(any(unix)) {
        ensure_owner_readable_only(&res)?;
    }
    let mut buf = String::new();
    res.read_to_string(&mut buf)?;

    let config: keepasshttp::Config = serde_json::from_str(buf.as_str())
        .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, format!("Invalid JSON: {}", e.description())))?;
    Ok(config)
}

#[cfg(any(unix))]
fn write_config_file(config: &keepasshttp::Config) {
    use std::os::unix::fs::OpenOptionsExt;
    let mut file = fs::OpenOptions::new().write(true).create(true).mode(0o600).open(config_path()).unwrap();
    file.write_all(serde_json::to_string(&config).unwrap().as_bytes()).unwrap();
}

#[cfg(any(not(unix)))]
fn write_config_file(config: &keepasshttp::Config) {
    let mut file = fs::OpenOptions::new().write(true).create(true).open(config_path()).unwrap();
    file.write_all(serde_json::to_string(&config).unwrap().as_bytes()).unwrap();
}

fn show_all(entries: &Vec<keepasshttp::Entry>) {
    for(i, entry) in entries.iter().enumerate() {
        println!("{}: {}", i, entry);
    }
}

fn show_one(entries: &Vec<keepasshttp::Entry>, args: &Args) {
    let entry = if args.flag_uuid.is_some() {
        entry_by_uuid(entries, &args.flag_uuid.clone().unwrap())
    } else if args.flag_index.is_some() {
        entry_by_index(entries, &args.flag_index.clone().unwrap())
    } else {
        None
    }.unwrap_or_else(|| {
        process::exit(1);
    });

    if args.flag_password_only {
        println!("{}", entry.password);
    } else if args.flag_username_only {
        println!("{}", entry.login);
    } else {
        println!("{}", entry);
    }

}

fn entry_by_index<'a>(entries: &'a Vec<keepasshttp::Entry>, index: &usize) -> Option<&'a keepasshttp::Entry> {
    let entry = entries.get(*index);

    if entry.is_none() {
        writeln!(io::stderr(), "Could not find an entry at index {}", index).unwrap();
    }

    entry
}

fn entry_by_uuid<'a, T: AsRef<str>>(entries: &'a Vec<keepasshttp::Entry>, uuid: T) -> Option<&'a keepasshttp::Entry> {
    let entry = entries.iter().find(|e| e.uuid == uuid.as_ref());

    if entry.is_none() {
        writeln!(io::stderr(), "Could not find an entry with UUID {}", uuid.as_ref()).unwrap();
    }

    entry
}

fn get_entries<T: AsRef<str>>(search_string: T) -> Vec<keepasshttp::Entry> {
    let config = load_config().unwrap_or_else(|e| {
        writeln!(io::stderr(), "Could not load config:\n{}", e).unwrap();
        process::exit(1);
    });
    let success = keepasshttp::test_associate(&config);
    if !success {
        writeln!(io::stderr(), "Config rejected by keepasshttp. Make sure that the correct database is open, or delete your config file ({}) and re-associate", config_path().to_string_lossy()).unwrap();
        process::exit(1);
    }

    keepasshttp::get_logins(&config, &search_string).unwrap_or_else(|e| {
        writeln!(io::stderr(), "Error - Server said: '{}'", e).unwrap();
        process::exit(1);
    })
}

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

    env_logger::init().unwrap();

    if args.flag_help {
        println!("{}", USAGE);
        process::exit(0);
    }

    if args.flag_version {
        println!("cmdipass-{}", VERSION);
        process::exit(0);
    }

    if !config_exists() {
        writeln!(io::stderr(), "Config file not found at '{}', generating new key and registering with server", config_path().to_string_lossy()).unwrap();
        write_config_file(&keepasshttp::associate().unwrap());
        writeln!(io::stderr(), "Config file written.").unwrap();
    }

    let entries = get_entries(&args.arg_search_string);

    if args.cmd_get {
        show_all(&entries);
    } else if args.cmd_get_one {
        show_one(&entries, &args);
    }
}
<commit_msg>Provides a suggestion to fix config file permissions being too open<commit_after>extern crate rustc_serialize;
extern crate docopt;
use docopt::Docopt;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;

#[macro_use]
extern crate log;
extern crate env_logger;

use std::{process, env};
use std::io::{self, Read, Write};
use std::path::PathBuf;
use std::fs::{self, File};
use std::error::Error;

mod keepasshttp;

const VERSION: &'static str = "0.1.1";
const USAGE: &'static str = "
cmdipass

Usage:
  cmdipass get <search-string>
  cmdipass get-one <search-string> (--index=<index> | --uuid=<uuid>) [--password-only | --username-only]
  cmdipass --version
  cmdipass (-h | --help)

Options:
  -h --help         Show this screen.
  --version         Show version.
  --index=<index>   Select the entry at this 0-indexed location.
  --uuid=<uuid>     Select the entry with this uuid.
  --password-only   Print only the password.
  --username-only   Print only the username.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    cmd_get: bool,
    cmd_get_one: bool,
    flag_version: bool,
    flag_help: bool,
    arg_search_string: String,
    flag_index: Option<usize>,
    flag_uuid: Option<String>,
    flag_password_only: bool,
    flag_username_only: bool
}

fn config_path() -> PathBuf {
    env::var("CMDIPASS_CONFIG").map(|e| PathBuf::from(e)).unwrap_or_else(|_| {
        let mut pathbuf = env::home_dir().unwrap_or(PathBuf::from(""));
        pathbuf.push(".cmdipass");
        pathbuf
    })
}

fn config_exists() -> bool {
    config_path().as_path().exists()
}

#[cfg(any(unix))]
fn ensure_owner_readable_only(f: &File) -> io::Result<()> {
    use std::os::unix::fs::PermissionsExt;
    let metadata = f.metadata()?;
    let mode = metadata.permissions().mode();

    if 0o077 & mode != 0 {
        Err(io::Error::new(io::ErrorKind::Other,
            format!("Permissions {:04o} on '{path}' are too open.\n\
                It is recommended that your cmdipass config file is not accessible to others.\n\
                Try using `chmod 0600 '{path}'` to solve this problem.", mode, path = config_path().to_string_lossy())))
    } else {
        Ok(())
    }
}

fn load_config() -> io::Result<keepasshttp::Config> {
    let mut res = File::open(config_path())?;
    if cfg!(any(unix)) {
        ensure_owner_readable_only(&res)?;
    }
    let mut buf = String::new();
    res.read_to_string(&mut buf)?;

    let config: keepasshttp::Config = serde_json::from_str(buf.as_str())
        .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, format!("Invalid JSON: {}", e.description())))?;
    Ok(config)
}

#[cfg(any(unix))]
fn write_config_file(config: &keepasshttp::Config) {
    use std::os::unix::fs::OpenOptionsExt;
    let mut file = fs::OpenOptions::new().write(true).create(true).mode(0o600).open(config_path()).unwrap();
    file.write_all(serde_json::to_string(&config).unwrap().as_bytes()).unwrap();
}

#[cfg(any(not(unix)))]
fn write_config_file(config: &keepasshttp::Config) {
    let mut file = fs::OpenOptions::new().write(true).create(true).open(config_path()).unwrap();
    file.write_all(serde_json::to_string(&config).unwrap().as_bytes()).unwrap();
}

fn show_all(entries: &Vec<keepasshttp::Entry>) {
    for(i, entry) in entries.iter().enumerate() {
        println!("{}: {}", i, entry);
    }
}

fn show_one(entries: &Vec<keepasshttp::Entry>, args: &Args) {
    let entry = if args.flag_uuid.is_some() {
        entry_by_uuid(entries, &args.flag_uuid.clone().unwrap())
    } else if args.flag_index.is_some() {
        entry_by_index(entries, &args.flag_index.clone().unwrap())
    } else {
        None
    }.unwrap_or_else(|| {
        process::exit(1);
    });

    if args.flag_password_only {
        println!("{}", entry.password);
    } else if args.flag_username_only {
        println!("{}", entry.login);
    } else {
        println!("{}", entry);
    }

}

fn entry_by_index<'a>(entries: &'a Vec<keepasshttp::Entry>, index: &usize) -> Option<&'a keepasshttp::Entry> {
    let entry = entries.get(*index);

    if entry.is_none() {
        writeln!(io::stderr(), "Could not find an entry at index {}", index).unwrap();
    }

    entry
}

fn entry_by_uuid<'a, T: AsRef<str>>(entries: &'a Vec<keepasshttp::Entry>, uuid: T) -> Option<&'a keepasshttp::Entry> {
    let entry = entries.iter().find(|e| e.uuid == uuid.as_ref());

    if entry.is_none() {
        writeln!(io::stderr(), "Could not find an entry with UUID {}", uuid.as_ref()).unwrap();
    }

    entry
}

fn get_entries<T: AsRef<str>>(search_string: T) -> Vec<keepasshttp::Entry> {
    let config = load_config().unwrap_or_else(|e| {
        writeln!(io::stderr(), "Could not load config:\n{}", e).unwrap();
        process::exit(1);
    });
    let success = keepasshttp::test_associate(&config);
    if !success {
        writeln!(io::stderr(), "Config rejected by keepasshttp. Make sure that the correct database is open, or delete your config file ({}) and re-associate", config_path().to_string_lossy()).unwrap();
        process::exit(1);
    }

    keepasshttp::get_logins(&config, &search_string).unwrap_or_else(|e| {
        writeln!(io::stderr(), "Error - Server said: '{}'", e).unwrap();
        process::exit(1);
    })
}

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

    env_logger::init().unwrap();

    if args.flag_help {
        println!("{}", USAGE);
        process::exit(0);
    }

    if args.flag_version {
        println!("cmdipass-{}", VERSION);
        process::exit(0);
    }

    if !config_exists() {
        writeln!(io::stderr(), "Config file not found at '{}', generating new key and registering with server", config_path().to_string_lossy()).unwrap();
        write_config_file(&keepasshttp::associate().unwrap());
        writeln!(io::stderr(), "Config file written.").unwrap();
    }

    let entries = get_entries(&args.arg_search_string);

    if args.cmd_get {
        show_all(&entries);
    } else if args.cmd_get_one {
        show_one(&entries, &args);
    }
}
<|endoftext|>