<commit_before>use std::env;
use std::fs;
use std::io::Read;
use std::path::Path;

fn main() {
    let pif_file_name = env::args().nth(1).unwrap();
    let rom_file_name = env::args().nth(2).unwrap();

    let pif = load_bin(pif_file_name);
    let rom = load_bin(rom_file_name);
}

fn load_bin<P: AsRef<Path>>(path: P) -> Vec<u8> {
    let mut file = fs::File::open(path).unwrap();
    let mut file_buf = Vec::new();
    file.read_to_end(&mut file_buf).unwrap();
    file_buf
}
<commit_msg>initial cpu<commit_after>use std::env;
use std::fs;
use std::io::Read;
use std::path::Path;

const NUM_GPREG: usize = 32;
const NUM_FPREG: usize = 32;

struct Cpu {
    reg_gprs: [u64; NUM_GPREG],
    reg_fprs: [u64; NUM_FPREG],

    reg_pc: u64,

    reg_hi: u64,
    reg_lo: u64,

    reg_llbit: bool,

    reg_fcr0: u32,
    reg_fcr31: u32,

    cp0: CP0
}

impl Cpu {
    fn new() -> Cpu {
        Cpu {
            reg_gprs: [0; NUM_GPREG],
            reg_fprs: [0; NUM_FPREG],

            reg_pc: 0,

            reg_hi: 0,
            reg_lo: 0,

            reg_llbit: false,

            reg_fcr0: 0,
            reg_fcr31: 0,

            cp0: CP0::new()
        }
    }

    fn power_on_reset(&mut self) {
        self.cp0.power_on_reset();
    }
}

struct CP0 {
    reg_index: u64,
    reg_random: u64,
    reg_entrylo0: u64,
    reg_entrylo1: u64,
    reg_context: u64,
    reg_pagemask: u64,
    reg_wired: u64,
    reg_badvaddr: u64,
    reg_count: u64,
    reg_entryhi: u64,
    reg_compare: u64,
    reg_status: u64,
    reg_cause: u64,
    reg_epc: u64,
    reg_prid: u64,
    reg_config: u64,
    reg_lladdr: u64,
    reg_watchlo: u64,
    reg_watchhi: u64,
    reg_xcontext: u64,
    reg_taglo: u64,
    reg_taghi: u64,
    reg_errorepc: u64
}

impl CP0 {
    fn new() -> CP0 {
        CP0 {
            reg_index: 0,
            reg_random: 0,
            reg_entrylo0: 0,
            reg_entrylo1: 0,
            reg_context: 0,
            reg_pagemask: 0,
            reg_wired: 0,
            reg_badvaddr: 0,
            reg_count: 0,
            reg_entryhi: 0,
            reg_compare: 0,
            reg_status: 0,
            reg_cause: 0,
            reg_epc: 0,
            reg_prid: 0,
            reg_config: 0,
            reg_lladdr: 0,
            reg_watchlo: 0,
            reg_watchhi: 0,
            reg_xcontext: 0,
            reg_taglo: 0,
            reg_taghi: 0,
            reg_errorepc: 0
        }
    }

    fn power_on_reset(&mut self) {

    }
}

fn main() {
    let pif_file_name = env::args().nth(1).unwrap();
    let rom_file_name = env::args().nth(2).unwrap();

    let pif = load_bin(pif_file_name);
    let rom = load_bin(rom_file_name);

    let mut cpu = Cpu::new();
}

fn load_bin<P: AsRef<Path>>(path: P) -> Vec<u8> {
    let mut file = fs::File::open(path).unwrap();
    let mut file_buf = Vec::new();
    file.read_to_end(&mut file_buf).unwrap();
    file_buf
}
<|endoftext|>


<commit_before>#![feature(collections)]
#![feature(io)]
#![feature(os)]
#![feature(rand)]

extern crate "rustc-serialize" as serialize;
extern crate getopts;

use std::os;
use std::rand::{ Rng, OsRng };
use std::iter::repeat;
use std::old_io::{ stdio, IoError, IoErrorKind, IoResult, BufferedReader };

use serialize::base64::{ self, FromBase64, ToBase64 };
use getopts::Options;

use gf256::Gf256;

mod gf256;

fn new_vec<T: Clone>(n: usize, x: T) -> Vec<T> {
	repeat(x).take(n).collect()
}

fn other_io_err(s: &'static str) -> IoError {
	IoError {
		kind: IoErrorKind::OtherIoError,
		desc: s,
		detail: None
	}
}

/// evaluates a polynomial at x=1, 2, 3, ... n (inclusive)
fn encode<W: Writer>(src: &[u8], n: u8, w: &mut W) -> IoResult<()> {
	for raw_x in 1 .. ((n as u16) + 1) {
		let x = Gf256::from_byte(raw_x as u8);
		let mut fac = Gf256::one();
		let mut acc = Gf256::zero();
		for &coeff in src.iter() {
			acc = acc + fac * Gf256::from_byte(coeff);
			fac = fac * x;
		}
		try!(w.write_u8(acc.to_byte()));
	}
	Ok(())
}

/// evaluates an interpolated polynomial at `raw_x` where
/// the polynomial is determined using Lagrangian interpolation
/// based on the given x/y coordinates `src`.
fn lagrange_interpolate(src: &[(u8, u8)], raw_x: u8) -> u8 {
	let x = Gf256::from_byte(raw_x);
	let mut sum = Gf256::zero();
	for (i, &(raw_xi, raw_yi)) in src.iter().enumerate() {
		let xi = Gf256::from_byte(raw_xi);
		let yi = Gf256::from_byte(raw_yi);
		let mut lix = Gf256::one();
		for (j, &(raw_xj, _)) in src.iter().enumerate() {
			if i != j {
				let xj = Gf256::from_byte(raw_xj);
				lix = lix * (x - xj) / (xi - xj);
			}
		}
		sum = sum + lix * yi;
	}
	sum.to_byte()
}

fn secret_share(src: &[u8], k: u8, n: u8) -> IoResult<Vec<Vec<u8>>> {
	let mut result = Vec::with_capacity(n as usize);
	for _ in 0 .. (n as usize) {
		result.push(new_vec(src.len(), 0u8));
	}
	let mut col_in = new_vec(k as usize, 0u8);
	let mut col_out = Vec::with_capacity(n as usize);
	let mut osrng = try!(OsRng::new());
	for (c, &s) in src.iter().enumerate() {
		col_in[0] = s;
		osrng.fill_bytes(&mut col_in[1..]);
		col_out.clear();
		try!(encode(&*col_in, n, &mut col_out));
		for (&y, share) in col_out.iter().zip(result.iter_mut()) {
			share[c] = y;
		}
	}
	Ok(result)
}

enum Action {
	Encode(u8, u8), // k and n parameter
	Decode
}

fn parse_k_n(s: &str) -> Option<(u8, u8)> {
	let mut iter = s.split(',');
	let first = match iter.next() { Some(x) => x, None => return None };
	let second = match iter.next() { Some(x) => x, None => return None };
	let k = match first.parse() { Some(x) => x, None => return None };
	let n = match second.parse() { Some(x) => x, None => return None };
	Some((k, n))
}

/// tries to read everything but stops early if the input seems to be
/// larger than `max` bytes and returns an IoError in this case
fn read_no_more_than<R: Reader>(r: &mut R, max: usize) -> IoResult<Vec<u8>> {
	let mut data = Vec::new();
	loop {
		if let Err(e) = r.push(max + 1 - data.len(), &mut data) {
			if e.kind == IoErrorKind::EndOfFile {
				break; // EOF condition is actually OK
			} else {
				return Err(e);
			}
		}
		if data.len() > max {
			return Err(other_io_err("Input too long"));
		}
	}
	Ok(data)
}

fn perform_encode(k: u8, n: u8) -> IoResult<()> {
	let secret = try!(read_no_more_than(&mut stdio::stdin(), 0x10000));
	let shares = try!(secret_share(&*secret, k, n));
	for (index, share) in shares.iter().enumerate() {
		println!("{}-{}-{}", k, index+1, share.to_base64(base64::STANDARD));
	}
	Ok(())
}

/// reads shares from stdin and returns Ok(k, shares) on success
/// where shares is a Vec<(u8, Vec<u8>)> representing x-coordinates
/// and share data.
fn read_shares() -> IoResult<(u8, Vec<(u8,Vec<u8>)>)> {
	let mut stdin = BufferedReader::new(stdio::stdin());
	let mut opt_k_l: Option<(u8, usize)> = None;
	let mut counter = 0u8;
	let mut shares = Vec::new();
	for line in stdin.lines() {
		let line = try!(line);
		let parts: Vec<_> = line.split('-').collect();
		let (k, n, raw) = match
			Some(parts).and_then(|p| {
				if p.len() != 3 { None } else { Some(p) }
			}).and_then(|p| {
				let mut iter = p.into_iter();
				let p1 = iter.next().unwrap().parse::<u8>();
				let p2 = iter.next().unwrap().parse::<u8>();
				let p3 = iter.next().unwrap();
				match (p1, p2) {
					(Some(k), Some(n)) => Some((k,n,p3)),
					_ => None
				}
			}).and_then(|(k,n,text)| {
				match text.from_base64() {
					Ok(v) => Some((k,n,v)),
					_ => None
				}
			}) {
				None => return Err(other_io_err("Share parse error")),
				Some(s) => s
			};
		if let Some((ck,cl)) = opt_k_l {
			if ck != k || cl != raw.len() {
				return Err(other_io_err("Incompatible shares"));
			}
		} else {
			opt_k_l = Some((k,raw.len()));
		}
		shares.push((n, raw));
		counter += 1;
		if counter == k {
			return Ok((k, shares));
		}
	}
	Err(other_io_err("No shares"))
}

fn perform_decode() -> IoResult<()> {
	let (k, shares) = try!(read_shares());
	assert!(!shares.is_empty());
	let slen = shares[0].1.len();
	let mut col_in = Vec::with_capacity(k as usize);
	let mut secret = Vec::with_capacity(slen);
	for byteindex in 0 .. slen {
		col_in.clear();
		for s in shares.iter().take(k as usize) {
			col_in.push((s.0, s.1[byteindex]));
		}
		secret.push(lagrange_interpolate(&*col_in, 0u8));
	}
	let mut out = stdio::stdout_raw();
	try!(out.write_all(&*secret));
	out.flush()
}

fn main() {
	let mut stderr = stdio::stderr();
	let args = os::args();

	let mut opts = Options::new();
	opts.optflag("h", "help", "print this help text");
	opts.optflag("d", "decode", "for decoding");
	opts.optopt("e", "encode", "for encoding, K is the required number of shares, \
		N is the number of shares to generate. 1 <= K <= N <= 255", "K,N");
	let opt_matches = match opts.parse(args.tail()) {
		Ok(m) => m,
		Err(f) => panic!(f.to_string())
	};

	if args.len() < 2 || opt_matches.opt_present("h") {
		println!(
"The program secretshare is an implementation of Shamir's secret sharing scheme.\n\
 It is applied byte-wise within a finite field for arbitraty long secrets.\n");
		println!("{}", opts.usage("Usage: secretshare [options]"));
 		return;
	}

	let action: Result<_,_> =
		match (opt_matches.opt_present("e"), opt_matches.opt_present("d")) {
			(false, false) => Err("Nothing to do! Use -e or -d"),
			(true, true) => Err("Use either -e or -d and not both"),
			(false, true) => Ok(Action::Decode),
			(true, false) => {
				if let Some(param) = opt_matches.opt_str("e") {
					if let Some((k,n)) = parse_k_n(&*param) {
						Ok(Action::Encode(k,n))
					} else {
						Err("Could not parse K,N parameters")
					}
				} else {
					Err("No parameter for -e or -d provided")
				}
			}
		};

	let result =
		match action {
			Ok(Action::Encode(k,n)) => perform_encode(k,n),
			Ok(Action::Decode) => perform_decode(),
			Err(e) => {
				drop(writeln!(&mut stderr, "Error: {}", e));
				os::set_exit_status(1);
				return;
			}
		};

	if let Err(e) = result {
		drop(writeln!(&mut stderr, "{}", e));
		os::set_exit_status(1);
	}
}

<commit_msg>error handling for share duplicates<commit_after>#![feature(collections)]
#![feature(io)]
#![feature(os)]
#![feature(rand)]

extern crate "rustc-serialize" as serialize;
extern crate getopts;

use std::os;
use std::rand::{ Rng, OsRng };
use std::iter::repeat;
use std::old_io::{ stdio, IoError, IoErrorKind, IoResult, BufferedReader };

use serialize::base64::{ self, FromBase64, ToBase64 };
use getopts::Options;

use gf256::Gf256;

mod gf256;

fn new_vec<T: Clone>(n: usize, x: T) -> Vec<T> {
	repeat(x).take(n).collect()
}

fn other_io_err(s: &'static str) -> IoError {
	IoError {
		kind: IoErrorKind::OtherIoError,
		desc: s,
		detail: None
	}
}

/// evaluates a polynomial at x=1, 2, 3, ... n (inclusive)
fn encode<W: Writer>(src: &[u8], n: u8, w: &mut W) -> IoResult<()> {
	for raw_x in 1 .. ((n as u16) + 1) {
		let x = Gf256::from_byte(raw_x as u8);
		let mut fac = Gf256::one();
		let mut acc = Gf256::zero();
		for &coeff in src.iter() {
			acc = acc + fac * Gf256::from_byte(coeff);
			fac = fac * x;
		}
		try!(w.write_u8(acc.to_byte()));
	}
	Ok(())
}

/// evaluates an interpolated polynomial at `raw_x` where
/// the polynomial is determined using Lagrangian interpolation
/// based on the given x/y coordinates `src`.
fn lagrange_interpolate(src: &[(u8, u8)], raw_x: u8) -> u8 {
	let x = Gf256::from_byte(raw_x);
	let mut sum = Gf256::zero();
	for (i, &(raw_xi, raw_yi)) in src.iter().enumerate() {
		let xi = Gf256::from_byte(raw_xi);
		let yi = Gf256::from_byte(raw_yi);
		let mut lix = Gf256::one();
		for (j, &(raw_xj, _)) in src.iter().enumerate() {
			if i != j {
				let xj = Gf256::from_byte(raw_xj);
				let delta = xi - xj;
				assert!(delta.poly !=0, "Duplicate shares");
				lix = lix * (x - xj) / delta;
			}
		}
		sum = sum + lix * yi;
	}
	sum.to_byte()
}

fn secret_share(src: &[u8], k: u8, n: u8) -> IoResult<Vec<Vec<u8>>> {
	let mut result = Vec::with_capacity(n as usize);
	for _ in 0 .. (n as usize) {
		result.push(new_vec(src.len(), 0u8));
	}
	let mut col_in = new_vec(k as usize, 0u8);
	let mut col_out = Vec::with_capacity(n as usize);
	let mut osrng = try!(OsRng::new());
	for (c, &s) in src.iter().enumerate() {
		col_in[0] = s;
		osrng.fill_bytes(&mut col_in[1..]);
		col_out.clear();
		try!(encode(&*col_in, n, &mut col_out));
		for (&y, share) in col_out.iter().zip(result.iter_mut()) {
			share[c] = y;
		}
	}
	Ok(result)
}

enum Action {
	Encode(u8, u8), // k and n parameter
	Decode
}

fn parse_k_n(s: &str) -> Option<(u8, u8)> {
	let mut iter = s.split(',');
	let first = match iter.next() { Some(x) => x, None => return None };
	let second = match iter.next() { Some(x) => x, None => return None };
	let k = match first.parse() { Some(x) => x, None => return None };
	let n = match second.parse() { Some(x) => x, None => return None };
	Some((k, n))
}

/// tries to read everything but stops early if the input seems to be
/// larger than `max` bytes and returns an IoError in this case
fn read_no_more_than<R: Reader>(r: &mut R, max: usize) -> IoResult<Vec<u8>> {
	let mut data = Vec::new();
	loop {
		if let Err(e) = r.push(max + 1 - data.len(), &mut data) {
			if e.kind == IoErrorKind::EndOfFile {
				break; // EOF condition is actually OK
			} else {
				return Err(e);
			}
		}
		if data.len() > max {
			return Err(other_io_err("Input too long"));
		}
	}
	Ok(data)
}

fn perform_encode(k: u8, n: u8) -> IoResult<()> {
	let secret = try!(read_no_more_than(&mut stdio::stdin(), 0x10000));
	let shares = try!(secret_share(&*secret, k, n));
	for (index, share) in shares.iter().enumerate() {
		println!("{}-{}-{}", k, index+1, share.to_base64(base64::STANDARD));
	}
	Ok(())
}

/// reads shares from stdin and returns Ok(k, shares) on success
/// where shares is a Vec<(u8, Vec<u8>)> representing x-coordinates
/// and share data.
fn read_shares() -> IoResult<(u8, Vec<(u8,Vec<u8>)>)> {
	let mut stdin = BufferedReader::new(stdio::stdin());
	let mut opt_k_l: Option<(u8, usize)> = None;
	let mut counter = 0u8;
	let mut shares: Vec<(u8,Vec<u8>)> = Vec::new();
	for line in stdin.lines() {
		let line = try!(line);
		let parts: Vec<_> = line.split('-').collect();
		let (k, n, raw) = match
			Some(parts).and_then(|p| {
				if p.len() != 3 { None } else { Some(p) }
			}).and_then(|p| {
				let mut iter = p.into_iter();
				let p1 = iter.next().unwrap().parse::<u8>();
				let p2 = iter.next().unwrap().parse::<u8>();
				let p3 = iter.next().unwrap();
				match (p1, p2) {
					(Some(k), Some(n)) => Some((k,n,p3)),
					_ => None
				}
			}).and_then(|(k,n,text)| {
				match text.from_base64() {
					Ok(v) => Some((k,n,v)),
					_ => None
				}
			}) {
				None => return Err(other_io_err("Share parse error")),
				Some(s) => s
			};
		if let Some((ck,cl)) = opt_k_l {
			if ck != k || cl != raw.len() {
				return Err(other_io_err("Incompatible shares"));
			}
		} else {
			opt_k_l = Some((k,raw.len()));
		}
		if shares.iter().all(|s| s.0 != n) {
			shares.push((n, raw));
			counter += 1;
			if counter == k {
				return Ok((k, shares));
			}
		}
	}
	Err(other_io_err("Not enough shares provided!"))
}

fn perform_decode() -> IoResult<()> {
	let (k, shares) = try!(read_shares());
	assert!(!shares.is_empty());
	let slen = shares[0].1.len();
	let mut col_in = Vec::with_capacity(k as usize);
	let mut secret = Vec::with_capacity(slen);
	for byteindex in 0 .. slen {
		col_in.clear();
		for s in shares.iter().take(k as usize) {
			col_in.push((s.0, s.1[byteindex]));
		}
		secret.push(lagrange_interpolate(&*col_in, 0u8));
	}
	let mut out = stdio::stdout_raw();
	try!(out.write_all(&*secret));
	out.flush()
}

fn main() {
	let mut stderr = stdio::stderr();
	let args = os::args();

	let mut opts = Options::new();
	opts.optflag("h", "help", "print this help text");
	opts.optflag("d", "decode", "for decoding");
	opts.optopt("e", "encode", "for encoding, K is the required number of shares, \
		N is the number of shares to generate. 1 <= K <= N <= 255", "K,N");
	let opt_matches = match opts.parse(args.tail()) {
		Ok(m) => m,
		Err(f) => panic!(f.to_string())
	};

	if args.len() < 2 || opt_matches.opt_present("h") {
		println!(
"The program secretshare is an implementation of Shamir's secret sharing scheme.\n\
 It is applied byte-wise within a finite field for arbitraty long secrets.\n");
		println!("{}", opts.usage("Usage: secretshare [options]"));
		println!("Input is read from STDIN and output is written to STDOUT.");
 		return;
	}

	let action: Result<_,_> =
		match (opt_matches.opt_present("e"), opt_matches.opt_present("d")) {
			(false, false) => Err("Nothing to do! Use -e or -d"),
			(true, true) => Err("Use either -e or -d and not both"),
			(false, true) => Ok(Action::Decode),
			(true, false) => {
				if let Some(param) = opt_matches.opt_str("e") {
					if let Some((k,n)) = parse_k_n(&*param) {
						Ok(Action::Encode(k,n))
					} else {
						Err("Could not parse K,N parameters")
					}
				} else {
					Err("No parameter for -e or -d provided")
				}
			}
		};

	let result =
		match action {
			Ok(Action::Encode(k,n)) => perform_encode(k,n),
			Ok(Action::Decode) => perform_decode(),
			Err(e) => {
				drop(writeln!(&mut stderr, "Error: {}", e));
				os::set_exit_status(1);
				return;
			}
		};

	if let Err(e) = result {
		drop(writeln!(&mut stderr, "{}", e));
		os::set_exit_status(1);
	}
}

<|endoftext|>


<commit_before>extern crate ppbert;
#[macro_use] extern crate clap;

use std::io::{self, ErrorKind, Read, Write};
use std::fs;
use std::process::exit;
use std::time::{Duration, Instant};

use clap::{Arg, App};

use ppbert::bertterm::BertTerm;
use ppbert::error::{BertError, Result};
use ppbert::parser;

const PROG_NAME: &str = "ppbert";

fn main() {
    let matches = App::new(PROG_NAME)
        .version(crate_version!())
        .author("Vincent Foley")
        .about("Pretty print structure encoded in Erlang's External Term Format")
        .arg(Arg::with_name("input_files")
             .value_name("FILES")
             .multiple(true))
        .arg(Arg::with_name("indent_width")
             .help("Indents with <num> spaces")
             .value_name("num")
             .short("i")
             .long("indent-width")
             .default_value("2")
             .takes_value(true))
        .arg(Arg::with_name("max_per_line")
             .help("Prints at most <num> basic terms per line")
             .value_name("num")
             .short("m")
             .long("max-terms-per-line")
             .default_value("5")
             .takes_value(true))
        .arg(Arg::with_name("verbose")
             .help("Enables verbose mode")
             .short("v")
             .long("verbose"))
        .arg(Arg::with_name("parse")
             .help("Parses the input, doesn't pretty print it")
             .short("p")
             .long("parse"))
        .arg(Arg::with_name("bert2")
             .help("Parses .bert2 files")
             .conflicts_with("disk_log")
             .short("2")
             .long("bert2"))
        .arg(Arg::with_name("disk_log")
             .help("Parses disk_log files")
             .conflicts_with("bert2")
             .short("d")
             .long("disk-log"))
        .arg(Arg::with_name("json")
             .help("Outputs in JSON")
             .short("j")
             .long("json"))
        .arg(Arg::with_name("transform-proplists")
             .help("Transforms proplists into JSON objects (only valid with --json)")
             .short("t")
             .long("transform-proplists"))
        .get_matches();

    let files: Vec<&str> = match matches.values_of("input_files") {
        Some(files) => files.collect(),
        None => vec!["-"]
    };
    let indent_level = value_t!(matches, "indent_width", usize).unwrap();
    let max_per_line = value_t!(matches, "max_per_line", usize).unwrap();
    let verbose = matches.is_present("verbose");
    let parse_only = matches.is_present("parse");
    let json = matches.is_present("json");
    let transform_proplists = matches.is_present("transform-proplists");

    let parse_fn =
        if matches.is_present("bert2") {
            parser::Parser::bert2_next
        } else if matches.is_present("disk_log") {
            parser::Parser::disk_log_next
        } else {
            parser::Parser::bert_next
        };
    let output_fn = match (json, transform_proplists) {
        (true, false)  => pp_json,
        (true, true)   => pp_json_proplist,
        (false, false) => pp_bert,
        (false, true)  => {
            eprintln!("{}: --transform-proplists is only valid with the --json flag", PROG_NAME);
            pp_bert
        }
    };

    let mut return_code = 0;
    for file in files {
        let res = handle_file(file, parse_only, verbose,
                              indent_level, max_per_line,
                              parse_fn, output_fn);
        match res {
            Ok(()) => (),
            Err(ref e) => {
                if broken_pipe(e) {
                    break;
                }
                return_code = 1;
                eprintln!("{}: {}: {}", PROG_NAME, file, e);
            }
        }
    }
    exit(return_code);
}

fn broken_pipe(err: &BertError) -> bool {
    match *err {
        BertError::IoError(ref ioerr) =>
            ioerr.kind() == ErrorKind::BrokenPipe,
        _ => false
    }
}

fn handle_file(
    file: &str,
    parse_only: bool,
    verbose: bool,
    indent: usize,
    terms_per_line: usize,
    parse_fn: fn(&mut parser::Parser) -> Option<Result<BertTerm>>,
    pp_fn: fn(BertTerm, usize, usize) -> Result<()>
) -> Result<()> {

    // Read file or stdin into buffer
    let now = Instant::now();
    let buf = if file == "-" {
        let stdin = io::stdin();
        let mut stdin = stdin.lock();
        let mut buf: Vec<u8> = Vec::with_capacity(4096);
        stdin.read_to_end(&mut buf)?;
        buf
    } else {
        fs::read(file)?
    };
    let read_dur = now.elapsed();

    let mut parser = parser::Parser::new(buf);
    let mut parse_dur = Duration::new(0, 0);
    let mut pp_dur = Duration::new(0, 0);

    loop {
        let now = Instant::now();
        let next_item = parse_fn(&mut parser);
        parse_dur += now.elapsed();

        match next_item {
            None => { break; }
            Some(Err(e)) => { return Err(e); }
            Some(Ok(t)) => {
                if !parse_only {
                    let now = Instant::now();
                    pp_fn(t, indent, terms_per_line)?;
                    pp_dur += now.elapsed();
                }
            }
        }
    }

    if verbose {
        eprintln!("{}: {} read time: {}.{:06} seconds", PROG_NAME, file, read_dur.as_secs(), read_dur.subsec_micros());
        eprintln!("{}: {} parse time: {}.{:06} seconds", PROG_NAME, file, parse_dur.as_secs(), parse_dur.subsec_micros());
        if !parse_only {
            eprintln!("{}: {} print time: {}.{:06} seconds", PROG_NAME, file, pp_dur.as_secs(), pp_dur.subsec_micros());
        }
    }

    return Ok(());
}

/// Outputs a BertTerm to stdout.
fn pp_bert(term: BertTerm, indent_width: usize, terms_per_line: usize) -> Result <()> {
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    term.write_as_erlang(&mut stdout, indent_width, terms_per_line)?;
    writeln!(&mut stdout, "")?;
    return Ok(());
}

/// Outputs a BertTerm as JSON to stdout.
fn pp_json(term: BertTerm, _: usize, _: usize) -> Result <()> {
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    term.write_as_json(&mut stdout, false)?;
    writeln!(&mut stdout, "")?;
    return Ok(());
}

/// Outputs a BertTerm as JSON to stdout;
/// Erlang proplists are converted to JSON objects.
fn pp_json_proplist(term: BertTerm, _: usize, _: usize) -> Result <()> {
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    term.write_as_json(&mut stdout, true)?;
    writeln!(&mut stdout, "")?;
    return Ok(());
}
<commit_msg>Wrap StdoutLock object in BufWriter<commit_after>extern crate ppbert;
#[macro_use] extern crate clap;

use std::io::{self, ErrorKind, Read, Write, BufWriter};
use std::fs;
use std::process::exit;
use std::time::{Duration, Instant};

use clap::{Arg, App};

use ppbert::bertterm::BertTerm;
use ppbert::error::{BertError, Result};
use ppbert::parser;

const PROG_NAME: &str = "ppbert";

fn main() {
    let matches = App::new(PROG_NAME)
        .version(crate_version!())
        .author("Vincent Foley")
        .about("Pretty print structure encoded in Erlang's External Term Format")
        .arg(Arg::with_name("input_files")
             .value_name("FILES")
             .multiple(true))
        .arg(Arg::with_name("indent_width")
             .help("Indents with <num> spaces")
             .value_name("num")
             .short("i")
             .long("indent-width")
             .default_value("2")
             .takes_value(true))
        .arg(Arg::with_name("max_per_line")
             .help("Prints at most <num> basic terms per line")
             .value_name("num")
             .short("m")
             .long("max-terms-per-line")
             .default_value("5")
             .takes_value(true))
        .arg(Arg::with_name("verbose")
             .help("Enables verbose mode")
             .short("v")
             .long("verbose"))
        .arg(Arg::with_name("parse")
             .help("Parses the input, doesn't pretty print it")
             .short("p")
             .long("parse"))
        .arg(Arg::with_name("bert2")
             .help("Parses .bert2 files")
             .conflicts_with("disk_log")
             .short("2")
             .long("bert2"))
        .arg(Arg::with_name("disk_log")
             .help("Parses disk_log files")
             .conflicts_with("bert2")
             .short("d")
             .long("disk-log"))
        .arg(Arg::with_name("json")
             .help("Outputs in JSON")
             .short("j")
             .long("json"))
        .arg(Arg::with_name("transform-proplists")
             .help("Transforms proplists into JSON objects (only valid with --json)")
             .short("t")
             .long("transform-proplists"))
        .get_matches();

    let files: Vec<&str> = match matches.values_of("input_files") {
        Some(files) => files.collect(),
        None => vec!["-"]
    };
    let indent_level = value_t!(matches, "indent_width", usize).unwrap();
    let max_per_line = value_t!(matches, "max_per_line", usize).unwrap();
    let verbose = matches.is_present("verbose");
    let parse_only = matches.is_present("parse");
    let json = matches.is_present("json");
    let transform_proplists = matches.is_present("transform-proplists");

    let parse_fn =
        if matches.is_present("bert2") {
            parser::Parser::bert2_next
        } else if matches.is_present("disk_log") {
            parser::Parser::disk_log_next
        } else {
            parser::Parser::bert_next
        };
    let output_fn = match (json, transform_proplists) {
        (true, false)  => pp_json,
        (true, true)   => pp_json_proplist,
        (false, false) => pp_bert,
        (false, true)  => {
            eprintln!("{}: --transform-proplists is only valid with the --json flag", PROG_NAME);
            pp_bert
        }
    };

    let mut return_code = 0;
    for file in files {
        let res = handle_file(file, parse_only, verbose,
                              indent_level, max_per_line,
                              parse_fn, output_fn);
        match res {
            Ok(()) => (),
            Err(ref e) => {
                if broken_pipe(e) {
                    break;
                }
                return_code = 1;
                eprintln!("{}: {}: {}", PROG_NAME, file, e);
            }
        }
    }
    exit(return_code);
}

fn broken_pipe(err: &BertError) -> bool {
    match *err {
        BertError::IoError(ref ioerr) =>
            ioerr.kind() == ErrorKind::BrokenPipe,
        _ => false
    }
}

fn handle_file(
    file: &str,
    parse_only: bool,
    verbose: bool,
    indent: usize,
    terms_per_line: usize,
    parse_fn: fn(&mut parser::Parser) -> Option<Result<BertTerm>>,
    pp_fn: fn(BertTerm, usize, usize) -> Result<()>
) -> Result<()> {

    // Read file or stdin into buffer
    let now = Instant::now();
    let buf = if file == "-" {
        let stdin = io::stdin();
        let mut stdin = stdin.lock();
        let mut buf: Vec<u8> = Vec::with_capacity(4096);
        stdin.read_to_end(&mut buf)?;
        buf
    } else {
        fs::read(file)?
    };
    let read_dur = now.elapsed();

    let mut parser = parser::Parser::new(buf);
    let mut parse_dur = Duration::new(0, 0);
    let mut pp_dur = Duration::new(0, 0);

    loop {
        let now = Instant::now();
        let next_item = parse_fn(&mut parser);
        parse_dur += now.elapsed();

        match next_item {
            None => { break; }
            Some(Err(e)) => { return Err(e); }
            Some(Ok(t)) => {
                if !parse_only {
                    let now = Instant::now();
                    pp_fn(t, indent, terms_per_line)?;
                    pp_dur += now.elapsed();
                }
            }
        }
    }

    if verbose {
        eprintln!("{}: {} read time: {}.{:06} seconds", PROG_NAME, file, read_dur.as_secs(), read_dur.subsec_micros());
        eprintln!("{}: {} parse time: {}.{:06} seconds", PROG_NAME, file, parse_dur.as_secs(), parse_dur.subsec_micros());
        if !parse_only {
            eprintln!("{}: {} print time: {}.{:06} seconds", PROG_NAME, file, pp_dur.as_secs(), pp_dur.subsec_micros());
        }
    }

    return Ok(());
}

/// Outputs a BertTerm to stdout.
fn pp_bert(term: BertTerm, indent_width: usize, terms_per_line: usize) -> Result <()> {
    let stdout = io::stdout();
    let stdout = stdout.lock();
    let mut stdout = BufWriter::new(stdout);
    term.write_as_erlang(&mut stdout, indent_width, terms_per_line)?;
    writeln!(&mut stdout, "")?;
    return Ok(());
}

/// Outputs a BertTerm as JSON to stdout.
fn pp_json(term: BertTerm, _: usize, _: usize) -> Result <()> {
    let stdout = io::stdout();
    let stdout = stdout.lock();
    let mut stdout = BufWriter::new(stdout);
    term.write_as_json(&mut stdout, false)?;
    writeln!(&mut stdout, "")?;
    return Ok(());
}

/// Outputs a BertTerm as JSON to stdout;
/// Erlang proplists are converted to JSON objects.
fn pp_json_proplist(term: BertTerm, _: usize, _: usize) -> Result <()> {
    let stdout = io::stdout();
    let stdout = stdout.lock();
    let mut stdout = BufWriter::new(stdout);
    term.write_as_json(&mut stdout, true)?;
    writeln!(&mut stdout, "")?;
    return Ok(());
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
extern crate chrono;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
extern crate colored;

use std::env;
use std::fs;
use std::fs::{OpenOptions, File, Metadata};
use std::io::{Write, ErrorKind};
use std::path::PathBuf;

use chrono::{DateTime, Utc, Local, Duration};
use clap::{App, Arg, AppSettings, SubCommand};
use serde_json::Error;
use colored::*;

#[derive(Serialize, Deserialize, Debug, Clone)]
struct Period {
    project: String,
    start_time: DateTime<Utc>,
    end_time: Option<DateTime<Utc>>,
}

fn main() {
    let matches = App::new("Doug")
        .version(crate_version!())
        .about("A time tracking command-line utility")
        .author(crate_authors!())
        .settings(&[
            AppSettings::DeriveDisplayOrder,
            AppSettings::GlobalVersion,
            AppSettings::SubcommandRequiredElseHelp,
            AppSettings::VersionlessSubcommands,
            AppSettings::DisableHelpSubcommand,
        ])
        .subcommand(SubCommand::with_name("start")
            .about("Track new or existing project")
            .arg(Arg::with_name("project")
                .help("project to track")
                .required(true)))
        .subcommand(SubCommand::with_name("status")
            .about("Display elapsed time, start time, and running project name"))
        .subcommand(SubCommand::with_name("stop")
            .about("Stop any running projects"))
        .subcommand(SubCommand::with_name("cancel")
            .about("Stop running project and remove most recent time interval"))
        .subcommand(SubCommand::with_name("restart")
            .about("Track last running project"))
        .subcommand(SubCommand::with_name("log")
            .about("Display time intervals across all projects"))
        .subcommand(SubCommand::with_name("report")
            .about("Display aggregate time from last week"))
        .subcommand(SubCommand::with_name("amend")
            .about("Change name of currently running project")
            .arg(Arg::with_name("project")
                .help("new project name")
                .required(true)))
        .subcommand(SubCommand::with_name("edit")
            .about("Edit last frame or currently running frame")
            .arg(Arg::with_name("project")
                .help("project to track")))
        .get_matches();

    if let Some(matches) = matches.subcommand_matches("start") {
        if matches.is_present("project") {
            start(matches.value_of("project").unwrap());
        }
    }

    if let Some(matches) = matches.subcommand_matches("amend") {
        if matches.is_present("project") {
            amend(matches.value_of("project").expect("missing project name"));
        }
    }

    if let Some(matches) = matches.subcommand_matches("edit") {
        edit(matches.value_of("project"));
    }

    match matches.subcommand_name() {
        Some("stop") => stop(),
        Some("cancel") => cancel(),
        Some("restart") => restart(),
        Some("log") => log(),
        Some("report") => report(),
        Some("status") => status(),
        _ => {},
    }
}

fn start(project_name: &str) {
    let mut periods = get_periods();

    if !periods.is_empty() {
        let last_index = periods.len() - 1;
        if let Some(period) = periods.get_mut(last_index) {
            if period.end_time.is_none() {
                let message = format!("project {} is being tracked", period.project);
                eprintln!("Error: {}",  message.red());
                return eprintln!("Try stopping your current project with {} first.", "stop".blue());
            }
        }
    }
    let current_period = create_period(project_name);
    // store current period in file
    print!("Started tracking project {} at {}", current_period.project.blue(), humanize_time(current_period.start_time));
    periods.push(current_period);
    save_periods(periods.to_vec());
}

fn status() {
    let mut periods = get_periods();
    if let Some(period) = periods.pop() {
        if period.end_time.is_none() {
            let diff = Utc::now().signed_duration_since(period.start_time);
            return println!("Project {} started {} ({})", period.project.magenta(), humanize_duration(diff), humanize_datetime(period.start_time).blue());
        }
    }
    eprintln!("No running project");
}

fn stop() {
    let mut periods = get_periods();
    let mut updated_period = false;
    let last_index = periods.len() - 1;
    if periods.len() > 0 {
        if let Some(period) = periods.get_mut(last_index) {
            if period.end_time.is_none() {
                period.end_time = Some(Utc::now());
                updated_period = true;
                let diff = Utc::now().signed_duration_since(period.start_time);
                println!("Stopped project {}, started {}", period.project.blue(), humanize_duration(diff));
            }
        }
    }
    if updated_period {
        save_periods(periods);
    } else {
        eprintln!("Error: {}", "No project started.".red());
    }
}

fn cancel() {
    let mut periods = get_periods();
    if let Some(period) = periods.pop() {
        if period.end_time.is_none() {
            save_periods(periods);
            let diff = Utc::now().signed_duration_since(period.start_time);
            println!("Canceled project {}, started {}", period.project.blue(), humanize_duration(diff));
            return
        }
    }
    eprintln!("Error: {}", "No project started".red());
}

fn restart() {
    let periods = get_periods();
    let mut new_periods = periods.to_vec();
    if let Some(period) = periods.last() {
        if !period.end_time.is_none() {
            let new_period = create_period(&period.project);
            new_periods.push(new_period);
            save_periods(new_periods);
            return println!("Tracking last running project: {}", period.project.blue());
        } else {
            let message = format!("No project to restart. Project {} is being tracked", period.project);
            eprintln!("Error: {}",  message.red());
            return eprintln!("Try stopping your current project with {} first.", "stop".blue());
        }
    }
    eprintln!("Error: {}", "No previous project to restart".red());
}

fn log() {
    let periods = get_periods();
    let periods_iter = periods.iter();

    for period in periods_iter {
        match period.end_time {
            Some(end_time) => {
                let diff = end_time.signed_duration_since(period.start_time);
                println!("{} from {} to {} [{}]", period.project, humanize_datetime(period.start_time), humanize_datetime(end_time), humanize_duration(diff));
            },
            None => {
                let diff = Utc::now().signed_duration_since(period.start_time);
                println!("{} from {} to {} [{}]", period.project, humanize_datetime(period.start_time), "in-progress", humanize_duration(diff));
            },
        }
    }
}

fn humanize_datetime(time: DateTime<Utc>) -> String {
    time.with_timezone(&Local).format("%F %H:%I %p").to_string()
}

fn humanize_time(time: DateTime<Utc>) -> String {
    time.with_timezone(&Local).format("%H:%I %p").to_string()
}

fn humanize_duration(time: Duration) -> String {
    let hours = time.num_hours();
    let minutes = time.num_minutes();
    let seconds = time.num_seconds();
    if minutes == 0 {
        if seconds < 5 {
            return String::from("just now")
        }
        return String::from("seconds ago")
    } else if hours == 0 {
        if minutes == 1 {
            return format!("{minutes} minute ago", minutes=minutes)
        } else {
            return format!("{minutes} minutes ago", minutes=minutes)
        }
    } else {
        return format!("{hours}:{minutes}", hours=hours, minutes=minutes)
    }
}

fn report() {
    unimplemented!();
}

fn amend(project_name: &str) {
    println!("Amend project: {:?}", project_name);
    unimplemented!();
}

fn edit(project_name: Option<&str>) {
    if let Some(name) = project_name {
        println!("Edit project: {}", name);
    }
    unimplemented!();
}

fn create_period(project: &str) -> Period {
    Period {
        project: String::from(project),
        start_time: Utc::now(),
        end_time: None,
    }
}

fn get_config_folder() -> PathBuf {
    let home_dir = env::var("HOME").expect("Failed to find home directory from environment 'HOME'");
    let mut config_folder = PathBuf::from(home_dir);
    config_folder.push(".config/doug");
    config_folder
}

fn get_config_file_path() -> PathBuf {
    let config_folder = get_config_folder();
    let mut config_file = PathBuf::from(&config_folder);
    config_file.push("periods.json");
    config_file
}

fn get_config_back_file_path() -> PathBuf {
    let config_file = get_config_file_path();
    config_file.with_extension("json-backup")
}

fn get_config_file() -> (File, Metadata) {
    let config_file = get_config_file_path();
    (OpenOptions::new()
        .create(true)
        .read(true)
        .write(true)
        .open(&config_file)
        .expect(&format!("Couldn't open datafile: {:?}", config_file)),
    fs::metadata(&config_file).expect("Couldn't access datafile metadata")
    )
}

fn get_periods() -> Vec<Period> {
    let config_folder = get_config_folder();

    match fs::create_dir(&config_folder) {
        Err(ref error) if error.kind() == ErrorKind::AlreadyExists => {},
        Err(error) => panic!("There was a problem creating the config directory: {:?}", error),
        Ok(_) => {},
    }

    let (file, metadata) = get_config_file();

    let periods: Result<Vec<Period>, Error> = serde_json::from_reader(file);
    let periods = match periods {
        Ok(p) => p,
        Err(_) if metadata.len() > 0 => Vec::new(),
        Err(error) => panic!("There was a serialization issue: {:?}", error),
    };
    periods
}

fn save_periods(periods: Vec<Period>) {
    let serialized = serde_json::to_string(&periods).expect("Couldn't serialize data to string");
    let config_file = get_config_file_path();
    let config_file_backup = get_config_back_file_path();
    fs::copy(&config_file, &config_file_backup).expect("Couldn't create backup file");
    let mut file = OpenOptions::new()
                    .create(true)
                    .write(true)
                    .truncate(true)
                    .open(&config_file)
                    .expect("Couldn't open file for saving period.");

    file.write_all(serialized.as_bytes()).expect("Couldn't write serialized data to file");
}
<commit_msg>Add better formatting for log command<commit_after>#[macro_use]
extern crate clap;
extern crate chrono;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
extern crate colored;

use std::env;
use std::fs;
use std::fs::{OpenOptions, File, Metadata};
use std::io::{Write, ErrorKind};
use std::path::PathBuf;
use std::collections::HashSet;

use chrono::{DateTime, Date, Utc, Local, Duration};
use clap::{App, Arg, AppSettings, SubCommand};
use serde_json::Error;
use colored::*;

#[derive(Serialize, Deserialize, Debug, Clone)]
struct Period {
    project: String,
    start_time: DateTime<Utc>,
    end_time: Option<DateTime<Utc>>,
}

fn main() {
    let matches = App::new("Doug")
        .version(crate_version!())
        .about("A time tracking command-line utility")
        .author(crate_authors!())
        .settings(&[
            AppSettings::DeriveDisplayOrder,
            AppSettings::GlobalVersion,
            AppSettings::SubcommandRequiredElseHelp,
            AppSettings::VersionlessSubcommands,
            AppSettings::DisableHelpSubcommand,
        ])
        .subcommand(SubCommand::with_name("start")
            .about("Track new or existing project")
            .arg(Arg::with_name("project")
                .help("project to track")
                .required(true)))
        .subcommand(SubCommand::with_name("status")
            .about("Display elapsed time, start time, and running project name"))
        .subcommand(SubCommand::with_name("stop")
            .about("Stop any running projects"))
        .subcommand(SubCommand::with_name("cancel")
            .about("Stop running project and remove most recent time interval"))
        .subcommand(SubCommand::with_name("restart")
            .about("Track last running project"))
        .subcommand(SubCommand::with_name("log")
            .about("Display time intervals across all projects"))
        .subcommand(SubCommand::with_name("report")
            .about("Display aggregate time from last week"))
        .subcommand(SubCommand::with_name("amend")
            .about("Change name of currently running project")
            .arg(Arg::with_name("project")
                .help("new project name")
                .required(true)))
        .subcommand(SubCommand::with_name("edit")
            .about("Edit last frame or currently running frame")
            .arg(Arg::with_name("project")
                .help("project to track")))
        .get_matches();

    if let Some(matches) = matches.subcommand_matches("start") {
        if matches.is_present("project") {
            start(matches.value_of("project").unwrap());
        }
    }

    if let Some(matches) = matches.subcommand_matches("amend") {
        if matches.is_present("project") {
            amend(matches.value_of("project").expect("missing project name"));
        }
    }

    if let Some(matches) = matches.subcommand_matches("edit") {
        edit(matches.value_of("project"));
    }

    match matches.subcommand_name() {
        Some("stop") => stop(),
        Some("cancel") => cancel(),
        Some("restart") => restart(),
        Some("log") => log(),
        Some("report") => report(),
        Some("status") => status(),
        _ => {},
    }
}

fn start(project_name: &str) {
    let mut periods = get_periods();

    if !periods.is_empty() {
        let last_index = periods.len() - 1;
        if let Some(period) = periods.get_mut(last_index) {
            if period.end_time.is_none() {
                let message = format!("project {} is being tracked", period.project);
                eprintln!("Error: {}",  message.red());
                return eprintln!("Try stopping your current project with {} first.", "stop".blue());
            }
        }
    }
    let current_period = create_period(project_name);
    // store current period in file
    print!("Started tracking project {} at {}", current_period.project.blue(), humanize_time(current_period.start_time));
    periods.push(current_period);
    save_periods(periods.to_vec());
}

fn status() {
    let mut periods = get_periods();
    if let Some(period) = periods.pop() {
        if period.end_time.is_none() {
            let diff = Utc::now().signed_duration_since(period.start_time);
            return println!("Project {} started {} ({})", period.project.magenta(), humanize_duration(diff), humanize_datetime(period.start_time).blue());
        }
    }
    eprintln!("No running project");
}

fn stop() {
    let mut periods = get_periods();
    let mut updated_period = false;
    let last_index = periods.len() - 1;
    if periods.len() > 0 {
        if let Some(period) = periods.get_mut(last_index) {
            if period.end_time.is_none() {
                period.end_time = Some(Utc::now());
                updated_period = true;
                let diff = Utc::now().signed_duration_since(period.start_time);
                println!("Stopped project {}, started {}", period.project.blue(), humanize_duration(diff));
            }
        }
    }
    if updated_period {
        save_periods(periods);
    } else {
        eprintln!("Error: {}", "No project started.".red());
    }
}

fn cancel() {
    let mut periods = get_periods();
    if let Some(period) = periods.pop() {
        if period.end_time.is_none() {
            save_periods(periods);
            let diff = Utc::now().signed_duration_since(period.start_time);
            println!("Canceled project {}, started {}", period.project.blue(), humanize_duration(diff));
            return
        }
    }
    eprintln!("Error: {}", "No project started".red());
}

fn restart() {
    let periods = get_periods();
    let mut new_periods = periods.to_vec();
    if let Some(period) = periods.last() {
        if !period.end_time.is_none() {
            let new_period = create_period(&period.project);
            new_periods.push(new_period);
            save_periods(new_periods);
            return println!("Tracking last running project: {}", period.project.blue());
        } else {
            let message = format!("No project to restart. Project {} is being tracked", period.project);
            eprintln!("Error: {}",  message.red());
            return eprintln!("Try stopping your current project with {} first.", "stop".blue());
        }
    }
    eprintln!("Error: {}", "No previous project to restart".red());
}

fn log() {
    let periods = get_periods();
    let periods_iter = periods.iter();
    let mut days: HashSet<Date<chrono::Local>> = HashSet::new();

    for period in periods_iter {
        let time = period.start_time.with_timezone(&Local).date();
        if !days.contains(&time) {
            // Monday 16 October 2017 (3h 20m 52s)
            println!("{}", period.start_time.with_timezone(&Local).format("%A %-d %B %Y").to_string());
        }
        days.insert(time);
        match period.end_time {
            Some(end_time) => {
                let diff = end_time.signed_duration_since(period.start_time);
                println!("    {start} to {end} {project} {duration}", project=period.project, start=humanize_time(period.start_time), end=humanize_time(end_time), duration=format_duration(diff));
            },
            None => {
                let diff = Utc::now().signed_duration_since(period.start_time);
                println!("    {start} to --:-- {project} {duration}", project=period.project, start=humanize_time(period.start_time), duration=format_duration(diff));
            },
        }
    }
}

fn humanize_datetime(time: DateTime<Utc>) -> String {
    time.with_timezone(&Local).format("%F %H:%M").to_string()
}

fn humanize_time(time: DateTime<Utc>) -> String {
    time.with_timezone(&Local).format("%H:%M").to_string()
}

fn format_duration(duration: Duration) -> String{
    let days = duration.num_days();
    let hours = duration.num_hours();
    let minutes = duration.num_minutes();
    let seconds = duration.num_seconds();
    if minutes == 0 {
        return format!("{}s", seconds)
    } else if hours == 0 {
        return format!("{minutes}m", minutes=minutes)
    } else if days == 0 {
        return format!("{hours}h, {minutes}m", hours=hours, minutes=minutes/(hours*60))
    } else {
        return format!("{days}d, {hours}h, {minutes}m", hours=hours/(days*24), minutes=minutes/(hours*60), days=days)
    }
}

fn humanize_duration(time: Duration) -> String {
    let hours = time.num_hours();
    let minutes = time.num_minutes();
    let seconds = time.num_seconds();
    if minutes == 0 {
        if seconds < 5 {
            return String::from("just now")
        }
        return String::from("seconds ago")
    } else if hours == 0 {
        if minutes == 1 {
            return format!("{minutes} minute ago", minutes=minutes)
        } else {
            return format!("{minutes} minutes ago", minutes=minutes)
        }
    } else {
        return format!("{hours}:{minutes}", hours=hours, minutes=minutes)
    }
}

fn report() {
    unimplemented!();
}

fn amend(project_name: &str) {
    println!("Amend project: {:?}", project_name);
    unimplemented!();
}

fn edit(project_name: Option<&str>) {
    if let Some(name) = project_name {
        println!("Edit project: {}", name);
    }
    unimplemented!();
}

fn create_period(project: &str) -> Period {
    Period {
        project: String::from(project),
        start_time: Utc::now(),
        end_time: None,
    }
}

fn get_config_folder() -> PathBuf {
    let home_dir = env::var("HOME").expect("Failed to find home directory from environment 'HOME'");
    let mut config_folder = PathBuf::from(home_dir);
    config_folder.push(".config/doug");
    config_folder
}

fn get_config_file_path() -> PathBuf {
    let config_folder = get_config_folder();
    let mut config_file = PathBuf::from(&config_folder);
    config_file.push("periods.json");
    config_file
}

fn get_config_back_file_path() -> PathBuf {
    let config_file = get_config_file_path();
    config_file.with_extension("json-backup")
}

fn get_config_file() -> (File, Metadata) {
    let config_file = get_config_file_path();
    (OpenOptions::new()
        .create(true)
        .read(true)
        .write(true)
        .open(&config_file)
        .expect(&format!("Couldn't open datafile: {:?}", config_file)),
    fs::metadata(&config_file).expect("Couldn't access datafile metadata")
    )
}

fn get_periods() -> Vec<Period> {
    let config_folder = get_config_folder();

    match fs::create_dir(&config_folder) {
        Err(ref error) if error.kind() == ErrorKind::AlreadyExists => {},
        Err(error) => panic!("There was a problem creating the config directory: {:?}", error),
        Ok(_) => {},
    }

    let (file, metadata) = get_config_file();

    let periods: Result<Vec<Period>, Error> = serde_json::from_reader(file);
    let periods = match periods {
        Ok(p) => p,
        Err(_) if metadata.len() > 0 => Vec::new(),
        Err(error) => panic!("There was a serialization issue: {:?}", error),
    };
    periods
}

fn save_periods(periods: Vec<Period>) {
    let serialized = serde_json::to_string(&periods).expect("Couldn't serialize data to string");
    let config_file = get_config_file_path();
    let config_file_backup = get_config_back_file_path();
    fs::copy(&config_file, &config_file_backup).expect("Couldn't create backup file");
    let mut file = OpenOptions::new()
                    .create(true)
                    .write(true)
                    .truncate(true)
                    .open(&config_file)
                    .expect("Couldn't open file for saving period.");

    file.write_all(serialized.as_bytes()).expect("Couldn't write serialized data to file");
}
<|endoftext|>


<commit_before>extern crate byteorder;
extern crate piston_window;
// extern crate find_folder;
extern crate sdl2;

use std::env;
use sdl2::image::{LoadTexture, INIT_PNG, INIT_JPG};
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::pixels::{Color, PixelFormatEnum};
use sdl2::render::Texture;

use piston_window::*;
use std::path::Path;

use std::fs::File;
use std::io::{Read, Seek, SeekFrom, BufReader};
use std::fmt;

use byteorder::{NativeEndian, ReadBytesExt};

use std::str::FromStr;

#[derive(Debug)]
struct StyleFile {
    header: StyleFileHeader,
    chunks: StyleFileChunks
}

#[derive(Debug)]
struct StyleFileHeader {
    file_type: String,
    version: u16
}

#[derive(Debug)]
struct StyleFileChunks {
    tiles: Vec<Vec<u8>>
}

impl StyleFile {
    fn from_file(file: &File) -> StyleFile {
        let mut buf_reader = BufReader::new(file);

        let header = read_header(&mut buf_reader);
        let chunks = match read_chunks(&mut buf_reader) {
            Some(c) => c,
            None => panic!("Error while reading chunks.")
        };

        StyleFile {
            header,
            chunks
        }
    }
}

fn read_header<T: Read>(buf_reader: &mut T) -> StyleFileHeader {
    let mut buffer = [0; 4];

    buf_reader.read_exact(&mut buffer);
    let file_type = String::from_utf8(buffer.to_vec()).unwrap();

    let version = buf_reader.read_u16::<NativeEndian>().unwrap();

    StyleFileHeader {
        file_type,
        version
    }
}

enum StyleFileChunkTypes {
    PaletteIndex,
    PhysicalPalettes,
    PaletteBase,
    Tiles,
    SpriteGraphics,
    SpriteIndex,
    SpritesBases,
    DeltaStore,
    DeltaIndex,
    FontBase,
    CarInfo,
    MapObjectInfo,
    PSXTiles,
    CarRecyclingInfo
}

struct StyleChunkParseError();

impl FromStr for StyleFileChunkTypes {
    type Err = StyleChunkParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "PALX" => Ok(StyleFileChunkTypes::PaletteIndex),
            "PPAL" => Ok(StyleFileChunkTypes::PhysicalPalettes),
            "PALB" => Ok(StyleFileChunkTypes::PaletteBase),
            "TILE" => Ok(StyleFileChunkTypes::Tiles),
            "SPRG" => Ok(StyleFileChunkTypes::SpriteGraphics),
            "SPRX" => Ok(StyleFileChunkTypes::SpriteIndex),
            "SPRB" => Ok(StyleFileChunkTypes::SpritesBases),
            "DELS" => Ok(StyleFileChunkTypes::DeltaStore),
            "DELX" => Ok(StyleFileChunkTypes::DeltaIndex),
            "FONB" => Ok(StyleFileChunkTypes::FontBase),
            "CARI" => Ok(StyleFileChunkTypes::CarInfo),
            "OBJI" => Ok(StyleFileChunkTypes::MapObjectInfo),
            "PSXT" => Ok(StyleFileChunkTypes::PSXTiles),
            "RECY" => Ok(StyleFileChunkTypes::CarRecyclingInfo),
            _ => Err(StyleChunkParseError())
        }
    }
}

fn read_chunks<T: Read + Seek>(mut buf_reader: &mut T) -> Option<StyleFileChunks> {
    let mut buffer = [0; 4];

    loop {
        buf_reader.read_exact(&mut buffer);

        let chunk_type = match String::from_utf8(buffer.to_vec()) {
            Ok(s) => s,
            Err(_) => return None
        };

        let size = match buf_reader.read_u32::<NativeEndian>() {
            Ok(s) => s,
            Err(_) => return None
        };

        println!("Chunk-type: {}\nChunk size: {}", chunk_type, size);
        buf_reader.seek(SeekFrom::Current(256*256*7 as i64)).unwrap();

        match StyleFileChunkTypes::from_str(&chunk_type) {
            Ok(StyleFileChunkTypes::Tiles) => {
                let tiles = load_tiles(&mut buf_reader);
                return Some(StyleFileChunks{ tiles })
            },
            Ok(_) => {},
            Err(_) => println!("Tile parse error.")
        }

        buf_reader.seek(SeekFrom::Current(size as i64)).unwrap();
    }
}

const  PAGE_SIZE: usize = 256;
const  IMAGE_SIZE: usize = 64;

fn load_tiles<T: Read + Seek>(buf_reader: &mut T) -> Vec<Vec<u8>> {
    let mut tiles: Vec<Vec<u8>> = Vec::with_capacity(16); // one page

    // load page
    let mut page: [u8; PAGE_SIZE*PAGE_SIZE] = [0; PAGE_SIZE*PAGE_SIZE];
    for pixel in page.iter_mut() {
        *pixel = buf_reader.read_u8().unwrap();
    }
    let page = page;

    for id in 0..1 {
        let mut tile = Vec::with_capacity(IMAGE_SIZE*IMAGE_SIZE);

        for y in 0..IMAGE_SIZE {
            for x in 0..IMAGE_SIZE {
                // tile.push(page[(y + (id / 4) * 64) *4 256 + (x + (id % 4) * 64)]);
                tile.push(page[(y * PAGE_SIZE) + x]);
            }
        }
        tiles.push(tile);
    }

    tiles
}

impl fmt::Display for StyleFileHeader {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "File type: {}\nVersion: {}", self.file_type, self.version)
    }
}

impl fmt::Display for StyleFile {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Header:\n{}", self.header)
    }
}

fn main() {
    let file = File::open("data/bil.sty").unwrap();
    // let file = File::open("data/MP1-comp.gmp").unwrap();

    let style = StyleFile::from_file(&file);

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let mut windows = Vec::new();

    for tile in style.chunks.tiles {
        windows.push(show_tile(&video_subsystem, &tile));
    }

    'mainloop: loop {
        for event in sdl_context.event_pump().unwrap().poll_iter() {
            match event {
                Event::Quit{..} |
                Event::KeyDown {keycode: Option::Some(Keycode::Escape), ..} =>
                    break 'mainloop,
                _ => {}
            }
        }
    }
}

pub fn show_tile(video_subsystem: &sdl2::VideoSubsystem, tile: &[u8]) -> sdl2::video::Window {
    let window = video_subsystem.window("rust-sdl2 demo: Video", 512, 512)
      .position_centered()
      .build()
      .unwrap();

    let mut canvas = window.into_canvas().software().build().unwrap();
    let texture_creator = canvas.texture_creator();

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

    let mut texture = texture_creator.create_texture_static(
        Some(PixelFormatEnum::BGRA4444),
        IMAGE_SIZE as u32,
        IMAGE_SIZE as u32
    ).unwrap();
    texture.update(None, tile, IMAGE_SIZE);

    canvas.copy(&texture, None, None).expect("Render failed");
    canvas.present();

    canvas.into_window()
}
<commit_msg>Cleanup tiles loading<commit_after>extern crate byteorder;
extern crate piston_window;
// extern crate find_folder;
extern crate sdl2;

use std::env;
use sdl2::image::{LoadTexture, INIT_PNG, INIT_JPG};
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::pixels::{Color, PixelFormatEnum};
use sdl2::render::Texture;

use piston_window::*;
use std::path::Path;

use std::fs::File;
use std::io::{Read, Seek, SeekFrom, BufReader};
use std::fmt;

use byteorder::{NativeEndian, ReadBytesExt};

use std::str::FromStr;

#[derive(Debug)]
struct StyleFile {
    header: StyleFileHeader,
    chunks: StyleFileChunks
}

#[derive(Debug)]
struct StyleFileHeader {
    file_type: String,
    version: u16
}

#[derive(Debug)]
struct StyleFileChunks {
    tiles: Vec<Vec<u8>>
}

impl StyleFile {
    fn from_file(file: &File) -> StyleFile {
        let mut buf_reader = BufReader::new(file);

        let header = read_header(&mut buf_reader);
        let chunks = match read_chunks(&mut buf_reader) {
            Some(c) => c,
            None => panic!("Error while reading chunks.")
        };

        StyleFile {
            header,
            chunks
        }
    }
}

fn read_header<T: Read>(buf_reader: &mut T) -> StyleFileHeader {
    let mut buffer = [0; 4];

    buf_reader.read_exact(&mut buffer);
    let file_type = String::from_utf8(buffer.to_vec()).unwrap();

    let version = buf_reader.read_u16::<NativeEndian>().unwrap();

    StyleFileHeader {
        file_type,
        version
    }
}

enum StyleFileChunkTypes {
    PaletteIndex,
    PhysicalPalettes,
    PaletteBase,
    Tiles,
    SpriteGraphics,
    SpriteIndex,
    SpritesBases,
    DeltaStore,
    DeltaIndex,
    FontBase,
    CarInfo,
    MapObjectInfo,
    PSXTiles,
    CarRecyclingInfo
}

struct StyleChunkParseError();

impl FromStr for StyleFileChunkTypes {
    type Err = StyleChunkParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "PALX" => Ok(StyleFileChunkTypes::PaletteIndex),
            "PPAL" => Ok(StyleFileChunkTypes::PhysicalPalettes),
            "PALB" => Ok(StyleFileChunkTypes::PaletteBase),
            "TILE" => Ok(StyleFileChunkTypes::Tiles),
            "SPRG" => Ok(StyleFileChunkTypes::SpriteGraphics),
            "SPRX" => Ok(StyleFileChunkTypes::SpriteIndex),
            "SPRB" => Ok(StyleFileChunkTypes::SpritesBases),
            "DELS" => Ok(StyleFileChunkTypes::DeltaStore),
            "DELX" => Ok(StyleFileChunkTypes::DeltaIndex),
            "FONB" => Ok(StyleFileChunkTypes::FontBase),
            "CARI" => Ok(StyleFileChunkTypes::CarInfo),
            "OBJI" => Ok(StyleFileChunkTypes::MapObjectInfo),
            "PSXT" => Ok(StyleFileChunkTypes::PSXTiles),
            "RECY" => Ok(StyleFileChunkTypes::CarRecyclingInfo),
            _ => Err(StyleChunkParseError())
        }
    }
}

fn read_chunks<T: Read + Seek>(mut buf_reader: &mut T) -> Option<StyleFileChunks> {
    let mut buffer = [0; 4];

    loop {
        buf_reader.read_exact(&mut buffer);

        let chunk_type = match String::from_utf8(buffer.to_vec()) {
            Ok(s) => s,
            Err(_) => return None
        };

        let size = match buf_reader.read_u32::<NativeEndian>() {
            Ok(s) => s,
            Err(_) => return None
        };

        println!("Chunk-type: {}\nChunk size: {}", chunk_type, size);
        buf_reader.seek(SeekFrom::Current(256*256*7 as i64)).unwrap();

        match StyleFileChunkTypes::from_str(&chunk_type) {
            Ok(StyleFileChunkTypes::Tiles) => {
                let tiles = load_tiles(&mut buf_reader);
                return Some(StyleFileChunks{ tiles })
            },
            Ok(_) => {},
            Err(_) => println!("Tile parse error.")
        }

        buf_reader.seek(SeekFrom::Current(size as i64)).unwrap();
    }
}

const  PAGE_SIZE: usize = 256;
const  IMAGE_SIZE: usize = 64;

fn load_tiles<T: Read + Seek>(buf_reader: &mut T) -> Vec<Vec<u8>> {
    let mut tiles: Vec<Vec<u8>> = Vec::with_capacity(16); // one page

    // load page
    let mut page: [u8; PAGE_SIZE*PAGE_SIZE] = [0; PAGE_SIZE*PAGE_SIZE];
    for pixel in page.iter_mut() {
        *pixel = buf_reader.read_u8().unwrap();
    }
    let page = page;

    for id in 0..16 {
        let y_start = (id / 4) * IMAGE_SIZE;
        let y_end = y_start + IMAGE_SIZE;
        let mut tile = Vec::with_capacity(IMAGE_SIZE*IMAGE_SIZE);

        for y in y_start..y_end {
            let x_start = (id % 4) * IMAGE_SIZE;
            let x_end = x_start + IMAGE_SIZE;

            for x in x_start..x_end {
                tile.push(page[(y * PAGE_SIZE) + x]);
            }
        }
        tiles.push(tile);
    }

    tiles
}

impl fmt::Display for StyleFileHeader {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "File type: {}\nVersion: {}", self.file_type, self.version)
    }
}

impl fmt::Display for StyleFile {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Header:\n{}", self.header)
    }
}

fn main() {
    let file = File::open("data/bil.sty").unwrap();
    // let file = File::open("data/MP1-comp.gmp").unwrap();

    let style = StyleFile::from_file(&file);

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let mut windows = Vec::new();

    for tile in style.chunks.tiles {
        windows.push(show_tile(&video_subsystem, &tile));
    }

    'mainloop: loop {
        for event in sdl_context.event_pump().unwrap().poll_iter() {
            match event {
                Event::Quit{..} |
                Event::KeyDown {keycode: Option::Some(Keycode::Escape), ..} =>
                    break 'mainloop,
                _ => {}
            }
        }
    }
}

pub fn show_tile(video_subsystem: &sdl2::VideoSubsystem, tile: &[u8]) -> sdl2::video::Window {
    let window = video_subsystem.window("rust-sdl2 demo: Video", 512, 512)
      .position_centered()
      .build()
      .unwrap();

    let mut canvas = window.into_canvas().software().build().unwrap();
    let texture_creator = canvas.texture_creator();

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

    let mut texture = texture_creator.create_texture_static(
        Some(PixelFormatEnum::RGB332),
        IMAGE_SIZE as u32,
        IMAGE_SIZE as u32
    ).unwrap();
    texture.update(None, tile, IMAGE_SIZE);

    canvas.copy(&texture, None, None).expect("Render failed");
    canvas.present();

    canvas.into_window()
}
<|endoftext|>


<commit_before>extern crate serde_json;
extern crate silkthread_base;
extern crate silkthread_toolkit;
extern crate silkthread_lang;

use serde_json::*;

use silkthread_base::*;
use silkthread_base::basic::*;
use silkthread_toolkit::io::*;
use silkthread_toolkit::io::tool::*;
use silkthread_lang::script::*;
use silkthread_lang::script::tool::*;

fn main() {
    // Start up
    let main_env = DynamicEnvironment::new();
    main_env.import(IoTools::new_stdio());
    main_env.import(ScriptTools::new());

    // Display a header
    let print_string = main_env.get_typed_tool::<String, ()>("print").unwrap();
    print_string.invoke(format!("{} {} by {}\n", env!("CARGO_PKG_NAME"),  env!("CARGO_PKG_VERSION"), env!("CARGO_PKG_AUTHORS")), &main_env).unwrap();

    // Start a REPL
    loop {
        let print_string    = main_env.get_typed_tool::<String, ()>(PRINT).unwrap();
        let print_value     = main_env.get_typed_tool::<Value, ()>(PRINT).unwrap();
        let read_line       = main_env.get_typed_tool::<(), ReadLineResult>(READ_LINE).unwrap();
        let lex_line        = main_env.get_typed_tool::<String, Value>(LEX_SCRIPT).unwrap();
        let parse_script    = main_env.get_json_tool(PARSE_SCRIPT).unwrap();
        let eval_script     = main_env.get_json_tool(EVAL_SCRIPT).unwrap();
        let display_prompt  = main_env.get_typed_tool::<(), ()>("display-prompt");

        // Display a prompt
        display_prompt
            .map(|tool| tool.invoke((), &main_env).unwrap())
            .map_err(|_| print_string.invoke(String::from("\n=» "), &main_env).unwrap())
            .unwrap_or(());

        // Read the next line
        let next_line = read_line.invoke((), &main_env);

        match next_line {
            Ok(result) => {
                // Process the line
                // TODO!
                let lexed       = lex_line.invoke(result.line, &main_env).unwrap();
                let parsed      = parse_script.invoke_json(lexed, &main_env).unwrap();
                let eval_result = eval_script.invoke_json(parsed, &main_env);
                print_value.invoke(eval_result.unwrap(), &main_env).unwrap();
                print_string.invoke(String::from("\n"), &main_env).unwrap();

                // Stop on EOF
                if result.eof {
                    break;
                }
            },

            Err(erm) => {
                // Stop if we hit an error
                print_string.invoke(String::from("Error while reading from prompt: "), &main_env).unwrap();
                print_value.invoke(erm, &main_env).unwrap();
                break;
            },
        }
    }
}
<commit_msg>Use a slightly safer way of decoding/evaluating the input<commit_after>extern crate serde_json;
extern crate silkthread_base;
extern crate silkthread_toolkit;
extern crate silkthread_lang;

use serde_json::*;

use silkthread_base::*;
use silkthread_base::basic::*;
use silkthread_toolkit::io::*;
use silkthread_toolkit::io::tool::*;
use silkthread_lang::script::*;
use silkthread_lang::script::tool::*;

fn main() {
    // Start up
    let main_env = DynamicEnvironment::new();
    main_env.import(IoTools::new_stdio());
    main_env.import(ScriptTools::new());

    // Display a header
    let print_string = main_env.get_typed_tool::<String, ()>("print").unwrap();
    print_string.invoke(format!("{} {} by {}\n", env!("CARGO_PKG_NAME"),  env!("CARGO_PKG_VERSION"), env!("CARGO_PKG_AUTHORS")), &main_env).unwrap();

    // Start a REPL
    loop {
        let print_string    = main_env.get_typed_tool::<String, ()>(PRINT).unwrap();
        let print_value     = main_env.get_typed_tool::<Value, ()>(PRINT).unwrap();
        let read_line       = main_env.get_typed_tool::<(), ReadLineResult>(READ_LINE).unwrap();
        let lex_line        = main_env.get_typed_tool::<String, Value>(LEX_SCRIPT).unwrap();
        let parse_script    = main_env.get_json_tool(PARSE_SCRIPT).unwrap();
        let eval_script     = main_env.get_json_tool(EVAL_SCRIPT).unwrap();
        let display_prompt  = main_env.get_typed_tool::<(), ()>("display-prompt");

        // Display a prompt
        display_prompt
            .map(|tool| tool.invoke((), &main_env).unwrap())
            .map_err(|_| print_string.invoke(String::from("\n=» "), &main_env).unwrap())
            .unwrap_or(());

        // Read the next line
        let next_line = read_line.invoke((), &main_env);

        match next_line {
            Ok(result) => {
                // Evaluate the result
                let eval_result = lex_line.invoke(result.line, &main_env)
                    .and_then(|lexed| parse_script.invoke_json(lexed, &main_env))
                    .and_then(|parsed| eval_script.invoke_json(parsed, &main_env));

                // Print it out
                match eval_result {
                    Ok(Value::Null) => { },
                    Ok(not_null)    => { print_value.invoke(not_null, &main_env).unwrap(); },
                    Err(erm)        => {
                        print_string.invoke(String::from("*** Error: "), &main_env).unwrap();
                        print_value.invoke(erm, &main_env).unwrap();
                    }
                }

                print_string.invoke(String::from("\n"), &main_env).unwrap();

                // Stop on EOF
                if result.eof {
                    break;
                }
            },

            Err(erm) => {
                // Stop if we hit an error
                print_string.invoke(String::from("Error while reading from prompt: "), &main_env).unwrap();
                print_value.invoke(erm, &main_env).unwrap();
                break;
            },
        }
    }
}
<|endoftext|>


<commit_before>extern crate glob;
extern crate http;
extern crate hyper;
extern crate hyper_tls;
#[macro_use]
extern crate lazy_static;
extern crate libc;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate structopt;
extern crate toml;

mod error;
mod ghclient;
mod statics;
mod structs;
#[macro_use]
mod syslog;

use statics::CONF_PATH;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
enum Command {
    /// Gets user public key
    #[structopt(name = "key")]
    Key {
        #[structopt(parse(from_str))]
        user: String,
    },
    /// Executes pam check
    #[structopt(name = "pam")]
    Pam,
    /// Check configuration
    #[structopt(name = "check")]
    Check {
        #[structopt(parse(from_os_str))]
        confpath: std::path::PathBuf,
    },
    /// Cleans caches up
    #[structopt(name = "cleanup")]
    CleanUp,
    /// Get rate limit for github api
    #[structopt(name = "ratelimit")]
    RateLimit,
    /// Displays version details
    #[structopt(name = "version")]
    Version,
}

fn main() {
    let command = Command::from_args();

    use ghclient::GithubClient;
    use std::env;
    use std::process;
    use structs::Config;

    match command {
        Command::Check { confpath } => match Config::from_path(&confpath) {
            Ok(_) => process::exit(0),
            Err(_) => process::exit(11),
        },
        Command::Key { user } => {
            match Config::from_path(&CONF_PATH).and_then(|conf| Ok(GithubClient::new(&conf)))
                                               .and_then(|client| client.print_user_public_key(&user))
            {
                Ok(_) => process::exit(0),
                Err(_) => process::exit(21),
            }
        }
        Command::Pam => match env::var("PAM_USER") {
            Ok(user) => match Config::from_path(&CONF_PATH).and_then(|conf| Ok(GithubClient::new(&conf)))
                                                           .and_then(|client| client.check_pam(&user))
            {
                Ok(true) => process::exit(0),
                Ok(false) => process::exit(1),
                Err(_) => process::exit(31),
            },
            Err(_) => process::exit(41),
        },
        Command::CleanUp => match Config::from_path(&CONF_PATH).and_then(|conf| Ok(GithubClient::new(&conf)))
                                                               .and_then(|client| client.clear_all_caches())
        {
            Ok(_) => process::exit(0),
            Err(_) => process::exit(51),
        },
        Command::RateLimit => match Config::from_path(&CONF_PATH).and_then(|conf| Ok(GithubClient::new(&conf)))
                                                                 .and_then(|client| client.print_rate_limit())
        {
            Ok(_) => process::exit(0),
            Err(_) => process::exit(61),
        },
        Command::Version => {
            println!("{}",
                     concat!(env!("CARGO_PKG_VERSION"),
                             include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt"))));
        }
    };
}
<commit_msg>Add helper command for completion<commit_after>extern crate glob;
extern crate http;
extern crate hyper;
extern crate hyper_tls;
#[macro_use]
extern crate lazy_static;
extern crate libc;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate structopt;
extern crate toml;

mod error;
mod ghclient;
mod statics;
mod structs;
#[macro_use]
mod syslog;

use statics::CONF_PATH;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
enum Command {
    /// Gets user public key
    #[structopt(name = "key")]
    Key {
        #[structopt(parse(from_str))]
        user: String,
    },
    /// Executes pam check
    #[structopt(name = "pam")]
    Pam,
    /// Check configuration
    #[structopt(name = "check")]
    Check {
        #[structopt(parse(from_os_str))]
        confpath: std::path::PathBuf,
    },
    /// Cleans caches up
    #[structopt(name = "cleanup")]
    CleanUp,
    /// Get rate limit for github api
    #[structopt(name = "ratelimit")]
    RateLimit,
    /// Displays version details
    #[structopt(name = "version")]
    Version,
    /// Displays completion
    #[structopt(name = "completion")]
    Completion {
        #[structopt(subcommand)]
        shell: Shell,
    },
}

#[derive(Debug, StructOpt)]
enum Shell {
    #[structopt(name = "bash")]
    Bash,
    #[structopt(name = "fish")]
    Fish,
    #[structopt(name = "zsh")]
    Zsh,
    #[structopt(name = "powershell")]
    PowerShell,
    #[structopt(name = "elvish")]
    Elvish,
}

fn main() {
    let command = Command::from_args();

    use ghclient::GithubClient;
    use std::env;
    use std::process;
    use structs::Config;

    match command {
        Command::Check { confpath } => match Config::from_path(&confpath) {
            Ok(_) => process::exit(0),
            Err(_) => process::exit(11),
        },
        Command::Key { user } => {
            match Config::from_path(&CONF_PATH).and_then(|conf| Ok(GithubClient::new(&conf)))
                                               .and_then(|client| client.print_user_public_key(&user))
            {
                Ok(_) => process::exit(0),
                Err(_) => process::exit(21),
            }
        }
        Command::Pam => match env::var("PAM_USER") {
            Ok(user) => match Config::from_path(&CONF_PATH).and_then(|conf| Ok(GithubClient::new(&conf)))
                                                           .and_then(|client| client.check_pam(&user))
            {
                Ok(true) => process::exit(0),
                Ok(false) => process::exit(1),
                Err(_) => process::exit(31),
            },
            Err(_) => process::exit(41),
        },
        Command::CleanUp => match Config::from_path(&CONF_PATH).and_then(|conf| Ok(GithubClient::new(&conf)))
                                                               .and_then(|client| client.clear_all_caches())
        {
            Ok(_) => process::exit(0),
            Err(_) => process::exit(51),
        },
        Command::RateLimit => match Config::from_path(&CONF_PATH).and_then(|conf| Ok(GithubClient::new(&conf)))
                                                                 .and_then(|client| client.print_rate_limit())
        {
            Ok(_) => process::exit(0),
            Err(_) => process::exit(61),
        },
        Command::Version => {
            println!("{}",
                     concat!(env!("CARGO_PKG_VERSION"),
                             include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt"))));
        }
        Command::Completion { shell } => {
            let shell = match shell {
                Shell::Bash => structopt::clap::Shell::Bash,
                Shell::Fish => structopt::clap::Shell::Fish,
                Shell::Zsh => structopt::clap::Shell::Zsh,
                Shell::PowerShell => structopt::clap::Shell::PowerShell,
                Shell::Elvish => structopt::clap::Shell::Elvish,
            };
            Command::clap().gen_completions_to("sectora", shell, &mut std::io::stdout());
        }
    };
}
<|endoftext|>


<commit_before>#![feature(globs)]

// Load external crates provided via cargo.
extern crate graphics;
extern crate piston;
extern crate sdl2_game_window;
extern crate opengl_graphics;

// Texture is used for images; Gl for accessing OpenGL
use opengl_graphics::{
    Gl,
    Texture,
};

// For creating a window
use sdl2_game_window::WindowSDL2;

use piston::{
    AssetStore,                     // Managing assets
    EventIterator,                  // Used for the game loop
    EventSettings,                  // Struct used for setting and updates
    WindowSettings,                 // Struct defines window config
    Render,                         // Called each iteration of the game loop
};

use piston::graphics::*;

// Game Constants
pub static WIN_HEIGHT: int = 480;
pub static WIN_WIDTH: int = 800;

fn run( config: GameConfig ) {

    // Values for Window Creation
    let opengl = piston::shader_version::opengl::OpenGL_3_2;
    let window_settings = WindowSettings {
            title: "Centipede-RS".to_string(),
            size: [config.window_width, config.window_height],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        };

    // Create SDL Window
    let mut window = WindowSDL2::new(
        opengl,
        window_settings
    );

    // Create Asset Store
    let asset_store = AssetStore::from_folder("../bin/assets");

    // Load Logo from Asset Store
    let image = asset_store.path("rust-logo.png").unwrap();
    let image = Texture::from_path(&image).unwrap();

    // Create Settings for Game loop
    let event_settings = EventSettings {
            updates_per_second: config.updates_per_second,
            max_frames_per_second: config.max_frames_per_second,
        };

    // Create new OpenGL Handle
    let ref mut gl = Gl::new(opengl);

    let mut yellow = 0.0;

    // For each e in Event Iterator (whose range is 0 to infinity)
    // e becomes a new Event by passing our window and event settings
    for e in EventIterator::new(&mut window, &event_settings) {

        // If e is Render(args) do something, else return ()?
        match e {
            Render(args) => {

                yellow = yellow + 0.001;

                // Creates viewport at 0,0 with width and height of window.
                gl.viewport(0, 0, args.width as i32, args.height as i32);

                // graphics::context a new drawing context (think html5)
                let c = Context::abs(args.width as f64, args.height as f64);

                // I'm guessing this draws white across the entire window
                c.rgb(1.0, 1.0, 1.0).draw(gl);

                let num_cols = config.window_width as int / config.tile_size as int;

                let num_rows = config.window_height as int / config.tile_size as int;

                let mut green = 0.0;

                // Draw a square
                for row in range(0i, num_rows ) {

                    let mut red = 0.0;

                    green = green + 0.02;

                    let row_shift: f64 = row as f64 * config.tile_size as f64;

                    for col in range(0i, num_cols ) {

                        let col_shift: f64 = col as f64 * config.tile_size as f64;

                        red = red + 0.02;

                        c.square(
                            col_shift,
                            row_shift,
                            config.tile_size as f64
                        ).rgb(red, green, yellow).draw(gl);

                    }

                }

                // Draws the texture we loaded previously in the screen.
                // Next question: how do I draw this somewhere else?
                //c.image(&image).draw(gl);
            },
            _ => {},
        }
    }

}

struct GameConfig {
    window_height: u32,
    window_width: u32,
    updates_per_second: u64,
    max_frames_per_second: u64,
    tile_size: uint
}

fn main() {

    let config = GameConfig {
            window_height: 480,
            window_width: 800,
            updates_per_second: 120,
            max_frames_per_second: 60,
            tile_size: 32,
        };

    run( config );

}

<commit_msg>Refactoring game loop into Game struct<commit_after>#![feature(globs)]

// Load external crates provided via cargo.
extern crate graphics;
extern crate piston;
extern crate sdl2_game_window;
extern crate opengl_graphics;

// Texture is used for images; Gl for accessing OpenGL
use opengl_graphics::{
    Gl,
};

// For creating a window
use sdl2_game_window::WindowSDL2;

// Stuff from piston.
use piston::{
    EventIterator,                  // Used for the game loop
    EventSettings,                  // Struct used for setting and updates
    WindowSettings,                 // Struct defines window config
    Render,                         // Render Evemt
};

use piston::graphics::*;
use piston::shader_version::opengl;

// Config options for the game.
struct GameConfig {
    title: String,
    window_height: u32,
    window_width: u32,
    updates_per_second: u64,
    max_frames_per_second: u64,
    tile_size: uint
}

// Represents the Game Loop
struct Game {
    config: GameConfig
}

// Represents the Game Loop
impl Game {

    // Returns a new game struct
    pub fn new( config: GameConfig ) -> Game {

        // Return a new Game
        Game {
            config: config,
        }

    }

    // Run the game loop
    pub fn run( &mut self ) {

        let mut window = self.window();

        // Get Gl
        let ref mut gl = Gl::new( opengl::OpenGL_3_2 );

        // Create Settings for Game loop
        let event_settings = EventSettings {
                updates_per_second: self.config.updates_per_second,
                max_frames_per_second: self.config.max_frames_per_second,
            };

        // For each e in Event Iterator (whose range is 0 to infinity)
        // e becomes a new Event by passing our window and event settings
        for e in EventIterator::new(&mut window, &event_settings) {

            // If e is Render(args) do something, else return ()?
            match e {
                Render(args) => self.render( gl ),
                _ => {},
            }

        }

    }

    // Returns a window.
    fn window( &self ) -> WindowSDL2 {

        // Values for Window Creation
        let window_settings = WindowSettings {
                title: self.config.title.to_string(),
                size: [self.config.window_width, self.config.window_height],
                fullscreen: false,
                exit_on_esc: true,
                samples: 0,
            };

        // Create SDL Window
        WindowSDL2::new(
            opengl::OpenGL_3_2,
            window_settings
        )
    }

    // Render the game state to the screen.
    fn render( &mut self, gl: &mut Gl ) {

        let width = self.config.window_width;
        let height = self.config.window_height;

        // Creates viewport at 0,0 with width and height of window.
        gl.viewport(0, 0, width as i32, height as i32);

        // graphics::context a new drawing context (think html5)
        let c = Context::abs(width as f64, height as f64);

        // I'm guessing this draws white across the entire window
        c.rgb(1.0, 1.0, 1.0).draw(gl);

        // Get number of columns and rows.
        let tile_size = self.config.tile_size;
        let num_cols = width as int / tile_size as int;
        let num_rows = height as int / tile_size as int;

        let mut red = 0.01;

        // Fill screen with red one 32x32 tile at a time.
        for row in range(0i, num_rows ) {

            red = red + 0.02;

            let row_shift: f64 = row as f64 * tile_size as f64;

            for col in range(0i, num_cols ) {

                let col_shift: f64 = col as f64 * tile_size as f64;

                c.square(
                    col_shift,
                    row_shift,
                    tile_size as f64
                ).rgb( red, 0.0, 0.0).draw(gl);

            }

        }
    }

}

// Entry point for our game.
fn main() {

    let config = GameConfig {
            title: "Centipede-RS".to_string(),
            window_height: 480,
            window_width: 800,
            updates_per_second: 120,
            max_frames_per_second: 60,
            tile_size: 32,
        };

    // Create and run new game.
    let mut game = Game::new( config );
    game.run();

}

<|endoftext|>


<commit_before>
#![feature(phase)]

extern crate crypto;
extern crate libc;
#[phase(plugin, link)] extern crate log;

use crypto::sha2::Sha512;
use crypto::digest::Digest;
use libc::{getgid, getuid};
use std::os;
use std::io::{OTHER_EXECUTE, OTHER_READ, OTHER_RWX,
              GROUP_EXECUTE, GROUP_READ, GROUP_RWX,
              USER_RWX, ALL_PERMISSIONS};
use std::io::fs::{File, PathExtensions, mkdir, mkdir_recursive, chmod};
use std::io::process::{Command, InheritFd, ExitStatus};

const CACHE_SUBPATH: &'static str = "pexe-runner-cache";
// TODO: support overriding cache location.
const CACHE_BASE: &'static str = "/tmp";

const RUST_PNACL_TRANS: &'static str = "rust-pnacl-trans";

pub fn main() {
    let args = os::args();
    if args.len() != 2 { return; }
    let pexe_path = Path::new(args[1].as_slice());
    let pexe_filename = Path::new(pexe_path.filename().unwrap());

    let cache = Path::new(CACHE_BASE).join(CACHE_SUBPATH);
    if !cache.exists() {
        mkdir_recursive(&cache, ALL_PERMISSIONS).unwrap();
    }

    // if the binary is rx by the world, don't use a user prefix when caching.

    let mut pexe = File::open(&pexe_path).unwrap();

    let pexe_stat = pexe.stat().unwrap();
    let (cache_dir, perms) = if pexe_stat.perm.contains(OTHER_EXECUTE | OTHER_READ) {
        let c = cache.join("other");
        if !c.exists() {
            mkdir(&c, ALL_PERMISSIONS).unwrap();
        }
        (c, OTHER_RWX)
    } else if pexe_stat.perm.contains(GROUP_EXECUTE | GROUP_READ) {
        let c = cache.join("group");
        if !c.exists() {
            mkdir(&c, ALL_PERMISSIONS).unwrap();
        }
        let gid = unsafe { getgid() };
        let c = c.join(format!("{}", gid));
        if !c.exists() {
            mkdir(&c, GROUP_RWX).unwrap();
        }
        (c, GROUP_RWX)
    } else {
        let c = cache.join("user");
        if !c.exists() {
            mkdir(&c, ALL_PERMISSIONS).unwrap();
        }
        let uid = unsafe { getuid() };
        let c = c.join(format!("{}", uid));
        if !c.exists() {
            mkdir(&c, USER_RWX).unwrap();
        }
        (c, USER_RWX)
    };

    let pexe_bin = pexe.read_to_end().unwrap();

    let mut hasher = Sha512::new();
    hasher.input(pexe_bin.as_slice());
    let cache_dir = cache_dir.join(hasher.result_str());
    if !cache_dir.exists() {
        mkdir(&cache_dir, perms).unwrap();
    }
    let nexe_path = cache_dir
        .join(pexe_filename.with_extension("nexe"));

    let nacl_sdk_root = env!("NACL_SDK_ROOT");

    if !nexe_path.exists() {
        let mut cmd = Command::new(RUST_PNACL_TRANS);
        cmd.arg("--cross-path");
        cmd.arg(nacl_sdk_root);
        cmd.arg(pexe_path.display().to_string());
        cmd.arg("-o");
        cmd.arg(nexe_path.display().to_string());
        cmd.arg("--opt-level=2");
        debug!("trans cmd line: `{}`", cmd);
        let mut trans = cmd.spawn().unwrap();

        let status = trans.wait().unwrap();
        match status {
            ExitStatus(0) => {
                chmod(&nexe_path, perms).unwrap();
            }
            _ => {
                panic!("trans failed!");
            }
        }
    }

    let nacl_sdk_root = Path::new(nacl_sdk_root);
    let tools = nacl_sdk_root.join("tools");
    let nacl_helper_bootstrap = tools.join("nacl_helper_bootstrap_x86_64");
    let sel_ldr_bin = tools.join("sel_ldr_x86_64");
    let irt_core = tools.join("irt_core_x86_64.nexe");

    let mut sel_ldr_args = vec!(sel_ldr_bin.display().to_string(),
                                "--r_debug=0xXXXXXXXXXXXXXXXX".to_string(),
                                "--reserved_at_zero=0xXXXXXXXXXXXXXXXX".to_string(),
                                //"-a".to_string(),
                                "-B".to_string(),
                                irt_core.display().to_string(),
                                "-l".to_string(), "/dev/null".to_string());
    sel_ldr_args.push("--".to_string());
    sel_ldr_args.push(nexe_path.display().to_string());
    sel_ldr_args.extend(args.slice_from(2).to_vec().into_iter());

    let mut cmd = Command::new(nacl_helper_bootstrap);
    cmd.args(sel_ldr_args.as_slice());
    cmd.stdout(InheritFd(libc::STDOUT_FILENO));
    cmd.stderr(InheritFd(libc::STDERR_FILENO));
    debug!("sel_ldr cmd line: `{}`", cmd);
    match cmd.spawn() {
        Ok(mut process) => {
            match process.wait() {
                Ok(ExitStatus(status)) => {
                    os::set_exit_status(status);
                }
                Ok(_) => {
                    os::set_exit_status(1);
                }
                Err(e) => {
                    panic!("couldn't wait on sel_ldr: {}", e);
                }
            }
        }
        Err(e) => {
            panic!("couldn't spawn sel_ldr: {}", e);
        }
    }
}
<commit_msg>Fix incorrect permissions for 'others' and 'group'.<commit_after>
#![feature(phase)]

extern crate crypto;
extern crate libc;
#[phase(plugin, link)] extern crate log;

use crypto::sha2::Sha512;
use crypto::digest::Digest;
use libc::{getgid, getuid};
use std::os;
use std::io::{OTHER_EXECUTE, OTHER_READ,
              GROUP_EXECUTE, GROUP_READ, GROUP_RWX,
              USER_EXECUTE,  USER_RWX, ALL_PERMISSIONS};
use std::io::fs::{File, PathExtensions, mkdir, mkdir_recursive, chmod};
use std::io::process::{Command, InheritFd, ExitStatus};

const CACHE_SUBPATH: &'static str = "pexe-runner-cache";
// TODO: support overriding cache location.
const CACHE_BASE: &'static str = "/tmp";

const RUST_PNACL_TRANS: &'static str = "rust-pnacl-trans";

pub fn main() {
    let args = os::args();
    if args.len() != 2 { return; }
    let pexe_path = Path::new(args[1].as_slice());
    let pexe_filename = Path::new(pexe_path.filename().unwrap());

    let cache = Path::new(CACHE_BASE).join(CACHE_SUBPATH);
    if !cache.exists() {
        mkdir_recursive(&cache, ALL_PERMISSIONS).unwrap();
    }

    // if the binary is rx by the world, don't use a user prefix when caching.

    let mut pexe = File::open(&pexe_path).unwrap();

    let pexe_stat = pexe.stat().unwrap();
    let (cache_dir, perms) = if pexe_stat.perm.contains(OTHER_EXECUTE | OTHER_READ) {
        let c = cache.join("other");
        if !c.exists() {
            mkdir(&c, ALL_PERMISSIONS).unwrap();
        }
        (c, ALL_PERMISSIONS)
    } else if pexe_stat.perm.contains(GROUP_EXECUTE | GROUP_READ) {
        let c = cache.join("group");
        if !c.exists() {
            mkdir(&c, ALL_PERMISSIONS).unwrap();
        }
        let gid = unsafe { getgid() };
        let c = c.join(format!("{}", gid));
        if !c.exists() {
            mkdir(&c, GROUP_RWX | USER_RWX).unwrap();
        }
        (c, GROUP_RWX | USER_RWX)
    } else if pexe_stat.perm.contains(USER_EXECUTE) {
        let c = cache.join("user");
        if !c.exists() {
            mkdir(&c, ALL_PERMISSIONS).unwrap();
        }
        let uid = unsafe { getuid() };
        let c = c.join(format!("{}", uid));
        if !c.exists() {
            mkdir(&c, USER_RWX).unwrap();
        }
        (c, USER_RWX)
    } else {
        panic!("cann't execute: permissing denied");
    };

    let pexe_bin = pexe.read_to_end().unwrap();

    let mut hasher = Sha512::new();
    hasher.input(pexe_bin.as_slice());
    let cache_dir = cache_dir.join(hasher.result_str());
    if !cache_dir.exists() {
        mkdir(&cache_dir, perms).unwrap();
    }
    let nexe_path = cache_dir
        .join(pexe_filename.with_extension("nexe"));

    let nacl_sdk_root = env!("NACL_SDK_ROOT");

    if !nexe_path.exists() {
        let mut cmd = Command::new(RUST_PNACL_TRANS);
        cmd.arg("--cross-path");
        cmd.arg(nacl_sdk_root);
        cmd.arg(pexe_path.display().to_string());
        cmd.arg("-o");
        cmd.arg(nexe_path.display().to_string());
        cmd.arg("--opt-level=2");
        debug!("trans cmd line: `{}`", cmd);
        let mut trans = cmd.spawn().unwrap();

        let status = trans.wait().unwrap();
        match status {
            ExitStatus(0) => {
                chmod(&nexe_path, perms).unwrap();
            }
            _ => {
                panic!("trans failed!");
            }
        }
    }

    let nacl_sdk_root = Path::new(nacl_sdk_root);
    let tools = nacl_sdk_root.join("tools");
    let nacl_helper_bootstrap = tools.join("nacl_helper_bootstrap_x86_64");
    let sel_ldr_bin = tools.join("sel_ldr_x86_64");
    let irt_core = tools.join("irt_core_x86_64.nexe");

    let mut sel_ldr_args = vec!(sel_ldr_bin.display().to_string(),
                                "--r_debug=0xXXXXXXXXXXXXXXXX".to_string(),
                                "--reserved_at_zero=0xXXXXXXXXXXXXXXXX".to_string(),
                                //"-a".to_string(),
                                "-B".to_string(),
                                irt_core.display().to_string(),
                                "-l".to_string(), "/dev/null".to_string());
    sel_ldr_args.push("--".to_string());
    sel_ldr_args.push(nexe_path.display().to_string());
    sel_ldr_args.extend(args.slice_from(2).to_vec().into_iter());

    let mut cmd = Command::new(nacl_helper_bootstrap);
    cmd.args(sel_ldr_args.as_slice());
    cmd.stdout(InheritFd(libc::STDOUT_FILENO));
    cmd.stderr(InheritFd(libc::STDERR_FILENO));
    debug!("sel_ldr cmd line: `{}`", cmd);
    match cmd.spawn() {
        Ok(mut process) => {
            match process.wait() {
                Ok(ExitStatus(status)) => {
                    os::set_exit_status(status);
                }
                Ok(_) => {
                    os::set_exit_status(1);
                }
                Err(e) => {
                    panic!("couldn't wait on sel_ldr: {}", e);
                }
            }
        }
        Err(e) => {
            panic!("couldn't spawn sel_ldr: {}", e);
        }
    }
}
<|endoftext|>