<commit_before>use std::env;
use std::io;
use std::process;
use std::process::Command;
use std::io::Write;
use std::os::unix::process::CommandExt;

mod auth;
use auth::authenticate_current_user_n;
use auth::get_username;

mod settings;
use settings::Settings;

mod session;

extern crate libc;
use libc::isatty;

extern crate getopts;
use getopts::Options;
use getopts::ParsingStyle;

extern crate users;
use users::get_user_by_name;
use users::get_group_by_name;

extern crate time;

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

// Global config
static CONFIG_PATH: &'static str = "/etc/rudo.json";
static DEFAULT_PROMPT: &'static str = "Password: ";
static SESSION_PATH: &'static str = "/var/run/rudo";
static DEFAULT_SESSION_TIMEOUT: i64 = 900;

fn print_help(program_name: &str, opts: Options) {
    let brief = format!("Usage: {} [flags] [command]", program_name);
    writeln!(&mut io::stderr(), "{}", opts.usage(&brief))
        .expect("Failed to write to stderr!");
}

fn generate_empty_config() {
    // Create a new settings object
    let new_settings = Settings::new();

    // Get a serialized string representation of the object
    let settings_str = new_settings.to_string()
        .expect("Unable to generate empty settings file!");

    // Output the new settings string to stdout
    println!("{}", settings_str);
}

/**
 * Handles listing of current user's permissions to STDOUT
 */
fn list_permissions() {
    // Load the settings file
    let settings = Settings::from_file(CONFIG_PATH)
        .expect("Unable to read configuration file! Run --genconfig.");

    // Give the user 3 tries to authenticate
    let auth_res = authenticate_current_user_n(&settings, 3);
    if !auth_res {
        process::exit(1);
    }

    // Get this user's User struct
    let username = get_username();
    let user = settings.get_user(&username).unwrap_or_else(|_| {
        writeln!(&mut io::stderr(), "You are not in the rudo.json file! This incident won't be reported.")
            .expect("Failed to write to stderr!");
        process::exit(1);
    });

    // Create a string of all commands the user can run
    let mut all_commands: String = String::new();
    for cmd in &user.permissions.allowed_commands {
        all_commands += cmd;
        all_commands += " ";
    }

    println!("You are allowed to run the following commands: {}", all_commands);
    process::exit(0);
}

/**
 * Handles default behavior of program - Authenticate and run a command
 * @param user user to run command as
 * @param command program to launch
 * @param args arguments to launch the program with
 */
fn run_command(user: Option<String>, group: Option<String>,  command: &str, args: &Vec<String>) {
    // Load the settings file
    let settings = Settings::from_file(CONFIG_PATH)
    .expect("Unable to read configuration file! Run --genconfig.");

    // Give the user 3 tries to authenticate
    let auth_res = authenticate_current_user_n(&settings, 3);
    if !auth_res {
        process::exit(1);
    }

    // Confirm that user is in the settings file and has permission
    let username: String = get_username();
    let can_run = settings.can_run_command(&username, command).unwrap_or_else(|_| {
        writeln!(&mut io::stderr(), "You are not in the rudo.json file! This incident won't be reported.")
            .expect("Failed to write to stderr!");
        process::exit(1);
    });

    if !can_run {
        writeln!(&mut io::stderr(), "You don't have permission to run that! This incident won't be reported.")
            .expect("Failed to write to stderr!");
        process::exit(1);
    }

    // Determine the uid of the user to impersonate
    let mut uid: u32 = 0;
    let mut gid: u32 = 0;
    if let Some(username) = user {
        let u = get_user_by_name(&username).unwrap_or_else(|| {
            writeln!(&mut io::stderr(), "Invalid username! See --help for more information.")
                .expect("Failed to write to stderr!");
            process::exit(1);
        });
        uid = u.uid();
        gid = u.primary_group_id();
    }

    // If the user provided a group, set that
    if let Some(groupname) = group {
    	let g = get_group_by_name(&groupname).unwrap_or_else(|| {
    		writeln!(&mut io::stderr(), "Invalid group name! See --help for more information.")
    			.expect("Failed to write to stderr!");
    		process::exit(1);
    	});
    	gid = g.gid();
    }

    // Now that the user is authenticated, run the provided command
    Command::new(command).args(args).uid(uid).gid(gid).exec();

    // If we got here, it means the command failed
    writeln!(&mut io::stderr(), "rudo: {}: command not found", &command)
        .expect("Failed to write to stderr!");
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program_name = args[0].clone();
    let mut opts = Options::new();
    opts.parsing_style(ParsingStyle::StopAtFirstFree);

    let mut user: Option<String> = None;
    let mut group: Option<String> = None;

    // Set up arguments
    opts.optflag("h", "help", "print this help menu");
    opts.optflag("l", "list", "list all permissions for current user");
    opts.optopt("u", "user", "run as the specified user", "<user>");
    opts.optopt("g", "group", "run as the specified group", "<group>");
    opts.optflag("", "genconfig", "Generate an empty config and output to STDOUT");

    // Create a vec of up to 2 arguments to parse
    // We ignore all arguments past the first
    let mut matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(_) => { print_help(&program_name, opts); process::exit(1); }
    };

    // Handle help
    if matches.opt_present("h") {
        print_help(&program_name, opts);
        process::exit(0);
    }

    // Handle --list
    if matches.opt_present("l") {
        list_permissions();
        process::exit(0);
    }

    if matches.free.len() < 1 {
        print_help(&program_name, opts);
        process::exit(1);
    }

    // Handle --user
    if matches.opt_present("u") {
        // Set the user to the provided user
        user = match matches.opt_str("u") {
            Some(x) => Some(x),
            None => { print_help(&program_name, opts); process::exit(1); }
        };
    }

    // Handle --group
    if matches.opt_present("g") {
    	// Set the group to the provided group
    	group = match matches.opt_str("g") {
    		Some(x) => Some(x),
    		None => { print_help(&program_name, opts); process::exit(1) }
    	};
    }

    // Handle --genconfig
    if matches.opt_present("genconfig") {
        generate_empty_config();
        process::exit(0);
    }

    // Handle default behavior (run command)

    // Make sure we're running in a tty
    let is_tty = unsafe { isatty(0) };
    if is_tty != 1 {
        writeln!(&mut io::stderr(), "rudo must be run from a TTY!").unwrap();
    }
    let command = matches.free[0].clone();
    matches.free.remove(0);
    run_command(user, group, &command, &matches.free);
}
<commit_msg>Fix --genconfig<commit_after>use std::env;
use std::io;
use std::process;
use std::process::Command;
use std::io::Write;
use std::os::unix::process::CommandExt;

mod auth;
use auth::authenticate_current_user_n;
use auth::get_username;

mod settings;
use settings::Settings;

mod session;

extern crate libc;
use libc::isatty;

extern crate getopts;
use getopts::Options;
use getopts::ParsingStyle;

extern crate users;
use users::get_user_by_name;
use users::get_group_by_name;

extern crate time;

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

// Global config
static CONFIG_PATH: &'static str = "/etc/rudo.json";
static DEFAULT_PROMPT: &'static str = "Password: ";
static SESSION_PATH: &'static str = "/var/run/rudo";
static DEFAULT_SESSION_TIMEOUT: i64 = 900;

fn print_help(program_name: &str, opts: Options) {
    let brief = format!("Usage: {} [flags] [command]", program_name);
    writeln!(&mut io::stderr(), "{}", opts.usage(&brief))
        .expect("Failed to write to stderr!");
}

fn generate_empty_config() {
    // Create a new settings object
    let new_settings = Settings::new();

    // Get a serialized string representation of the object
    let settings_str = new_settings.to_string()
        .expect("Unable to generate empty settings file!");

    // Output the new settings string to stdout
    println!("{}", settings_str);
}

/**
 * Handles listing of current user's permissions to STDOUT
 */
fn list_permissions() {
    // Load the settings file
    let settings = Settings::from_file(CONFIG_PATH)
        .expect("Unable to read configuration file! Run --genconfig.");

    // Give the user 3 tries to authenticate
    let auth_res = authenticate_current_user_n(&settings, 3);
    if !auth_res {
        process::exit(1);
    }

    // Get this user's User struct
    let username = get_username();
    let user = settings.get_user(&username).unwrap_or_else(|_| {
        writeln!(&mut io::stderr(), "You are not in the rudo.json file! This incident won't be reported.")
            .expect("Failed to write to stderr!");
        process::exit(1);
    });

    // Create a string of all commands the user can run
    let mut all_commands: String = String::new();
    for cmd in &user.permissions.allowed_commands {
        all_commands += cmd;
        all_commands += " ";
    }

    println!("You are allowed to run the following commands: {}", all_commands);
    process::exit(0);
}

/**
 * Handles default behavior of program - Authenticate and run a command
 * @param user user to run command as
 * @param command program to launch
 * @param args arguments to launch the program with
 */
fn run_command(user: Option<String>, group: Option<String>,  command: &str, args: &Vec<String>) {
    // Load the settings file
    let settings = Settings::from_file(CONFIG_PATH)
    .expect("Unable to read configuration file! Run --genconfig.");

    // Give the user 3 tries to authenticate
    let auth_res = authenticate_current_user_n(&settings, 3);
    if !auth_res {
        process::exit(1);
    }

    // Confirm that user is in the settings file and has permission
    let username: String = get_username();
    let can_run = settings.can_run_command(&username, command).unwrap_or_else(|_| {
        writeln!(&mut io::stderr(), "You are not in the rudo.json file! This incident won't be reported.")
            .expect("Failed to write to stderr!");
        process::exit(1);
    });

    if !can_run {
        writeln!(&mut io::stderr(), "You don't have permission to run that! This incident won't be reported.")
            .expect("Failed to write to stderr!");
        process::exit(1);
    }

    // Determine the uid of the user to impersonate
    let mut uid: u32 = 0;
    let mut gid: u32 = 0;
    if let Some(username) = user {
        let u = get_user_by_name(&username).unwrap_or_else(|| {
            writeln!(&mut io::stderr(), "Invalid username! See --help for more information.")
                .expect("Failed to write to stderr!");
            process::exit(1);
        });
        uid = u.uid();
        gid = u.primary_group_id();
    }

    // If the user provided a group, set that
    if let Some(groupname) = group {
    	let g = get_group_by_name(&groupname).unwrap_or_else(|| {
    		writeln!(&mut io::stderr(), "Invalid group name! See --help for more information.")
    			.expect("Failed to write to stderr!");
    		process::exit(1);
    	});
    	gid = g.gid();
    }

    // Now that the user is authenticated, run the provided command
    Command::new(command).args(args).uid(uid).gid(gid).exec();

    // If we got here, it means the command failed
    writeln!(&mut io::stderr(), "rudo: {}: command not found", &command)
        .expect("Failed to write to stderr!");
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program_name = args[0].clone();
    let mut opts = Options::new();
    opts.parsing_style(ParsingStyle::StopAtFirstFree);

    let mut user: Option<String> = None;
    let mut group: Option<String> = None;

    // Set up arguments
    opts.optflag("h", "help", "print this help menu");
    opts.optflag("l", "list", "list all permissions for current user");
    opts.optopt("u", "user", "run as the specified user", "<user>");
    opts.optopt("g", "group", "run as the specified group", "<group>");
    opts.optflag("", "genconfig", "Generate an empty config and output to STDOUT");

    // Create a vec of up to 2 arguments to parse
    // We ignore all arguments past the first
    let mut matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(_) => { print_help(&program_name, opts); process::exit(1); }
    };

    // Handle help
    if matches.opt_present("h") {
        print_help(&program_name, opts);
        process::exit(0);
    }

    // Handle --list
    if matches.opt_present("l") {
        list_permissions();
        process::exit(0);
    }

    // Handle --genconfig
    if matches.opt_present("genconfig") {
        generate_empty_config();
        process::exit(0);
    }

    if matches.free.len() < 1 {
        print_help(&program_name, opts);
        process::exit(1);
    }

    // Handle --user
    if matches.opt_present("u") {
        // Set the user to the provided user
        user = match matches.opt_str("u") {
            Some(x) => Some(x),
            None => { print_help(&program_name, opts); process::exit(1); }
        };
    }

    // Handle --group
    if matches.opt_present("g") {
    	// Set the group to the provided group
    	group = match matches.opt_str("g") {
    		Some(x) => Some(x),
    		None => { print_help(&program_name, opts); process::exit(1) }
    	};
    }

    // Handle default behavior (run command)

    // Make sure we're running in a tty
    let is_tty = unsafe { isatty(0) };
    if is_tty != 1 {
        writeln!(&mut io::stderr(), "rudo must be run from a TTY!").unwrap();
    }
    let command = matches.free[0].clone();
    matches.free.remove(0);
    run_command(user, group, &command, &matches.free);
}
<|endoftext|>


<commit_before>extern crate kernel32;
extern crate user32;
extern crate winapi;
extern crate libc;
extern crate gdi32;

use winapi::windef::HWND;
use winapi::windef::HMENU;
use winapi::windef::HBRUSH;
use winapi::minwindef::HINSTANCE;

use winapi::minwindef::UINT;
use winapi::minwindef::DWORD;
use winapi::minwindef::WPARAM;
use winapi::minwindef::LPARAM;
use winapi::minwindef::LRESULT;
use winapi::winnt::LPCWSTR;

use winapi::winuser::WS_OVERLAPPEDWINDOW;
use winapi::winuser::WS_VISIBLE;
use winapi::winuser::WNDCLASSW;
use winapi::winuser::CF_BITMAP;

use std::os::windows::ffi::OsStrExt;
use std::ffi::OsStr;

const g_class_name: &'static str = "winshot";

// Rectangle represents screen coordinates
struct Rectangle {
	x: i32,
	y: i32,
	x2: i32,
	y2: i32,
}

// convert normal string to wide string
#[allow(dead_code)]
fn to_wstring(str: &str) -> *const u16 {
	let v: Vec<u16> = OsStr::new(str).encode_wide() . chain(Some(0).into_iter()).collect();
	v.as_ptr()
}

// This is our window message handler function. Currently,
// it only processes the WM_DESTROY message to exit our window properly on close event.
#[allow(dead_code)]
pub unsafe extern "system" fn window_proc(h_wnd: HWND, msg: UINT, w_param: WPARAM, l_param: LPARAM) -> LRESULT {
	if msg == winapi::winuser::WM_DESTROY {
		user32::PostQuitMessage(0);
	}

	match msg {
		winapi::winuser::WM_DESTROY => user32::PostQuitMessage(0),
		winapi::winuser::WM_MOUSEMOVE => 0 as LRESULT,
		winapi::winuser::WM_LBUTTONDOWN => 0 as LRESULT,
		winapi::winuser::WM_LBUTTONUP => 0 as LRESULT,
		_ => user32::DefWindowProcW(h_wnd, msg, w_param, l_param),
	}
}

// The following function hides the Console Window since we are building a GUI application.
#[allow(dead_code)]
fn hide_console_window() {
	let window = unsafe {
		kernel32::GetConsoleWindow()
	};

	if window != std::ptr::null_mut() {
		unsafe {
			user32::ShowWindow(window, winapi::SW_HIDE)
		};
	}
}

fn normalize_coords(rect: Rectangle) -> Rectangle {
    let Rectangle{mut x, mut y, mut x2, mut y2} = rect;

    if x > x2 {
        let tmp = x;
        x = x2;
        x2 = tmp;
    }
    if y > y2 {
        let tmp = y;
        y = y2;
        y2 = tmp;
    }

    Rectangle{x: x, y: y, x2: x2, y2: y2}
}

fn get_screen_rect() -> Rectangle {
	Rectangle{
		x /* left */: user32::GetSystemMetrics(winapi::winuser::SM_XVIRTUALSCREEN),
		y /* top */: user32::GetSystemMetrics(winapi::winuser::SM_YVIRTUALSCREEN),
		x2 /* right */: user32::GetSystemMetrics(winapi::winuser::SM_CXVIRTUALSCREEN) + user32::GetSystemMetrics(winapi::winuser::SM_XVIRTUALSCREEN),
		y2 /* bottom */: user32::GetSystemMetrics(winapi::winuser::SM_CYVIRTUALSCREEN) + user32::GetSystemMetrics(winapi::winuser::SM_CYVIRTUALSCREEN),
	}
}

fn capture_screen_clipboard(hwnd: HWND, mut rect: Rectangle) -> bool {
	// normalize coordinates
	let rect = normalize_coords(rect);
	let w = rect.x2 - rect.x;
	let h = rect.y2 - rect.y;

	let screen_dc = user32::GetDC(0 as HWND);
	let shot_dc = gdi32::CreateCompatibleDC(screen_dc);
	let shot_bitmap = gdi32::CreateCompatibleBitmap(screen_dc, w, h);
	let old_obj = gdi32::SelectObject(shot_dc, shot_bitmap);

	if !gdi32::BitBlt(shot_dc, 0, 0, w, h, screen_dc, rect.x, rect.y, 0 as DWORD) {
		println!("{:?}", "BitBlt failed? Perhaps.");
		false
	}

	let mut ret = false;
	if user32::OpenClipboard(hwnd) {
		if user32::EmptyClipboard() {
			if user32::SetClipboardData(CF_BITMAP, shot_bitmap) {
				ret = true;
			}
			user32::CloseClipboard();
		}
	} else {
		println!("{:?}", "could not open clipboard");
	}

	// Clean up
	gdi32::DeleteDC(shot_dc);
	gdi32::DeleteDC(screen_dc);
	gdi32::SelectObject(shot_dc, old_obj);

	return ret;
}

fn main() {
	unsafe {
		let hInstance = kernel32::GetModuleHandleW(0 as LPCWSTR);
		let m_class_name = to_wstring(g_class_name);
		let wnd = WNDCLASSW {
			hInstance: hInstance,
			lpszClassName: m_class_name,
			lpszMenuName: 0 as LPCWSTR,
			lpfnWndProc: Some(window_proc),
			cbClsExtra: 0,
			cbWndExtra: 0,
			style: winapi::winuser::CS_HREDRAW | winapi::winuser::CS_VREDRAW,
			hbrBackground: 0,
			hCursor: user32::LoadCursorW(0 as HINSTANCE, winapi::winuser::IDC_CROSS),
			hIcon: user32::LoadIconW(0 as HINSTANCE, winapi::winuser::IDI_APPLICATION),
		};

		user32::RegisterClassW(&wnd);
		let rect = get_screen_rect();
		let exstyle = winapi::winuser::WS_EX_TRANSPARENT;
		let style = winapi::winuser::WS_POPUP;

		let win = user32::CreateWindowExW(exstyle,
			m_class_name,
			m_class_name,
			style,
			// dimensions
			0, 0, rect.x2, rect.y2,
			0, // no parent
			0, // no menu
			hInstance, // module_instance
			0 as LPARAM,
		);

		user32::ShowWindow(win, winapi::winuser::SW_SHOW);
		user32::ShowWindow(win, winapi::winuser::SW_SHOWMAXIMIZED);
		user32::SetForegroundWindow(win);

		capture_screen_clipboard(win, Rectangle{
			x: 0,
			y: 0,
			x2: 200,
			y2: 200,
		});
		user32::DestroyWindow(win);
	}
}

// fn main() {
// 	// Here our unsafe code goes
// 	unsafe {
// 		// First we hide the console window
// 		hide_console_window();

// 		// Then we initialize the WNDCLASS structure
// 		let m_class_name = to_wstring(g_class_name);
// 		let wnd = WNDCLASSW {
// 			hInstance: 0 as HINSTANCE,
// 			lpszClassName = m_class_name,
// 			lpszMenuName: 0 as LPCWSTR,
// 			lpfnWndProc: Some(window_proc),

// 			style: winapi::winuser::CS_HREDRAW | winapi::winuser::CS_VREDRAW,

// 			cbClsExtra: 0,
// 			cbWndExtra: 0,

// 			hIcon: user32::LoadIconW(0 as HINSTANCE, winapi::winuser::IDI_APPLICATION),
// 			hCursor: user32::LoadCursorW(0 as HINSTANCE, winapi::winuser::IDI_APPLICATION),
// 			hbrBackground: 16 as HBRUSH,

// 		};

// 		// Register our class
// 		user32::RegisterClassW(&wnd);

// 		let h_wnd_desktop = user32::GetDesktopWindow();

// 		user32::CreateWindowExA(0, "my_window".as_ptr() as *mut _,
// 			"Simple Window".as_ptr() as *mut _, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
// 			0, 0, 400, 400, h_wnd_desktop, 0 as HMENU, 0 as HINSTANCE,
// 			std::ptr::null_mut());

// 		let mut msg = winapi::winuser::MSG {
// 			hwnd: 0 as HWND,
// 			message: 0 as UINT,
// 			wParam: 0 as WPARAM,
// 			lParam: 0 as LPARAM,
// 			time: 0 as DWORD,
// 			pt : winapi::windef::POINT{ x: 0, y: 0, },
// 		};

// 		// Kick off the application loop
// 		loop {
// 			let pm = user32::PeekMessageW(&mut msg, 0 as HWND, 0, 0, winapi::winuser::PM_REMOVE);

// 			if pm == 0 {
// 				continue;
// 			}

// 			if msg.message == winapi::winuser::WM_QUIT {
// 				break;
// 			}

// 			user32::TranslateMessage(&mut msg);
// 			user32::DispatchMessageW(&mut msg);
// 		}
// 	}
// }<commit_msg>Interesting<commit_after>extern crate kernel32;
extern crate user32;
extern crate winapi;
extern crate libc;
extern crate gdi32;

use winapi::windef::HWND;
use winapi::windef::HMENU;
use winapi::windef::HBRUSH;
use winapi::minwindef::HINSTANCE;

use winapi::minwindef::UINT;
use winapi::minwindef::DWORD;
use winapi::minwindef::WPARAM;
use winapi::minwindef::LPARAM;
use winapi::minwindef::LRESULT;
use winapi::winnt::LPCWSTR;

use winapi::winuser::WS_OVERLAPPEDWINDOW;
use winapi::winuser::WS_VISIBLE;
use winapi::winuser::WNDCLASSW;
use winapi::winuser::CF_BITMAP;

use std::os::windows::ffi::OsStrExt;
use std::ffi::OsStr;

const g_class_name: &'static str = "winshot";

// Rectangle represents screen coordinates
struct Rectangle {
	x: i32,
	y: i32,
	x2: i32,
	y2: i32,
}

// convert normal string to wide string
#[allow(dead_code)]
fn to_wstring(str: &str) -> *const u16 {
	let v: Vec<u16> = OsStr::new(str).encode_wide() . chain(Some(0).into_iter()).collect();
	v.as_ptr()
}

// This is our window message handler function. Currently,
// it only processes the WM_DESTROY message to exit our window properly on close event.
#[allow(dead_code)]
pub unsafe extern "system" fn window_proc(h_wnd: HWND, msg: UINT, w_param: WPARAM, l_param: LPARAM) -> LRESULT {
	if msg == winapi::winuser::WM_DESTROY {
		user32::PostQuitMessage(0);
	} else if msg == winapi::winuser::WM_MOUSEMOVE {
		return 0 as LRESULT;
	} else if msg == winapi::winuser::WM_LBUTTONDOWN {
		return 0 as LRESULT;
	} else if msg == winapi::winuser::WM_LBUTTONUP {
		return 0 as LRESULT;
	} else {
		return user32::DefWindowProcW(h_wnd, msg, w_param, l_param);
	}
}

// The following function hides the Console Window since we are building a GUI application.
#[allow(dead_code)]
fn hide_console_window() {
	let window = unsafe {
		kernel32::GetConsoleWindow()
	};

	if window != std::ptr::null_mut() {
		unsafe {
			user32::ShowWindow(window, winapi::SW_HIDE)
		};
	}
}

fn normalize_coords(rect: Rectangle) -> Rectangle {
    let Rectangle{mut x, mut y, mut x2, mut y2} = rect;

    if x > x2 {
        let tmp = x;
        x = x2;
        x2 = tmp;
    }
    if y > y2 {
        let tmp = y;
        y = y2;
        y2 = tmp;
    }

    Rectangle{x: x, y: y, x2: x2, y2: y2}
}

fn get_screen_rect() -> Rectangle {
	Rectangle{
		x /* left */: user32::GetSystemMetrics(winapi::winuser::SM_XVIRTUALSCREEN),
		y /* top */: user32::GetSystemMetrics(winapi::winuser::SM_YVIRTUALSCREEN),
		x2 /* right */: user32::GetSystemMetrics(winapi::winuser::SM_CXVIRTUALSCREEN) + user32::GetSystemMetrics(winapi::winuser::SM_XVIRTUALSCREEN),
		y2 /* bottom */: user32::GetSystemMetrics(winapi::winuser::SM_CYVIRTUALSCREEN) + user32::GetSystemMetrics(winapi::winuser::SM_CYVIRTUALSCREEN),
	}
}

fn capture_screen_clipboard(hwnd: HWND, mut rect: Rectangle) -> bool {
	// normalize coordinates
	let rect = normalize_coords(rect);
	let w = rect.x2 - rect.x;
	let h = rect.y2 - rect.y;

	let screen_dc = user32::GetDC(0 as HWND);
	let shot_dc = gdi32::CreateCompatibleDC(screen_dc);
	let shot_bitmap = gdi32::CreateCompatibleBitmap(screen_dc, w, h);
	let old_obj = gdi32::SelectObject(shot_dc, shot_bitmap);

	if !gdi32::BitBlt(shot_dc, 0, 0, w, h, screen_dc, rect.x, rect.y, 0 as DWORD) {
		println!("{:?}", "BitBlt failed? Perhaps.");
		false
	}

	let mut ret = false;
	if user32::OpenClipboard(hwnd) {
		if user32::EmptyClipboard() {
			if user32::SetClipboardData(CF_BITMAP, shot_bitmap) {
				ret = true;
			}
			user32::CloseClipboard();
		}
	} else {
		println!("{:?}", "could not open clipboard");
	}

	// Clean up
	gdi32::DeleteDC(shot_dc);
	gdi32::DeleteDC(screen_dc);
	gdi32::SelectObject(shot_dc, old_obj);

	return ret;
}

fn main() {
	unsafe {
		let hInstance = kernel32::GetModuleHandleW(0 as LPCWSTR);
		let m_class_name = to_wstring(g_class_name);
		let wnd = WNDCLASSW {
			hInstance: hInstance,
			lpszClassName: m_class_name,
			lpszMenuName: 0 as LPCWSTR,
			lpfnWndProc: Some(window_proc),
			cbClsExtra: 0,
			cbWndExtra: 0,
			style: winapi::winuser::CS_HREDRAW | winapi::winuser::CS_VREDRAW,
			hbrBackground: 0,
			hCursor: user32::LoadCursorW(0 as HINSTANCE, winapi::winuser::IDC_CROSS),
			hIcon: user32::LoadIconW(0 as HINSTANCE, winapi::winuser::IDI_APPLICATION),
		};

		user32::RegisterClassW(&wnd);
		let rect = get_screen_rect();
		let exstyle = winapi::winuser::WS_EX_TRANSPARENT;
		let style = winapi::winuser::WS_POPUP;

		let win = user32::CreateWindowExW(exstyle,
			m_class_name,
			m_class_name,
			style,
			// dimensions
			0, 0, rect.x2, rect.y2,
			0, // no parent
			0, // no menu
			hInstance, // module_instance
			0 as LPARAM,
		);

		user32::ShowWindow(win, winapi::winuser::SW_SHOW);
		user32::ShowWindow(win, winapi::winuser::SW_SHOWMAXIMIZED);
		user32::SetForegroundWindow(win);

		capture_screen_clipboard(win, Rectangle{
			x: 0,
			y: 0,
			x2: 200,
			y2: 200,
		});
		user32::DestroyWindow(win);
	}
}

// fn main() {
// 	// Here our unsafe code goes
// 	unsafe {
// 		// First we hide the console window
// 		hide_console_window();

// 		// Then we initialize the WNDCLASS structure
// 		let m_class_name = to_wstring(g_class_name);
// 		let wnd = WNDCLASSW {
// 			hInstance: 0 as HINSTANCE,
// 			lpszClassName = m_class_name,
// 			lpszMenuName: 0 as LPCWSTR,
// 			lpfnWndProc: Some(window_proc),

// 			style: winapi::winuser::CS_HREDRAW | winapi::winuser::CS_VREDRAW,

// 			cbClsExtra: 0,
// 			cbWndExtra: 0,

// 			hIcon: user32::LoadIconW(0 as HINSTANCE, winapi::winuser::IDI_APPLICATION),
// 			hCursor: user32::LoadCursorW(0 as HINSTANCE, winapi::winuser::IDI_APPLICATION),
// 			hbrBackground: 16 as HBRUSH,

// 		};

// 		// Register our class
// 		user32::RegisterClassW(&wnd);

// 		let h_wnd_desktop = user32::GetDesktopWindow();

// 		user32::CreateWindowExA(0, "my_window".as_ptr() as *mut _,
// 			"Simple Window".as_ptr() as *mut _, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
// 			0, 0, 400, 400, h_wnd_desktop, 0 as HMENU, 0 as HINSTANCE,
// 			std::ptr::null_mut());

// 		let mut msg = winapi::winuser::MSG {
// 			hwnd: 0 as HWND,
// 			message: 0 as UINT,
// 			wParam: 0 as WPARAM,
// 			lParam: 0 as LPARAM,
// 			time: 0 as DWORD,
// 			pt : winapi::windef::POINT{ x: 0, y: 0, },
// 		};

// 		// Kick off the application loop
// 		loop {
// 			let pm = user32::PeekMessageW(&mut msg, 0 as HWND, 0, 0, winapi::winuser::PM_REMOVE);

// 			if pm == 0 {
// 				continue;
// 			}

// 			if msg.message == winapi::winuser::WM_QUIT {
// 				break;
// 			}

// 			user32::TranslateMessage(&mut msg);
// 			user32::DispatchMessageW(&mut msg);
// 		}
// 	}
// }<|endoftext|>


<commit_before>// TODO
// generic number instead of f64 for position?

extern crate serialize;

use std::collections::TreeMap;
use serialize::json::ToJson;
use serialize::json;

/// ToGeoJson
pub trait ToGeoJson {
    // TODO: change this to return a generic GeoJSON object
    fn to_geojson(&self) -> Geometry;
}

/// Pos (alias for Positions)
///
/// [GeoJSON Format Specification § 2.1.1](http://geojson.org/geojson-spec.html#positions)
pub struct Pos(pub Vec<f64>);

impl ToJson for Pos {
    fn to_json(&self) -> json::Json {
        let &Pos(ref nums) = self;
        nums.to_json()
    }
}

impl Clone for Pos {
    fn clone(&self) -> Pos {
        let &Pos(ref nums) = self;
        Pos(nums.clone())
    }
}

/// Point
///
/// [GeoJSON Format Specification § 2.1.2](http://geojson.org/geojson-spec.html#point)
pub struct Point {
    pub coordinates: Pos,
}

impl ToJson for Point {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Point".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/// MultiPoint
///
/// [GeoJSON Format Specification § 2.1.3](http://geojson.org/geojson-spec.html#multipoint)
pub struct MultiPoint {
    pub points: Vec<Point>,
}

impl ToJson for MultiPoint {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Pos> =
            self.points.iter().map(|p| p.coordinates.clone()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiPoint".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// LineString
///
/// [GeoJSON Format Specification § 2.1.4](http://geojson.org/geojson-spec.html#linestring)
pub struct LineString {
    pub coordinates: Vec<Pos>,
}

impl ToJson for LineString {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "LineString".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/// MultiLineString
///
/// [GeoJSON Format Specification § 2.1.5](http://geojson.org/geojson-spec.html#multilinestring)
pub struct MultiLineString {
    pub line_strings: Vec<LineString>,
}

impl ToJson for MultiLineString {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Vec<Pos>> =
            self.line_strings.iter().map(|l| l.coordinates.clone()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiLineString".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// Polygon
///
/// [GeoJSON Format Specification § 2.1.6](http://geojson.org/geojson-spec.html#polygon)
pub struct Polygon {
    pub exterior: Vec<Pos>,
    pub holes: Option<Vec<Vec<Pos>>>,
}

impl Polygon {
    fn coordinates(&self) -> Vec<Vec<Pos>> {
        match self.holes {
            None => vec![self.exterior.clone()],
            Some(ref holes) => {
                let mut coordinates = holes.clone();
                coordinates.insert(0, self.exterior.clone());
                coordinates
            }
        }
    }
}

impl ToJson for Polygon {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Polygon".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates().to_json());
        d.to_json()
    }
}

/// MultiPolygon
///
/// [GeoJSON Format Specification § 2.1.7](http://geojson.org/geojson-spec.html#multipolygon)
pub struct MultiPolygon {
    pub polygons: Vec<Polygon>,
}

impl ToJson for MultiPolygon {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Vec<Vec<Pos>>> =
            self.polygons.iter().map(|p| p.coordinates()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiPolygon".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// Geometry
pub enum Geometry {
    Point(Point),
    MultiPoint(MultiPoint),
    LineString(LineString),
    MultiLineString(MultiLineString),
    Polygon(Polygon),
    MultiPolygon(MultiPolygon),
    GeometryCollection(GeometryCollection),
}

impl ToJson for Geometry {
    fn to_json(&self) -> json::Json {
        match *self {
            Geometry::Point(ref geom) => geom.to_json(),
            Geometry::MultiPoint(ref geom) => geom.to_json(),
            Geometry::LineString(ref geom) => geom.to_json(),
            Geometry::MultiLineString(ref geom) => geom.to_json(),
            Geometry::Polygon(ref geom) => geom.to_json(),
            Geometry::MultiPolygon(ref geom) => geom.to_json(),
            Geometry::GeometryCollection(ref geom) => geom.to_json(),
        }
    }
}

/// GeometryCollection
///
/// [GeoJSON Format Specification § 2.1.8](http://geojson.org/geojson-spec.html#geometry-collection)
pub struct GeometryCollection {
    geometries: Vec<Geometry>,
}

impl ToJson for GeometryCollection {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "GeometryCollection".to_string().to_json());
        d.insert("geometries".to_string(), self.geometries.to_json());
        d.to_json()
    }
}

/// Feature
///
/// [GeoJSON Format Specification § 2.2](http://geojson.org/geojson-spec.html#feature-objects)
pub struct Feature {
    geometry: Geometry,
    properties: json::Json,
}

impl ToJson for Feature {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Feature".to_string().to_json());
        d.insert("geometry".to_string(), self.geometry.to_json());
        d.insert("properties".to_string(), self.properties.to_json());
        d.to_json()
    }
}

/// FeatureCollection
///
/// [GeoJSON Format Specification § 2.3](http://geojson.org/geojson-spec.html#feature-collection-objects)
pub struct FeatureCollection {
    features: Vec<Feature>,
}

impl ToJson for FeatureCollection {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "FeatureCollection".to_string().to_json());
        d.insert("features".to_string(), self.features.to_json());
        d.to_json()
    }
}

fn main() {
    let point = Point {coordinates: Pos(vec![1., 2., 3.])};

    let j: json::Json = point.to_json();
    let s: String = j.to_pretty_str();

    println!("{}", s);
}
<commit_msg>Simplify imports<commit_after>// TODO
// generic number instead of f64 for position?

extern crate serialize;

use std::collections::TreeMap;
use serialize::json::{mod, ToJson};

/// ToGeoJson
pub trait ToGeoJson {
    // TODO: change this to return a generic GeoJSON object
    fn to_geojson(&self) -> Geometry;
}

/// Pos (alias for Positions)
///
/// [GeoJSON Format Specification § 2.1.1](http://geojson.org/geojson-spec.html#positions)
pub struct Pos(pub Vec<f64>);

impl ToJson for Pos {
    fn to_json(&self) -> json::Json {
        let &Pos(ref nums) = self;
        nums.to_json()
    }
}

impl Clone for Pos {
    fn clone(&self) -> Pos {
        let &Pos(ref nums) = self;
        Pos(nums.clone())
    }
}

/// Point
///
/// [GeoJSON Format Specification § 2.1.2](http://geojson.org/geojson-spec.html#point)
pub struct Point {
    pub coordinates: Pos,
}

impl ToJson for Point {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Point".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/// MultiPoint
///
/// [GeoJSON Format Specification § 2.1.3](http://geojson.org/geojson-spec.html#multipoint)
pub struct MultiPoint {
    pub points: Vec<Point>,
}

impl ToJson for MultiPoint {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Pos> =
            self.points.iter().map(|p| p.coordinates.clone()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiPoint".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// LineString
///
/// [GeoJSON Format Specification § 2.1.4](http://geojson.org/geojson-spec.html#linestring)
pub struct LineString {
    pub coordinates: Vec<Pos>,
}

impl ToJson for LineString {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "LineString".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/// MultiLineString
///
/// [GeoJSON Format Specification § 2.1.5](http://geojson.org/geojson-spec.html#multilinestring)
pub struct MultiLineString {
    pub line_strings: Vec<LineString>,
}

impl ToJson for MultiLineString {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Vec<Pos>> =
            self.line_strings.iter().map(|l| l.coordinates.clone()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiLineString".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// Polygon
///
/// [GeoJSON Format Specification § 2.1.6](http://geojson.org/geojson-spec.html#polygon)
pub struct Polygon {
    pub exterior: Vec<Pos>,
    pub holes: Option<Vec<Vec<Pos>>>,
}

impl Polygon {
    fn coordinates(&self) -> Vec<Vec<Pos>> {
        match self.holes {
            None => vec![self.exterior.clone()],
            Some(ref holes) => {
                let mut coordinates = holes.clone();
                coordinates.insert(0, self.exterior.clone());
                coordinates
            }
        }
    }
}

impl ToJson for Polygon {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Polygon".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates().to_json());
        d.to_json()
    }
}

/// MultiPolygon
///
/// [GeoJSON Format Specification § 2.1.7](http://geojson.org/geojson-spec.html#multipolygon)
pub struct MultiPolygon {
    pub polygons: Vec<Polygon>,
}

impl ToJson for MultiPolygon {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Vec<Vec<Pos>>> =
            self.polygons.iter().map(|p| p.coordinates()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiPolygon".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// Geometry
pub enum Geometry {
    Point(Point),
    MultiPoint(MultiPoint),
    LineString(LineString),
    MultiLineString(MultiLineString),
    Polygon(Polygon),
    MultiPolygon(MultiPolygon),
    GeometryCollection(GeometryCollection),
}

impl ToJson for Geometry {
    fn to_json(&self) -> json::Json {
        match *self {
            Geometry::Point(ref geom) => geom.to_json(),
            Geometry::MultiPoint(ref geom) => geom.to_json(),
            Geometry::LineString(ref geom) => geom.to_json(),
            Geometry::MultiLineString(ref geom) => geom.to_json(),
            Geometry::Polygon(ref geom) => geom.to_json(),
            Geometry::MultiPolygon(ref geom) => geom.to_json(),
            Geometry::GeometryCollection(ref geom) => geom.to_json(),
        }
    }
}

/// GeometryCollection
///
/// [GeoJSON Format Specification § 2.1.8](http://geojson.org/geojson-spec.html#geometry-collection)
pub struct GeometryCollection {
    geometries: Vec<Geometry>,
}

impl ToJson for GeometryCollection {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "GeometryCollection".to_string().to_json());
        d.insert("geometries".to_string(), self.geometries.to_json());
        d.to_json()
    }
}

/// Feature
///
/// [GeoJSON Format Specification § 2.2](http://geojson.org/geojson-spec.html#feature-objects)
pub struct Feature {
    geometry: Geometry,
    properties: json::Json,
}

impl ToJson for Feature {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Feature".to_string().to_json());
        d.insert("geometry".to_string(), self.geometry.to_json());
        d.insert("properties".to_string(), self.properties.to_json());
        d.to_json()
    }
}

/// FeatureCollection
///
/// [GeoJSON Format Specification § 2.3](http://geojson.org/geojson-spec.html#feature-collection-objects)
pub struct FeatureCollection {
    features: Vec<Feature>,
}

impl ToJson for FeatureCollection {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "FeatureCollection".to_string().to_json());
        d.insert("features".to_string(), self.features.to_json());
        d.to_json()
    }
}

fn main() {
    let point = Point {coordinates: Pos(vec![1., 2., 3.])};

    let j: json::Json = point.to_json();
    let s: String = j.to_pretty_str();

    println!("{}", s);
}
<|endoftext|>


<commit_before>// TODO: many items from tokio-core::io have been deprecated in favour of tokio-io
#![allow(deprecated)]

#[cfg(debug_assertions)]
#[macro_use] extern crate log;
#[cfg(debug_assertions)]
extern crate env_logger;
extern crate futures;
extern crate getopts;
extern crate librespot;
extern crate tokio_core;
extern crate tokio_signal;

#[cfg(debug_assertions)]
use env_logger::LogBuilder;
use futures::{Future, Async, Poll, Stream};
#[cfg(debug_assertions)]
use std::env;
use std::io::{self, stderr, Write};
use std::path::PathBuf;
use std::process::exit;
use tokio_core::reactor::{Handle, Core};
use tokio_core::io::IoStream;
use std::mem;

use librespot::spirc::{Spirc, SpircTask};
use librespot::authentication::{get_credentials, Credentials};
#[cfg(not(target_os="windows"))]
use librespot::authentication::discovery::{discovery, DiscoveryStream};
use librespot::audio_backend;
use librespot::cache::Cache;
use librespot::player::Player;
use librespot::session::{Bitrate, Config, Session};
use librespot::mixer;
use librespot::util::SpotifyId;

const VERSION: &'static str = concat!(env!("CARGO_PKG_NAME"), " v", env!("CARGO_PKG_VERSION"));

fn usage(program: &str, opts: &getopts::Options) -> String {
	println!("{}", VERSION.to_string());

	let brief = format!("Usage: {} [options]", program);
	opts.usage(&brief)
}

#[cfg(debug_assertions)]
fn setup_logging(verbose: bool) {
	let mut builder = LogBuilder::new();
	match env::var("RUST_LOG") {
		Ok(config) => {
			builder.parse(&config);
			builder.init().unwrap();

			if verbose {
				warn!("`--verbose` flag overidden by `RUST_LOG` environment variable");
			}
		}
		Err(_) => {
			if verbose {
				builder.parse("mdns=info,librespot=trace");
			} else {
				builder.parse("mdns=error,librespot=warn");
			}
			builder.init().unwrap();
		}
	}
}

#[derive(Clone)]
struct Setup {
	name: String,
	cache: Option<Cache>,
	config: Config,
	credentials: Option<Credentials>,
	authenticate: bool,
	enable_discovery: bool,

	get_token: bool,
	client_id: Option<String>,
	scope: Option<String>,

	single_track: Option<String>,
	start_position: u32,
}

fn setup(args: &[String]) -> Setup {
	let mut opts = getopts::Options::new();
	opts.optopt("c", "cache", "Path to a directory where files will be cached.", "CACHE")
		.reqopt("n", "name", "Device name", "NAME")
		.optopt("", "onstart", "Run PROGRAM when playback is about to begin.", "PROGRAM")
		.optopt("", "onstop", "Run PROGRAM when playback has ended.", "PROGRAM")
		.optopt("", "single-track", "Play a single track ID and exit.", "ID")
		.optopt("", "start-position", "Position (in ms) where playback should be started. Only valid with the --single-track option.", "STARTPOSITION")
		.optopt("u", "username", "Username to sign in with", "USERNAME")
		.optopt("p", "password", "Password", "PASSWORD")
		.optflag("a", "authenticate", "Authenticate given username and password. Make sure you define a cache folder to store credentials.")
		.optflag("", "disable-discovery", "Disable discovery mode")
		.optflag("t", "get-token", "Get oauth token to be used with the web API etc.")
		.optopt("i", "client-id", "A Spotify client_id to be used to get the oauth token. Required with the --get-token request.", "CLIENT_ID")
		.optopt("", "scope", "The scopes you want to have access to with the oauth token.", "SCOPE")
		.optflag("x", "check", "Run quick internal check");

	#[cfg(debug_assertions)]
	opts.optflag("v", "verbose", "Enable verbose output");

	let matches = match opts.parse(&args[1..]) {
		Ok(m) => m,
		Err(f) => {
			writeln!(stderr(), "error: {}\n{}", f.to_string(), usage(&args[0], &opts)).unwrap();
			exit(1);
		}
	};

	if matches.opt_present("check") {
		println!("ok {}", VERSION.to_string());
		exit(1);
	}

	#[cfg(debug_assertions)]
	{
		let verbose = matches.opt_present("verbose");
		setup_logging(verbose);
	}

	let name = matches.opt_str("name").unwrap();
	let device_id = librespot::session::device_id(&name);

	let cache = matches.opt_str("c").map(|cache_location| {
		Cache::new(PathBuf::from(cache_location))
	});

	let cached_credentials = cache.as_ref().and_then(Cache::credentials);

	let credentials = get_credentials(matches.opt_str("username"), matches.opt_str("password"), cached_credentials);

	let authenticate = matches.opt_present("authenticate");

#[cfg(not(target_os="windows"))]
	let enable_discovery = !matches.opt_present("disable-discovery");
#[cfg(target_os="windows")]
	let enable_discovery = false;

	let start_position = matches.opt_str("start-position")
		.unwrap_or("0".to_string())
		.parse().unwrap_or(0.0);

		let config = Config {
		user_agent: VERSION.to_string(),
		device_id: device_id,
		bitrate: Bitrate::Bitrate320,
		onstart: matches.opt_str("onstart"),
		onstop: matches.opt_str("onstop"),
	};

	Setup {
		name: name,
		cache: cache,
		config: config,
		credentials: credentials,
		authenticate: authenticate,
		enable_discovery: enable_discovery,

		get_token: matches.opt_present("get-token"),
		client_id: matches.opt_str("client-id"),
		scope: matches.opt_str("scope"),

		single_track: matches.opt_str("single-track"),
		start_position: (start_position * 1000.0) as u32,
	}
}

struct Main {
	name: String,
	cache: Option<Cache>,
	config: Config,
	handle: Handle,

#[cfg(not(target_os="windows"))]
	discovery: Option<DiscoveryStream>,
#[cfg(target_os="windows")]
	discovery: Option<String>,
	signal: IoStream<()>,

	spirc: Option<Spirc>,
	spirc_task: Option<SpircTask>,
	connect: Box<Future<Item=Session, Error=io::Error>>,

	player: Option<Player>,

	shutdown: bool,
	authenticate: bool,
}

impl Main {
	fn new(
		handle: Handle,
		name: String,
		config: Config,
		cache: Option<Cache>,
		authenticate: bool,
	) -> Main
	{
		Main {
			handle: handle.clone(),
			name: name,
			cache: cache,
			config: config,

			connect: Box::new(futures::future::empty()),
			discovery: None,
			spirc: None,
			spirc_task: None,

			player: None,

			shutdown: false,
			authenticate: authenticate,
			signal: tokio_signal::ctrl_c(&handle).flatten_stream().boxed(),
		}
	}

#[cfg(not(target_os="windows"))]
	fn discovery(&mut self) {
		let device_id = self.config.device_id.clone();
		let name = self.name.clone();

		self.discovery = Some(discovery(&self.handle, name, device_id).unwrap());
	}

	fn credentials(&mut self, credentials: Credentials) {
		let config = self.config.clone();
		let handle = self.handle.clone();

		let connection = Session::connect(config, credentials, self.cache.clone(), handle);

		self.connect = connection;
		self.spirc = None;
		let task = mem::replace(&mut self.spirc_task, None);
		if let Some(task) = task {
			self.handle.spawn(task);
		}
	}
}

impl Future for Main {
	type Item = ();
	type Error = ();

	fn poll(&mut self) -> Poll<(), ()> {
		loop {
			let mut progress = false;

#[cfg(not(target_os="windows"))] {
			if let Some(Async::Ready(Some(creds))) = self.discovery.as_mut().map(|d| d.poll().unwrap()) {
				if let Some(ref spirc) = self.spirc {
					spirc.shutdown();
				}
				self.credentials(creds);

				progress = true;
			}
}

			if let Async::Ready(session) = self.connect.poll().unwrap() {
				if self.authenticate {
					if !self.shutdown {
						if let Some(ref spirc) = self.spirc {
							spirc.shutdown();
						}
						self.shutdown = true;
					} else {
						return Ok(Async::Ready(()));
					}
				}
				else {
					self.connect = Box::new(futures::future::empty());

					let mixer = (mixer::find(Some("softvol")).unwrap())();

					let audio_filter = mixer.get_audio_filter();
					let backend = audio_backend::find(None).unwrap();
					let player = Player::new(session.clone(), audio_filter, move || {
						(backend)(None)
					});

					self.player = Some(player.clone());

					let (spirc, spirc_task) = Spirc::new(self.name.clone(), session, player, mixer);
					self.spirc = Some(spirc);
					self.spirc_task = Some(spirc_task);
				}

				progress = true;
			}

			if let Async::Ready(Some(())) = self.signal.poll().unwrap() {
				if !self.shutdown {
					if let Some(ref spirc) = self.spirc {
						spirc.shutdown();
					}
					self.shutdown = true;
				} else {
					return Ok(Async::Ready(()));
				}

				progress = true;
			}

			if let Some(ref mut spirc_task) = self.spirc_task {
				if let Async::Ready(()) = spirc_task.poll().unwrap() {
					if self.shutdown {
						return Ok(Async::Ready(()));
					} else {
						panic!("Spirc shut down unexpectedly");
					}
				}
			}

			if !progress {
				return Ok(Async::NotReady);
			}
		}
	}
}

fn main() {
	let mut core = Core::new().unwrap();
	let handle = core.handle();

	let args: Vec<String> = std::env::args().collect();
	let Setup { name, config, cache, enable_discovery, credentials, authenticate, get_token, client_id, scope, single_track, start_position } = setup(&args);

	if let Some(ref track_id) = single_track {
		match credentials {
			Some(credentials) => {
				let backend = audio_backend::find(None).unwrap();

				let track = SpotifyId::from_base62(
									track_id.replace("spotty://", "")
									.replace("spotify://", "")
									.replace("track:", "")
									.as_str());

				let session = core.run(Session::connect(config, credentials, None, handle)).unwrap();

				let player = Player::new(session.clone(), None, move || (backend)(None));

				core.run(player.load(track, true, start_position)).unwrap();
			}
			None => {
				println!("Missing credentials");
			}
		}
	}
	else if authenticate && !enable_discovery {
		core.run(Session::connect(config, credentials.unwrap(), cache.clone(), handle)).unwrap();
		println!("authorized");
	}
	else if get_token {
		if let Some(client_id) = client_id {
			let session = core.run(Session::connect(config, credentials.unwrap(), cache.clone(), handle)).unwrap();
			let scope = scope.unwrap_or("user-read-private,playlist-read-private,playlist-read-collaborative,playlist-modify-public,playlist-modify-private,user-follow-modify,user-follow-read,user-library-read,user-library-modify,user-top-read".to_string());
			let url = format!("hm://keymaster/token/authenticated?client_id={}&scope={}", client_id, scope);
			core.run(session.mercury().get(url).map(move |response| {
				let data = response.payload.first().expect("Empty payload");
				let token = String::from_utf8(data.clone()).unwrap();
				println!("{}", token);
			}).boxed()).unwrap();
		}
		else {
			println!("Use --client-id to provide a CLIENT_ID");
		}
	}
	else {
		let mut task = Main::new(handle, name, config, cache, authenticate);
		if enable_discovery {
#[cfg(not(target_os="windows"))]
			task.discovery();
		}
		if let Some(credentials) = credentials {
			task.credentials(credentials);
		}

		core.run(task).unwrap()
	}
}

<commit_msg>Fix parsing Spotify's track URI<commit_after>// TODO: many items from tokio-core::io have been deprecated in favour of tokio-io
#![allow(deprecated)]

#[cfg(debug_assertions)]
#[macro_use] extern crate log;
#[cfg(debug_assertions)]
extern crate env_logger;
extern crate futures;
extern crate getopts;
extern crate librespot;
extern crate tokio_core;
extern crate tokio_signal;

#[cfg(debug_assertions)]
use env_logger::LogBuilder;
use futures::{Future, Async, Poll, Stream};
#[cfg(debug_assertions)]
use std::env;
use std::io::{self, stderr, Write};
use std::path::PathBuf;
use std::process::exit;
use tokio_core::reactor::{Handle, Core};
use tokio_core::io::IoStream;
use std::mem;

use librespot::spirc::{Spirc, SpircTask};
use librespot::authentication::{get_credentials, Credentials};
#[cfg(not(target_os="windows"))]
use librespot::authentication::discovery::{discovery, DiscoveryStream};
use librespot::audio_backend;
use librespot::cache::Cache;
use librespot::player::Player;
use librespot::session::{Bitrate, Config, Session};
use librespot::mixer;
use librespot::util::SpotifyId;

const VERSION: &'static str = concat!(env!("CARGO_PKG_NAME"), " v", env!("CARGO_PKG_VERSION"));

fn usage(program: &str, opts: &getopts::Options) -> String {
	println!("{}", VERSION.to_string());

	let brief = format!("Usage: {} [options]", program);
	opts.usage(&brief)
}

#[cfg(debug_assertions)]
fn setup_logging(verbose: bool) {
	let mut builder = LogBuilder::new();
	match env::var("RUST_LOG") {
		Ok(config) => {
			builder.parse(&config);
			builder.init().unwrap();

			if verbose {
				warn!("`--verbose` flag overidden by `RUST_LOG` environment variable");
			}
		}
		Err(_) => {
			if verbose {
				builder.parse("mdns=info,librespot=trace");
			} else {
				builder.parse("mdns=error,librespot=warn");
			}
			builder.init().unwrap();
		}
	}
}

#[derive(Clone)]
struct Setup {
	name: String,
	cache: Option<Cache>,
	config: Config,
	credentials: Option<Credentials>,
	authenticate: bool,
	enable_discovery: bool,

	get_token: bool,
	client_id: Option<String>,
	scope: Option<String>,

	single_track: Option<String>,
	start_position: u32,
}

fn setup(args: &[String]) -> Setup {
	let mut opts = getopts::Options::new();
	opts.optopt("c", "cache", "Path to a directory where files will be cached.", "CACHE")
		.reqopt("n", "name", "Device name", "NAME")
		.optopt("", "onstart", "Run PROGRAM when playback is about to begin.", "PROGRAM")
		.optopt("", "onstop", "Run PROGRAM when playback has ended.", "PROGRAM")
		.optopt("", "single-track", "Play a single track ID and exit.", "ID")
		.optopt("", "start-position", "Position (in ms) where playback should be started. Only valid with the --single-track option.", "STARTPOSITION")
		.optopt("u", "username", "Username to sign in with", "USERNAME")
		.optopt("p", "password", "Password", "PASSWORD")
		.optflag("a", "authenticate", "Authenticate given username and password. Make sure you define a cache folder to store credentials.")
		.optflag("", "disable-discovery", "Disable discovery mode")
		.optflag("t", "get-token", "Get oauth token to be used with the web API etc.")
		.optopt("i", "client-id", "A Spotify client_id to be used to get the oauth token. Required with the --get-token request.", "CLIENT_ID")
		.optopt("", "scope", "The scopes you want to have access to with the oauth token.", "SCOPE")
		.optflag("x", "check", "Run quick internal check");

	#[cfg(debug_assertions)]
	opts.optflag("v", "verbose", "Enable verbose output");

	let matches = match opts.parse(&args[1..]) {
		Ok(m) => m,
		Err(f) => {
			writeln!(stderr(), "error: {}\n{}", f.to_string(), usage(&args[0], &opts)).unwrap();
			exit(1);
		}
	};

	if matches.opt_present("check") {
		println!("ok {}", VERSION.to_string());
		exit(1);
	}

	#[cfg(debug_assertions)]
	{
		let verbose = matches.opt_present("verbose");
		setup_logging(verbose);
	}

	let name = matches.opt_str("name").unwrap();
	let device_id = librespot::session::device_id(&name);

	let cache = matches.opt_str("c").map(|cache_location| {
		Cache::new(PathBuf::from(cache_location))
	});

	let cached_credentials = cache.as_ref().and_then(Cache::credentials);

	let credentials = get_credentials(matches.opt_str("username"), matches.opt_str("password"), cached_credentials);

	let authenticate = matches.opt_present("authenticate");

#[cfg(not(target_os="windows"))]
	let enable_discovery = !matches.opt_present("disable-discovery");
#[cfg(target_os="windows")]
	let enable_discovery = false;

	let start_position = matches.opt_str("start-position")
		.unwrap_or("0".to_string())
		.parse().unwrap_or(0.0);

		let config = Config {
		user_agent: VERSION.to_string(),
		device_id: device_id,
		bitrate: Bitrate::Bitrate320,
		onstart: matches.opt_str("onstart"),
		onstop: matches.opt_str("onstop"),
	};

	Setup {
		name: name,
		cache: cache,
		config: config,
		credentials: credentials,
		authenticate: authenticate,
		enable_discovery: enable_discovery,

		get_token: matches.opt_present("get-token"),
		client_id: matches.opt_str("client-id"),
		scope: matches.opt_str("scope"),

		single_track: matches.opt_str("single-track"),
		start_position: (start_position * 1000.0) as u32,
	}
}

struct Main {
	name: String,
	cache: Option<Cache>,
	config: Config,
	handle: Handle,

#[cfg(not(target_os="windows"))]
	discovery: Option<DiscoveryStream>,
#[cfg(target_os="windows")]
	discovery: Option<String>,
	signal: IoStream<()>,

	spirc: Option<Spirc>,
	spirc_task: Option<SpircTask>,
	connect: Box<Future<Item=Session, Error=io::Error>>,

	player: Option<Player>,

	shutdown: bool,
	authenticate: bool,
}

impl Main {
	fn new(
		handle: Handle,
		name: String,
		config: Config,
		cache: Option<Cache>,
		authenticate: bool,
	) -> Main
	{
		Main {
			handle: handle.clone(),
			name: name,
			cache: cache,
			config: config,

			connect: Box::new(futures::future::empty()),
			discovery: None,
			spirc: None,
			spirc_task: None,

			player: None,

			shutdown: false,
			authenticate: authenticate,
			signal: tokio_signal::ctrl_c(&handle).flatten_stream().boxed(),
		}
	}

#[cfg(not(target_os="windows"))]
	fn discovery(&mut self) {
		let device_id = self.config.device_id.clone();
		let name = self.name.clone();

		self.discovery = Some(discovery(&self.handle, name, device_id).unwrap());
	}

	fn credentials(&mut self, credentials: Credentials) {
		let config = self.config.clone();
		let handle = self.handle.clone();

		let connection = Session::connect(config, credentials, self.cache.clone(), handle);

		self.connect = connection;
		self.spirc = None;
		let task = mem::replace(&mut self.spirc_task, None);
		if let Some(task) = task {
			self.handle.spawn(task);
		}
	}
}

impl Future for Main {
	type Item = ();
	type Error = ();

	fn poll(&mut self) -> Poll<(), ()> {
		loop {
			let mut progress = false;

#[cfg(not(target_os="windows"))] {
			if let Some(Async::Ready(Some(creds))) = self.discovery.as_mut().map(|d| d.poll().unwrap()) {
				if let Some(ref spirc) = self.spirc {
					spirc.shutdown();
				}
				self.credentials(creds);

				progress = true;
			}
}

			if let Async::Ready(session) = self.connect.poll().unwrap() {
				if self.authenticate {
					if !self.shutdown {
						if let Some(ref spirc) = self.spirc {
							spirc.shutdown();
						}
						self.shutdown = true;
					} else {
						return Ok(Async::Ready(()));
					}
				}
				else {
					self.connect = Box::new(futures::future::empty());

					let mixer = (mixer::find(Some("softvol")).unwrap())();

					let audio_filter = mixer.get_audio_filter();
					let backend = audio_backend::find(None).unwrap();
					let player = Player::new(session.clone(), audio_filter, move || {
						(backend)(None)
					});

					self.player = Some(player.clone());

					let (spirc, spirc_task) = Spirc::new(self.name.clone(), session, player, mixer);
					self.spirc = Some(spirc);
					self.spirc_task = Some(spirc_task);
				}

				progress = true;
			}

			if let Async::Ready(Some(())) = self.signal.poll().unwrap() {
				if !self.shutdown {
					if let Some(ref spirc) = self.spirc {
						spirc.shutdown();
					}
					self.shutdown = true;
				} else {
					return Ok(Async::Ready(()));
				}

				progress = true;
			}

			if let Some(ref mut spirc_task) = self.spirc_task {
				if let Async::Ready(()) = spirc_task.poll().unwrap() {
					if self.shutdown {
						return Ok(Async::Ready(()));
					} else {
						panic!("Spirc shut down unexpectedly");
					}
				}
			}

			if !progress {
				return Ok(Async::NotReady);
			}
		}
	}
}

fn main() {
	let mut core = Core::new().unwrap();
	let handle = core.handle();

	let args: Vec<String> = std::env::args().collect();
	let Setup { name, config, cache, enable_discovery, credentials, authenticate, get_token, client_id, scope, single_track, start_position } = setup(&args);

	if let Some(ref track_id) = single_track {
		match credentials {
			Some(credentials) => {
				let backend = audio_backend::find(None).unwrap();

				let track = SpotifyId::from_base62(
									track_id.replace("spotty://", "")
									.replace("spotify://", "")
									.replace("spotify:", "")
									.replace("track:", "")
									.as_str());

				let session = core.run(Session::connect(config, credentials, None, handle)).unwrap();

				let player = Player::new(session.clone(), None, move || (backend)(None));

				core.run(player.load(track, true, start_position)).unwrap();
			}
			None => {
				println!("Missing credentials");
			}
		}
	}
	else if authenticate && !enable_discovery {
		core.run(Session::connect(config, credentials.unwrap(), cache.clone(), handle)).unwrap();
		println!("authorized");
	}
	else if get_token {
		if let Some(client_id) = client_id {
			let session = core.run(Session::connect(config, credentials.unwrap(), cache.clone(), handle)).unwrap();
			let scope = scope.unwrap_or("user-read-private,playlist-read-private,playlist-read-collaborative,playlist-modify-public,playlist-modify-private,user-follow-modify,user-follow-read,user-library-read,user-library-modify,user-top-read".to_string());
			let url = format!("hm://keymaster/token/authenticated?client_id={}&scope={}", client_id, scope);
			core.run(session.mercury().get(url).map(move |response| {
				let data = response.payload.first().expect("Empty payload");
				let token = String::from_utf8(data.clone()).unwrap();
				println!("{}", token);
			}).boxed()).unwrap();
		}
		else {
			println!("Use --client-id to provide a CLIENT_ID");
		}
	}
	else {
		let mut task = Main::new(handle, name, config, cache, authenticate);
		if enable_discovery {
#[cfg(not(target_os="windows"))]
			task.discovery();
		}
		if let Some(credentials) = credentials {
			task.credentials(credentials);
		}

		core.run(task).unwrap()
	}
}

<|endoftext|>


<commit_before>mod coverage;
mod report;
mod parser;
mod processor;
mod command;

extern crate clap;
extern crate lcov_parser;

use clap:: { App, SubCommand, Arg };
use command:: { coverage_parser, coverage_action };

fn main() {
    let app = App::new("lcovtool")
        .version("1.0")
        .author("Noritaka Horio <holy.shared.design@gmail.com>")
        .about("LCOV report of utility tool")
        .subcommand(coverage_parser());

    let matches = app.get_matches();

    match matches.subcommand() {
        ("coverage", Some(args)) => {
            match coverage_action(args) {
                Ok(_) => { println!("ok"); },
                Err(err) => { println!("{}", err); }
            };
        },
        _ => { }
    }
}
<commit_msg>Remove struct<commit_after>mod coverage;
mod report;
mod parser;
mod processor;
mod command;

extern crate clap;
extern crate lcov_parser;

use clap:: { App };
use command:: { coverage_parser, coverage_action };

fn main() {
    let app = App::new("lcovtool")
        .version("1.0")
        .author("Noritaka Horio <holy.shared.design@gmail.com>")
        .about("LCOV report of utility tool")
        .subcommand(coverage_parser());

    let matches = app.get_matches();

    match matches.subcommand() {
        ("coverage", Some(args)) => {
            match coverage_action(args) {
                Ok(_) => { println!("ok"); },
                Err(err) => { println!("{}", err); }
            };
        },
        _ => { }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate glium;
extern crate image;
extern crate nalgebra;

mod steve;

const VERT_PROG: &'static str = include_str!("vert.glsl");

const FRAG_PROG: &'static str = include_str!("frag.glsl");

use glium::{Surface, VertexBuffer, Frame, Program};
use glium::index::NoIndices;
use glium::texture::srgb_texture2d::SrgbTexture2d;
use glium::uniforms::MagnifySamplerFilter;
use glium::draw_parameters::DepthTest;
use glium::backend::glutin_backend::GlutinFacade;
use glium::index::PrimitiveType;
use glium::glutin::Event;
use std::f32::consts::{FRAC_PI_2, PI};
use std::thread::sleep_ms;
use nalgebra::{Rot3, Iso3, Vec3, Persp3, ToHomogeneous};

fn draw_frame(target: &mut Frame, vertex_buffer: &VertexBuffer<steve::Vertex>, index_buffer: &NoIndices, shader_prog: &Program, texture: &SrgbTexture2d, t: f32) {
    target.clear_color_and_depth((0.0, 0.0, 1.0, 1.0), 1.0);

    let perspective = {
        let (width, height) = target.get_dimensions();
        let aspect_ratio = width as f32 / height as f32;
        println!("Aspect ratio: {} ({} x {})", aspect_ratio, height, width);

        let fov: f32 = 3.141592 / 3.0;
        let zfar = 1024.0;
        let znear = 0.1;

        let pmat = Persp3::new(aspect_ratio, fov, znear, zfar).to_mat();
        pmat.as_array().clone()
    };

    let rot1 = Rot3::new(Vec3::new(-FRAC_PI_2, 0.0, 0.0));
    let rot2 = Rot3::new(Vec3::new(0.0, FRAC_PI_2, 0.0));
    let rot3 = Rot3::new(Vec3::new(0.0, t, 0.0));
    let model = Iso3::new_with_rotmat(Vec3::new(0.0, 0.0, 100.0), rot3 * rot2 * rot1)
        .to_homogeneous().as_array().clone();

    let uniforms = uniform!{
        model: model,
        view:  [
            [1.0, 0.0, 0.0, 0.0],
            [0.0, 1.0, 0.0, 0.0],
            [0.0, 0.0, 1.0, 0.0],
            [0.0, 0.0, 0.0, 1.0f32],
            ],
        projection:  perspective,
        tex: texture.sampled().magnify_filter(MagnifySamplerFilter::Nearest),
    };

    let params = glium::DrawParameters {
        depth: glium::Depth {
            test: DepthTest::IfLess,
            write: true,
            .. Default::default()
        },
        .. Default::default()
    };

    target.draw(vertex_buffer, index_buffer, shader_prog, &uniforms, &params).unwrap();
}

fn mainloop(display: &GlutinFacade) {
    use std::io::Cursor;

    let vertex_buffer = VertexBuffer::new(display, &steve::VERTICES).unwrap();
    let index_buffer = NoIndices(PrimitiveType::TrianglesList);
    let shader_prog = Program::from_source(display, VERT_PROG, FRAG_PROG, None).unwrap();

    let image = image::load(Cursor::new(&include_bytes!("steve.png")[..]),
                            image::PNG).unwrap();
    let texture = SrgbTexture2d::new(display, image).unwrap();

    let mut t = -PI;

    loop {
        t += PI / 200.0;
        if t > PI {
            t = -PI;
        }
        for ev in display.poll_events() {
            match ev {
                Event::Closed => return,
                _ => ()
            }
        }

        let (width, height) = display.get_framebuffer_dimensions();
        println!("Framebuffer dimensions: {} x {}", width, height);
        let mut target = display.draw();
        draw_frame(&mut target, &vertex_buffer, &index_buffer, &shader_prog, &texture, t);
        target.finish().unwrap();
        sleep_ms(16);
    }
}

fn main() {
    use glium::{DisplayBuild, GliumCreationError};
    use glium::glutin::{WindowBuilder, GlRequest, Api, GlProfile};
    let display_option = WindowBuilder::new()
        .with_gl(GlRequest::Specific(Api::OpenGl, (3, 3)))
        .with_gl_profile(GlProfile::Core)
        .with_depth_buffer(24)
        .with_vsync()
        .build_glium();
    println!("If there was a message about an error just now, ignore it.  I think the driver's on crack.");
    match display_option {
        Ok(display) => mainloop(&display),
        Err(creation_error) => match creation_error {
            GliumCreationError::BackendCreationError(_) => println!("Oh, crap!"),
            GliumCreationError::IncompatibleOpenGl(msg) => println!("Incompatible OpenGL: {}", msg)
        }
    }
}
<commit_msg>It works!<commit_after>#[macro_use]
extern crate glium;
extern crate image;
extern crate nalgebra;

mod steve;

const VERT_PROG: &'static str = include_str!("vert.glsl");

const FRAG_PROG: &'static str = include_str!("frag.glsl");

use glium::{Surface, VertexBuffer, Frame, Program};
use glium::index::NoIndices;
use glium::texture::srgb_texture2d::SrgbTexture2d;
use glium::uniforms::MagnifySamplerFilter;
use glium::draw_parameters::DepthTest;
use glium::backend::glutin_backend::GlutinFacade;
use glium::index::PrimitiveType;
use glium::glutin::{Event, ElementState, VirtualKeyCode};
use std::f32::consts::{FRAC_PI_2, PI};
use std::thread::sleep_ms;
use nalgebra::{Rot3, Iso3, Vec3, Persp3, ToHomogeneous};

enum NextAction {
    Quit,
}

fn draw_frame(target: &mut Frame, vertex_buffer: &VertexBuffer<steve::Vertex>, index_buffer: &NoIndices, shader_prog: &Program, texture: &SrgbTexture2d, t: f32) {
    target.clear_color_and_depth((0.0, 0.0, 1.0, 1.0), 1.0);

    let perspective = {
        let (width, height) = target.get_dimensions();
        let aspect_ratio = width as f32 / height as f32;
        //println!("Aspect ratio: {} ({} x {})", aspect_ratio, height, width);

        let fov: f32 = 3.141592 / 3.0;
        let zfar = 1024.0;
        let znear = 0.1;

        let pmat = Persp3::new(aspect_ratio, fov, znear, zfar).to_mat();
        pmat.as_array().clone()
    };

    let rot1 = Rot3::new(Vec3::new(-FRAC_PI_2, 0.0, 0.0));
    let rot2 = Rot3::new(Vec3::new(0.0, FRAC_PI_2, 0.0));
    let rot3 = Rot3::new(Vec3::new(0.0, t, 0.0));
    let model = Iso3::new_with_rotmat(Vec3::new(0.0, 10.0, 100.0), rot3 * rot2 * rot1)
        .to_homogeneous().as_array().clone();

    let uniforms = uniform!{
        model: model,
        view:  [
            [1.0, 0.0, 0.0, 0.0],
            [0.0, 1.0, 0.0, 0.0],
            [0.0, 0.0, 1.0, 0.0],
            [0.0, 0.0, 0.0, 1.0f32],
            ],
        projection:  perspective,
        tex: texture.sampled().magnify_filter(MagnifySamplerFilter::Nearest),
    };

    let params = glium::DrawParameters {
        depth: glium::Depth {
            test: DepthTest::IfLess,
            write: true,
            .. Default::default()
        },
        .. Default::default()
    };

    target.draw(vertex_buffer, index_buffer, shader_prog, &uniforms, &params).unwrap();
}

fn handle_input(turn_rate: &mut f32, state: ElementState, key_char: u8, vk_opt: &Option<VirtualKeyCode>) -> Option<NextAction> {
    let mut next_action = None;
    let new_turn_rate = match *vk_opt {
        Some(vk) => match (vk, state) {
            (VirtualKeyCode::D, ElementState::Pressed)  => PI / 200.0,
            (VirtualKeyCode::A, ElementState::Pressed)  => -PI / 200.0,
            (VirtualKeyCode::D, ElementState::Released) => 0.0f32,
            (VirtualKeyCode::A, ElementState::Released) => 0.0f32,
            (VirtualKeyCode::Q, ElementState::Released) => { next_action =  Some(NextAction::Quit); 0.0f32},
            _ => 0.0f32
        },
        None => 0.0f32
    };
    *turn_rate = new_turn_rate;
    next_action
}

fn mainloop(display: &GlutinFacade) {
    use std::io::Cursor;

    let vertex_buffer = VertexBuffer::new(display, &steve::VERTICES).unwrap();
    let index_buffer = NoIndices(PrimitiveType::TrianglesList);
    let shader_prog = Program::from_source(display, VERT_PROG, FRAG_PROG, None).unwrap();

    let image = image::load(Cursor::new(&include_bytes!("steve.png")[..]),
                            image::PNG).unwrap();
    let texture = SrgbTexture2d::new(display, image).unwrap();

    let mut t = 0.0f32;
    let mut turn_rate = 0.0f32;

    loop {
        t += turn_rate;

        for ev in display.poll_events() {
            match ev {
                Event::Closed => return,
                Event::KeyboardInput(state, key_char, vk_opt) => match handle_input(&mut turn_rate, state, key_char, &vk_opt) {
                    Some(NextAction::Quit) => return,
                    None => ()
                },
                _ => ()
            }
        }

        let (width, height) = display.get_framebuffer_dimensions();
        //println!("Framebuffer dimensions: {} x {}", width, height);
        let mut target = display.draw();
        draw_frame(&mut target, &vertex_buffer, &index_buffer, &shader_prog, &texture, t);
        target.finish().unwrap();
        sleep_ms(16);
    }
}

fn main() {
    use glium::{DisplayBuild, GliumCreationError};
    use glium::glutin::{WindowBuilder, GlRequest, Api, GlProfile};
    let display_option = WindowBuilder::new()
        .with_gl(GlRequest::Specific(Api::OpenGl, (3, 3)))
        .with_gl_profile(GlProfile::Core)
        .with_depth_buffer(24)
        .with_vsync()
        .build_glium();
    println!("If there was a message about an error just now, ignore it.  I think the driver's on crack.");
    match display_option {
        Ok(display) => mainloop(&display),
        Err(creation_error) => match creation_error {
            GliumCreationError::BackendCreationError(_) => println!("Oh, crap!"),
            GliumCreationError::IncompatibleOpenGl(msg) => println!("Incompatible OpenGL: {}", msg)
        }
    }
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate toml;

extern crate rustc_serialize;
use rustc_serialize::json;

use std::io::{Read, Write};
use std::thread;

use hyper::Client;
use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;

// required JSON keys are non-snakecase
#[allow(non_snake_case)]
#[derive(RustcDecodable)]
pub struct SymbolRequest {
    memoryMap: Vec<(String,String)>,
    // TODO check that key actually fits in 8-bit int
    stacks: Vec<Vec<(i8,i64)>>,
    symbolSources: Vec<String>,
    version: u8,
}

fn main() {
    let address = "0.0.0.0:8080";

    println!("Listening on {}", address);
    Server::http(address).unwrap().handle(server).unwrap();
}

/**
  * Receives single HTTP requests and demuxes to symbols file fetches from S3 bucket.
  */
fn server(mut req: Request, mut res: Response) {
    match req.method {
        hyper::Post => {
            let mut res = res.start().unwrap();

            let mut buffer = String::new();
            let _ = req.read_to_string(&mut buffer);
            println!("DEBUG raw POST: {:?}", &buffer);
            let decoded: SymbolRequest = json::decode(&buffer).unwrap();

            println!("DEBUG decoded memoryMap: {:?}", decoded.memoryMap);
            println!("DEBUG decoded stacks: {:?}", decoded.stacks);
            println!("DEBUG decoded symbolSources: {:?}", decoded.symbolSources);
            println!("DEBUG decoded version: {}", decoded.version);

            let symbol_url = get_config("symbol_urls.public");
            let symbols = client(symbol_url, decoded.memoryMap);
            let _ = res.write_all(symbols.as_bytes());

            res.end().unwrap();
        },
        _ => { *res.status_mut() = StatusCode::MethodNotAllowed },
    }
}

/**
  * Creates multiple client connections and aggregates result.
  */
fn client(url: String, memory_map: Vec<(String,String)>) -> String {
    let mut handles = vec![];
    for (debug_file, debug_id) in memory_map {
        let pdb = debug_file.find(".pdb").unwrap();
        let (symbol_name, _) = debug_file.split_at(pdb);
        let symbol_file = format!("{}.sym", symbol_name);
        let this_url = format!("{}/{}/{}/{}", url, debug_file, debug_id, symbol_file);

        // TODO decide min/max possible threads, possibly based on number of cores?
        handles.push(thread::spawn(move || {
            let c = Client::new();
            let mut res = c.get(&this_url).send().unwrap();
            let mut body = String::new();
            let _ = res.read_to_string(&mut body);

            (symbol_file, body)
        }));
    }

    let mut result = String::new();

    for handle in handles {
        let (symbol_file, body) = handle.join().unwrap();
        for c in format!("{:?} {:?}\n", symbol_file, body).chars() {
            result.push(c);
        }
    }

    result
}

fn get_config(value_name: &str) -> String {
    // TODO move to actual file, static str for the moment
    let toml = r#"
        [symbol_urls]
        public = "https://s3-us-west-2.amazonaws.com/org.mozilla.crash-stats.symbols-public/v1"
    "#;
    // TODO support multiple URLs
    let value: toml::Value = toml.parse().unwrap();

    value.lookup(value_name).unwrap().as_str().unwrap().to_string()
}
<commit_msg>comment<commit_after>extern crate hyper;
extern crate toml;

extern crate rustc_serialize;
use rustc_serialize::json;

use std::io::{Read, Write};
use std::thread;

use hyper::Client;
use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;

// required JSON keys are non-snakecase
#[allow(non_snake_case)]
#[derive(RustcDecodable)]
pub struct SymbolRequest {
    memoryMap: Vec<(String,String)>,
    // TODO check that key actually fits in 8-bit int
    stacks: Vec<Vec<(i8,i64)>>,
    symbolSources: Vec<String>,
    version: u8,
}

fn main() {
    let address = "0.0.0.0:8080";

    println!("Listening on {}", address);
    Server::http(address).unwrap().handle(server).unwrap();
}

/**
  * Receives single HTTP requests and demuxes to symbols file fetches from S3 bucket.
  */
fn server(mut req: Request, mut res: Response) {
    match req.method {
        hyper::Post => {
            let mut res = res.start().unwrap();

            let mut buffer = String::new();
            let _ = req.read_to_string(&mut buffer);
            println!("DEBUG raw POST: {:?}", &buffer);
            let decoded: SymbolRequest = json::decode(&buffer).unwrap();

            println!("DEBUG decoded memoryMap: {:?}", decoded.memoryMap);
            println!("DEBUG decoded stacks: {:?}", decoded.stacks);
            println!("DEBUG decoded symbolSources: {:?}", decoded.symbolSources);
            println!("DEBUG decoded version: {}", decoded.version);

            let symbol_url = get_config("symbol_urls.public");
            let symbols = client(symbol_url, decoded.memoryMap);
            let _ = res.write_all(symbols.as_bytes());

            res.end().unwrap();
        },
        _ => { *res.status_mut() = StatusCode::MethodNotAllowed },
    }
}

/**
  * Creates multiple client connections and aggregates result.
  */
fn client(url: String, memory_map: Vec<(String,String)>) -> String {
    let mut handles = vec![];
    for (debug_file, debug_id) in memory_map {
        let pdb = debug_file.find(".pdb").unwrap();
        let (symbol_name, _) = debug_file.split_at(pdb);
        let symbol_file = format!("{}.sym", symbol_name);
        let this_url = format!("{}/{}/{}/{}", url, debug_file, debug_id, symbol_file);

        // TODO decide min/max possible threads, possibly based on number of cores?
        // TODO most of the time is spent waiting on I/O, maybe async would be more appropriate?
        handles.push(thread::spawn(move || {
            let c = Client::new();
            let mut res = c.get(&this_url).send().unwrap();
            let mut body = String::new();
            let _ = res.read_to_string(&mut body);

            (symbol_file, body)
        }));
    }

    let mut result = String::new();

    for handle in handles {
        let (symbol_file, body) = handle.join().unwrap();
        for c in format!("{:?} {:?}\n", symbol_file, body).chars() {
            result.push(c);
        }
    }

    result
}

fn get_config(value_name: &str) -> String {
    // TODO move to actual file, static str for the moment
    let toml = r#"
        [symbol_urls]
        public = "https://s3-us-west-2.amazonaws.com/org.mozilla.crash-stats.symbols-public/v1"
    "#;
    // TODO support multiple URLs
    let value: toml::Value = toml.parse().unwrap();

    value.lookup(value_name).unwrap().as_str().unwrap().to_string()
}
<|endoftext|>


<commit_before>#[macro_use] extern crate log;

extern crate syntax;
extern crate collections;
extern crate core;

#[cfg(not(test))]
use racer::Match;
#[cfg(not(test))]
use racer::util::getline;
#[cfg(not(test))]
use racer::nameres::{do_file_search, do_external_search};
#[cfg(not(test))]
use racer::scopes;

pub mod racer;

#[cfg(not(test))]
fn match_fn(m:Match) {
    let (linenum, charnum) = scopes::point_to_coords_from_file(&m.filepath, m.point).unwrap();
    if m.matchstr.as_slice() == "" {
        panic!("MATCHSTR is empty - waddup?");
    }
    println!("MATCH {},{},{},{},{:?},{}", m.matchstr,
                                    linenum.to_string(),
                                    charnum.to_string(),
                                    m.filepath.as_str().unwrap(),
                                    m.mtype,
                                    m.contextstr
             );
}

#[cfg(not(test))]
fn complete() {
    let args = std::os::args();
    if args.len() < 3 {
        println!("Provide more arguments!");
        print_usage();
        std::os::set_exit_status(1);
        return;
    }
    match std::os::args().as_slice()[2].as_slice().parse::<usize>() {
        Some(linenum) => {
            // input: linenum, colnum, fname
            if args.len() < 5 {
                println!("Provide more arguments!");
                print_usage();
                std::os::set_exit_status(1);
                return;
            }
            let charnum = std::os::args().as_slice()[3].as_slice().parse::<usize>().unwrap();
            let fname = args.as_slice()[4].as_slice();
            let fpath = Path::new(fname);
            let src = racer::load_file(&fpath);
            let line = getline(&fpath, linenum);
            let (start, pos) = racer::util::expand_ident(line.as_slice(), charnum);
            println!("PREFIX {},{},{}", start, pos, line.as_slice().slice(start, pos));

            let point = scopes::coords_to_point(&*src, linenum, charnum);
            for m in racer::complete_from_file(&*src, &fpath, point) {
                match_fn(m);
            }
        }
        None => {
            // input: a command line string passed in
            let arg = args.as_slice()[2].as_slice();
            let it = arg.split_str("::");
            let p : Vec<&str> = it.collect();

            for m in do_file_search(p.as_slice()[0], &Path::new(".")) {
                if p.len() == 1 {
                    match_fn(m);
                } else {
                    for m in do_external_search(p.slice_from(1), &m.filepath, m.point, racer::SearchType::StartsWith, racer::Namespace::BothNamespaces) {
                        match_fn(m);
                    }
                }
            }
        }
    }
}

#[cfg(not(test))]
fn prefix() {
    let args_ = std::os::args();
    let args = args_.as_slice();
    if args.len() < 5 {
        println!("Provide more arguments!");
        print_usage();
        std::os::set_exit_status(1);
        return;
    }
    let linenum = args[2].as_slice().parse::<usize>().unwrap();
    let charnum = args[3].as_slice().parse::<usize>().unwrap();
    let fname = args[4].as_slice();

    // print the start, end, and the identifier prefix being matched
    let path = Path::new(fname);
    let line = getline(&path, linenum);
    let (start, pos) = racer::util::expand_ident(line.as_slice(), charnum);
    println!("PREFIX {},{},{}", start, pos, line.as_slice().slice(start, pos));
}

#[cfg(not(test))]
fn find_definition() {
    let args_ = std::os::args();
    let args = args_.as_slice();
    if args.len() < 5 {
        println!("Provide more arguments!");
        print_usage();
        std::os::set_exit_status(1);
        return;
    }
    let linenum = args[2].as_slice().parse::<usize>().unwrap();
    let charnum = args[3].as_slice().parse::<usize>().unwrap();
    let fname = args[4].as_slice();
    let fpath = Path::new(fname);
    let src = racer::load_file(&fpath);
    let pos = scopes::coords_to_point(&*src, linenum, charnum);

    racer::find_definition(&*src, &fpath, pos).map(match_fn);
}

#[cfg(not(test))]
fn print_usage() {
    let program = std::os::args().as_slice()[0].clone();
    println!("usage: {} complete linenum charnum fname", program);
    println!("or:    {} find-definition linenum charnum fname", program);
    println!("or:    {} complete fullyqualifiedname   (e.g. std::io::)",program);
    println!("or:    {} prefix linenum charnum fname",program);
}

#[cfg(not(test))]
fn main() {
    if std::os::getenv("RUST_SRC_PATH").is_none() {
        println!("RUST_SRC_PATH environment variable must be set");
        std::os::set_exit_status(1);
        return;
    }

    let args_ = std::os::args();
    let args = args_.as_slice();

    if args.len() == 1 {
        print_usage();
        std::os::set_exit_status(1);
        return;
    }

    let command = args[1].as_slice();
    match command.as_slice() {
        "prefix" => prefix(),
        "complete" => complete(),
        "find-definition" => find_definition(),
        "help" => print_usage(),
        _ => {
            println!("Sorry, I didn't understand command {}", command );
            print_usage();
            std::os::set_exit_status(1);
            return;
        }
    }
}
<commit_msg>Remove String.as_slice() in main.rs<commit_after>#[macro_use] extern crate log;

extern crate syntax;
extern crate collections;
extern crate core;

#[cfg(not(test))]
use racer::Match;
#[cfg(not(test))]
use racer::util::getline;
#[cfg(not(test))]
use racer::nameres::{do_file_search, do_external_search};
#[cfg(not(test))]
use racer::scopes;

pub mod racer;

#[cfg(not(test))]
fn match_fn(m:Match) {
    let (linenum, charnum) = scopes::point_to_coords_from_file(&m.filepath, m.point).unwrap();
    if m.matchstr == "" {
        panic!("MATCHSTR is empty - waddup?");
    }
    println!("MATCH {},{},{},{},{:?},{}", m.matchstr,
                                    linenum.to_string(),
                                    charnum.to_string(),
                                    m.filepath.as_str().unwrap(),
                                    m.mtype,
                                    m.contextstr
             );
}

#[cfg(not(test))]
fn complete() {
    let args = std::os::args();
    if args.len() < 3 {
        println!("Provide more arguments!");
        print_usage();
        std::os::set_exit_status(1);
        return;
    }
    match std::os::args()[2].parse::<usize>() {
        Some(linenum) => {
            // input: linenum, colnum, fname
            if args.len() < 5 {
                println!("Provide more arguments!");
                print_usage();
                std::os::set_exit_status(1);
                return;
            }
            let charnum = std::os::args()[3].parse::<usize>().unwrap();
            let fname = &args[4][];
            let fpath = Path::new(fname);
            let src = racer::load_file(&fpath);
            let line = &*getline(&fpath, linenum);
            let (start, pos) = racer::util::expand_ident(line, charnum);
            println!("PREFIX {},{},{}", start, pos, &line[start..pos]);

            let point = scopes::coords_to_point(&*src, linenum, charnum);
            for m in racer::complete_from_file(&*src, &fpath, point) {
                match_fn(m);
            }
        }
        None => {
            // input: a command line string passed in
            let arg = &args[2][];
            let it = arg.split_str("::");
            let p : Vec<&str> = it.collect();

            for m in do_file_search(p[0], &Path::new(".")) {
                if p.len() == 1 {
                    match_fn(m);
                } else {
                    for m in do_external_search(&p[1..], &m.filepath, m.point, racer::SearchType::StartsWith, racer::Namespace::BothNamespaces) {
                        match_fn(m);
                    }
                }
            }
        }
    }
}

#[cfg(not(test))]
fn prefix() {
    let args = std::os::args();
    if args.len() < 5 {
        println!("Provide more arguments!");
        print_usage();
        std::os::set_exit_status(1);
        return;
    }
    let linenum = args[2].parse::<usize>().unwrap();
    let charnum = args[3].parse::<usize>().unwrap();
    let fname = &args[4][];

    // print the start, end, and the identifier prefix being matched
    let path = Path::new(fname);
    let line = &*getline(&path, linenum);
    let (start, pos) = racer::util::expand_ident(line, charnum);
    println!("PREFIX {},{},{}", start, pos, &line[start..pos]);
}

#[cfg(not(test))]
fn find_definition() {
    let args = std::os::args();
    if args.len() < 5 {
        println!("Provide more arguments!");
        print_usage();
        std::os::set_exit_status(1);
        return;
    }
    let linenum = args[2].parse::<usize>().unwrap();
    let charnum = args[3].parse::<usize>().unwrap();
    let fname = &args[4][];
    let fpath = Path::new(fname);
    let src = racer::load_file(&fpath);
    let pos = scopes::coords_to_point(&*src, linenum, charnum);

    racer::find_definition(&*src, &fpath, pos).map(match_fn);
}

#[cfg(not(test))]
fn print_usage() {
    let program = std::os::args()[0].clone();
    println!("usage: {} complete linenum charnum fname", program);
    println!("or:    {} find-definition linenum charnum fname", program);
    println!("or:    {} complete fullyqualifiedname   (e.g. std::io::)",program);
    println!("or:    {} prefix linenum charnum fname",program);
}

#[cfg(not(test))]
fn main() {
    if std::os::getenv("RUST_SRC_PATH").is_none() {
        println!("RUST_SRC_PATH environment variable must be set");
        std::os::set_exit_status(1);
        return;
    }

    let args = std::os::args();

    if args.len() == 1 {
        print_usage();
        std::os::set_exit_status(1);
        return;
    }

    let command = &args[1][];
    match command {
        "prefix" => prefix(),
        "complete" => complete(),
        "find-definition" => find_definition(),
        "help" => print_usage(),
        _ => {
            println!("Sorry, I didn't understand command {}", command );
            print_usage();
            std::os::set_exit_status(1);
            return;
        }
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(test, allow(dead_code))]

// TODO revisit these after 1.0.0beta
#![feature(core)]
#![feature(io)]
#![feature(os)]
#![feature(path)]

extern crate shader_version;
extern crate input;
extern crate event;
extern crate graphics;
extern crate sdl2_window;
extern crate window;
extern crate opengl_graphics;
extern crate quack;

extern crate chip8_vm;

use std::cell::RefCell;
use sdl2_window::Sdl2Window;
use window::WindowSettings;
use opengl_graphics::{
    Gl,
};

use std::os;
use std::old_io::File;
use std::old_io::BufReader;
// use std::time::duration::Duration;
use quack::Set;
// use input::keyboard::Key;
use input::Button;

use chip8_vm::vm::Vm;

const TITLE: &'static str = "Chip8";
const BEEP_TITLE: &'static str = "♬ Chip8 ♬";

const INTRO_ROM: &'static [u8] = include_bytes!("intro/intro.ch8");

fn main() {
    let mut vm = Vm::new();

    let mut rom: Option<File> = None;

    if os::args().len() > 1 {
        if let Ok(f) = File::open(&Path::new(os::args()[1].clone())) {
            rom = Some(f);
        } else {
            println!("Could not open rom {}", os::args()[1]);
        }
    }

    let intro_reader = &mut BufReader::new(INTRO_ROM) as &mut Reader;
    let mut rom_reader = match &mut rom {
        &mut Some(ref mut r) => r as &mut Reader,
        _ => {
            println!("You can provide a path to a chip8 binary to interpret it.");
            intro_reader
        }
    };

    match vm.load_rom(rom_reader) {
        Ok(size) => println!("Loaded rom size: {}", size),
        Err(e) => {
            println!("Error loading rom: {}", e);
            return;
        }
    }

    let (width, height) = (800, 400);
    let opengl = shader_version::OpenGL::_3_2;
    let window = Sdl2Window::new(
        opengl,
        WindowSettings {
            title: TITLE.to_string(),
            size: [width, height],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        }
    );

    let ref mut gl = Gl::new(opengl);
    let window = RefCell::new(window);

    fn keymap(k: Option<Button>) -> Option<u8> {
        use input::Key::*;
        if let Some(Button::Keyboard(k)) = k {
            return match k {
                D1 => Some(0x1),
                D2 => Some(0x2),
                D3 => Some(0x3),

                Q  => Some(0x4),
                W  => Some(0x5),
                E  => Some(0x6),

                A  => Some(0x7),
                S  => Some(0x8),
                D  => Some(0x9),

                Z  => Some(0xA),
                X  => Some(0x0),
                C  => Some(0xB),

                D4 => Some(0xC),
                R  => Some(0xD),
                F  => Some(0xE),
                V  => Some(0xF),

                _ => None
            }
        }
        return None
    }

    for e in event::events(&window) {
        use event::{ ReleaseEvent, UpdateEvent, PressEvent, RenderEvent };

        if let Some(args) = e.update_args() {
            vm.step(args.dt as f32);
            if vm.beeping() {
                (*window.borrow_mut()).window.set_title(BEEP_TITLE);
            } else {
                (*window.borrow_mut()).window.set_title(TITLE);
            }
        }
        if let Some(args) = e.render_args() {
            use graphics::*;
            gl.draw([0, 0, args.width as i32, args.height as i32], |&mut: c, gl| {
                graphics::clear([0.0, 0.0, 0.0, 1.0], gl);
                let r = Rectangle::new([1.0, 1.0, 1.0, 1.0]);
                let off = Color([0.0, 0.0, 0.0, 1.0]);
                let on = Color([1.0, 1.0, 1.0, 1.0]);

                let w = args.width as f64 / 64.0;
                let h = args.height as f64 / 32.0;

                for (y,row) in vm.screen_rows().enumerate() {
                    for (x,byte) in row.iter().enumerate() {
                        let x = x as f64 * w;
                        let y = y as f64 * h;
                        r.set(match *byte { 0 => off, _ => on })
                        .draw([x, y, w, h], &c, gl);
                    }
                }
            });
        }
        if let Some(keynum) = keymap(e.press_args()) {
            vm.set_key(keynum);
        }
        if let Some(keynum) = keymap(e.release_args()) {
            vm.unset_key(keynum);
        }
    }
}
<commit_msg>Update closure syntax<commit_after>#![cfg_attr(test, allow(dead_code))]

// TODO revisit these after 1.0.0beta
#![feature(core)]
#![feature(io)]
#![feature(os)]
#![feature(path)]

extern crate shader_version;
extern crate input;
extern crate event;
extern crate graphics;
extern crate sdl2_window;
extern crate window;
extern crate opengl_graphics;
extern crate quack;

extern crate chip8_vm;

use std::cell::RefCell;
use sdl2_window::Sdl2Window;
use window::WindowSettings;
use opengl_graphics::{
    Gl,
};

use std::os;
use std::old_io::File;
use std::old_io::BufReader;
// use std::time::duration::Duration;
use quack::Set;
// use input::keyboard::Key;
use input::Button;

use chip8_vm::vm::Vm;

const TITLE: &'static str = "Chip8";
const BEEP_TITLE: &'static str = "♬ Chip8 ♬";

const INTRO_ROM: &'static [u8] = include_bytes!("intro/intro.ch8");

fn main() {
    let mut vm = Vm::new();

    let mut rom: Option<File> = None;

    if os::args().len() > 1 {
        if let Ok(f) = File::open(&Path::new(os::args()[1].clone())) {
            rom = Some(f);
        } else {
            println!("Could not open rom {}", os::args()[1]);
        }
    }

    let intro_reader = &mut BufReader::new(INTRO_ROM) as &mut Reader;
    let mut rom_reader = match &mut rom {
        &mut Some(ref mut r) => r as &mut Reader,
        _ => {
            println!("You can provide a path to a chip8 binary to interpret it.");
            intro_reader
        }
    };

    match vm.load_rom(rom_reader) {
        Ok(size) => println!("Loaded rom size: {}", size),
        Err(e) => {
            println!("Error loading rom: {}", e);
            return;
        }
    }

    let (width, height) = (800, 400);
    let opengl = shader_version::OpenGL::_3_2;
    let window = Sdl2Window::new(
        opengl,
        WindowSettings {
            title: TITLE.to_string(),
            size: [width, height],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        }
    );

    let ref mut gl = Gl::new(opengl);
    let window = RefCell::new(window);

    fn keymap(k: Option<Button>) -> Option<u8> {
        use input::Key::*;
        if let Some(Button::Keyboard(k)) = k {
            return match k {
                D1 => Some(0x1),
                D2 => Some(0x2),
                D3 => Some(0x3),

                Q  => Some(0x4),
                W  => Some(0x5),
                E  => Some(0x6),

                A  => Some(0x7),
                S  => Some(0x8),
                D  => Some(0x9),

                Z  => Some(0xA),
                X  => Some(0x0),
                C  => Some(0xB),

                D4 => Some(0xC),
                R  => Some(0xD),
                F  => Some(0xE),
                V  => Some(0xF),

                _ => None
            }
        }
        return None
    }

    for e in event::events(&window) {
        use event::{ ReleaseEvent, UpdateEvent, PressEvent, RenderEvent };

        if let Some(args) = e.update_args() {
            vm.step(args.dt as f32);
            if vm.beeping() {
                (*window.borrow_mut()).window.set_title(BEEP_TITLE);
            } else {
                (*window.borrow_mut()).window.set_title(TITLE);
            }
        }
        if let Some(args) = e.render_args() {
            use graphics::*;
            gl.draw([0, 0, args.width as i32, args.height as i32], |c, gl| {
                graphics::clear([0.0, 0.0, 0.0, 1.0], gl);
                let r = Rectangle::new([1.0, 1.0, 1.0, 1.0]);
                let off = Color([0.0, 0.0, 0.0, 1.0]);
                let on = Color([1.0, 1.0, 1.0, 1.0]);

                let w = args.width as f64 / 64.0;
                let h = args.height as f64 / 32.0;

                for (y,row) in vm.screen_rows().enumerate() {
                    for (x,byte) in row.iter().enumerate() {
                        let x = x as f64 * w;
                        let y = y as f64 * h;
                        r.set(match *byte { 0 => off, _ => on })
                        .draw([x, y, w, h], &c, gl);
                    }
                }
            });
        }
        if let Some(keynum) = keymap(e.press_args()) {
            vm.set_key(keynum);
        }
        if let Some(keynum) = keymap(e.release_args()) {
            vm.unset_key(keynum);
        }
    }
}
<|endoftext|>