<commit_before>#![feature(globs)]
#![feature(macro_rules)]

extern crate xml;

use std::io::{File, BufferedReader};
use std::default::Default;
use std::num::from_str_radix;

use xml::reader::EventReader;
use fromxml::{FromXml, XmlIter};

mod fromxml;

deriving_fromxml! {
    struct Device {
        vendor:Option<String>,
        vendorID:Option<String>,
        licenseText:Option<String>,
        series:Option<String>,
        version:Option<String>,
        description:Option<String>,
        cpu:Option<CPU>,
        peripherals: Vec<Peripheral>,
    }
}

deriving_fromxml! {
    struct Peripheral {
        name: String,
        version:Option<String>,
        description:Option<String>,
        groupName:Option<String>,
        prependToName:Option<String>,
        baseAddress:Option<String>,
        access:Option<String>,
        interrupt:Option<Interrupt>,
        registers: Vec<Regs>,
    }
}

deriving_fromxml! {
    struct Interrupt {
        name: String,
        value:Option<uint>,
    }
}

deriving_fromxml! {
    enum Regs {
        register(Register),
        cluster(Cluster),
    }
}

deriving_fromxml! {
    struct Register {
        name: String,
        dim:Option<uint>,
        dimIncrement:Option<String>,
        description:Option<String>,
        addressOffset:Option<String>,
        size:Option<uint>,
        access:Option<String>,
        fields: Vec<Field>,
    }
}

#[deriving(Default, Show)]
struct Cluster {
    name: String,
    registers: Vec<Register>,
}

impl ::fromxml::FromXml for Cluster {
    fn from_xml(iter: &mut ::fromxml::XmlIter) -> Result<Cluster, ()> {
        let mut obj = Cluster{..Default::default()};
        try!(iter.each_child(|iter| {
            match iter.tag_name() {
                    "name" => obj.name = try!(::fromxml::FromXml::from_xml(iter)),
                    "register" => obj.registers.push(try!(::fromxml::FromXml::from_xml(iter))),
                    _ => try!(iter.skip_node())
            }
            Ok(())
        }));
        Ok(obj)
    }
}

deriving_fromxml! {
    struct Field {
        name: String,
        description:Option<String>,
        bitOffset:Option<uint>,
        bitWidth:Option<uint>,
        access:Option<String>,
        enumeratedValues: Vec<EnumeratedValue>,
    }
}

deriving_fromxml! {
    struct EnumeratedValue {
        name: String,
        value: String,
        description:Option<String>,
    }
}

deriving_fromxml! {
    struct CPU {
        name:Option<String>,
        revision:Option<String>,
    }
}

fn parse_num(s: &str) -> Option<u32> {
    if s.slice_to(2) == "0x" {
        from_str_radix(s.slice_from(2), 16)
    } else {
        from_str_radix(s, 10)
    }
}

fn write_doc_comment(doc: Option<&String>) {
    if let Some(d) = doc {
        print!(" //= {}", d);
    }
}

fn write_device(device: &Device) {
    for peripheral in device.peripherals.iter() {
        write_peripheral(peripheral);
    }
}

fn write_peripheral(peripheral: &Peripheral) {
    let mut registers = vec![];

    println!("ioregs!({} = {{", peripheral.name);
    for register in peripheral.registers.iter() {
        match *register {
            Regs::register(ref r) => registers.push(r),
            Regs::cluster(ref c) => {
                let mut cluster_regs: Vec<_> = c.registers.iter().collect();

                println!("    // cluster: {}", c.name);
                write_registers(&mut *cluster_regs);
            }
        }
    }
    write_registers(&mut *registers);
    println!("}}")
}

fn write_registers(registers: &mut[&Register]) {
    registers.as_mut_slice().sort_by(|a, b| {
        let a = a.addressOffset.as_ref().map(|x| parse_num(x.as_slice()));
        let b = b.addressOffset.as_ref().map(|x| parse_num(x.as_slice()));
        a.cmp(&b)
    });

    for &r in registers.iter() {
        write_register(r);
    }
}

fn write_register(register: &Register) {
    if let (Some(dim), Some(dim_increment)) = (register.dim, register.dimIncrement.as_ref()) {
        println!("    // repeat: {} increment {}", dim, dim_increment);
    }
    let offset = register.addressOffset.as_ref().map_or("", |x| x.as_slice());
    let size = register.size.unwrap_or(0);
    print!("    {} => reg{} {} {{", offset, size, register.name);
    write_doc_comment(register.description.as_ref());
    print!("\n");

    for field in register.fields.iter() {
        write_field(field);
    }
    println!("    }}");
}

fn write_field(field: &Field) {
    let lsb = field.bitOffset.unwrap();
    let width = field.bitWidth.unwrap();

    print!("         {}", lsb);

    if width > 1 {
        print!("..{}", lsb + width - 1);
    }

    print!(" => {}", field.name);

    if field.enumeratedValues.len() == 0 {
        print!(",");
    } else {
        print!(" {{");
    }

    write_doc_comment(field.description.as_ref());
    print!("\n");

    if field.enumeratedValues.len() != 0 {
        for en in field.enumeratedValues.iter() {
            if en.name.len() == 0 { continue } // TODO: this is a <name>, not an <enumeratedValues>
            print!("             {} => {}", en.name, en.value);
            write_doc_comment(en.description.as_ref());
            print!("\n");
        }
        println!("         }}");
    }
}

fn main() {
    let file = File::open(&Path::new("file.xml")).unwrap();
    let reader = BufferedReader::new(file);

    let mut parser = EventReader::new(reader);
    let mut iter = XmlIter::new(parser.events()).unwrap();
    let device: Device = FromXml::from_xml(&mut iter).unwrap();

    write_device(&device);
}
<commit_msg>Fix ioregs format<commit_after>#![feature(globs)]
#![feature(macro_rules)]

extern crate xml;

use std::io::{File, BufferedReader};
use std::default::Default;
use std::num::from_str_radix;

use xml::reader::EventReader;
use fromxml::{FromXml, XmlIter};

mod fromxml;

deriving_fromxml! {
    struct Device {
        vendor:Option<String>,
        vendorID:Option<String>,
        licenseText:Option<String>,
        series:Option<String>,
        version:Option<String>,
        description:Option<String>,
        cpu:Option<CPU>,
        peripherals: Vec<Peripheral>,
    }
}

deriving_fromxml! {
    struct Peripheral {
        name: String,
        version:Option<String>,
        description:Option<String>,
        groupName:Option<String>,
        prependToName:Option<String>,
        baseAddress:Option<String>,
        access:Option<String>,
        interrupt:Option<Interrupt>,
        registers: Vec<Regs>,
    }
}

deriving_fromxml! {
    struct Interrupt {
        name: String,
        value:Option<uint>,
    }
}

deriving_fromxml! {
    enum Regs {
        register(Register),
        cluster(Cluster),
    }
}

deriving_fromxml! {
    struct Register {
        name: String,
        dim:Option<uint>,
        dimIncrement:Option<String>,
        description:Option<String>,
        addressOffset:Option<String>,
        size:Option<uint>,
        access:Option<String>,
        fields: Vec<Field>,
    }
}

#[deriving(Default, Show)]
struct Cluster {
    name: String,
    registers: Vec<Register>,
}

impl ::fromxml::FromXml for Cluster {
    fn from_xml(iter: &mut ::fromxml::XmlIter) -> Result<Cluster, ()> {
        let mut obj = Cluster{..Default::default()};
        try!(iter.each_child(|iter| {
            match iter.tag_name() {
                    "name" => obj.name = try!(::fromxml::FromXml::from_xml(iter)),
                    "register" => obj.registers.push(try!(::fromxml::FromXml::from_xml(iter))),
                    _ => try!(iter.skip_node())
            }
            Ok(())
        }));
        Ok(obj)
    }
}

deriving_fromxml! {
    struct Field {
        name: String,
        description:Option<String>,
        bitOffset:Option<uint>,
        bitWidth:Option<uint>,
        access:Option<String>,
        enumeratedValues: Vec<EnumeratedValue>,
    }
}

deriving_fromxml! {
    struct EnumeratedValue {
        name: String,
        value: String,
        description:Option<String>,
    }
}

deriving_fromxml! {
    struct CPU {
        name:Option<String>,
        revision:Option<String>,
    }
}

fn parse_num(s: &str) -> Option<u32> {
    if s.slice_to(2) == "0x" {
        from_str_radix(s.slice_from(2), 16)
    } else {
        from_str_radix(s, 10)
    }
}

fn write_doc_comment(doc: Option<&String>) {
    if let Some(d) = doc {
        print!(" //= {}", d);
    }
}

fn write_device(device: &Device) {
    for peripheral in device.peripherals.iter() {
        write_peripheral(peripheral);
    }
}

fn write_peripheral(peripheral: &Peripheral) {
    let mut registers = vec![];

    println!("ioregs!({} = {{", peripheral.name);
    for register in peripheral.registers.iter() {
        match *register {
            Regs::register(ref r) => registers.push(r),
            Regs::cluster(ref c) => {
                let mut cluster_regs: Vec<_> = c.registers.iter().collect();

                println!("    // cluster: {}", c.name);
                write_registers(&mut *cluster_regs);
            }
        }
    }
    write_registers(&mut *registers);
    println!("}})")
}

fn write_registers(registers: &mut[&Register]) {
    registers.as_mut_slice().sort_by(|a, b| {
        let a = a.addressOffset.as_ref().map(|x| parse_num(x.as_slice()));
        let b = b.addressOffset.as_ref().map(|x| parse_num(x.as_slice()));
        a.cmp(&b)
    });

    for &r in registers.iter() {
        write_register(r);
    }
}

fn write_register(register: &Register) {
    if let (Some(dim), Some(dim_increment)) = (register.dim, register.dimIncrement.as_ref()) {
        println!("    // repeat: {} increment {}", dim, dim_increment);
    }
    let offset = register.addressOffset.as_ref().map_or("", |x| x.as_slice());
    let size = register.size.unwrap_or(0);
    print!("    {} => reg{} {} {{", offset, size, register.name);
    write_doc_comment(register.description.as_ref());
    print!("\n");

    for field in register.fields.iter() {
        write_field(field);
    }
    println!("    }}");
}

fn write_field(field: &Field) {
    let lsb = field.bitOffset.unwrap();
    let width = field.bitWidth.unwrap();

    print!("         {}", lsb);

    if width > 1 {
        print!("..{}", lsb + width - 1);
    }

    print!(" => {}", field.name);

    if field.enumeratedValues.len() == 0 {
        print!(",");
    } else {
        print!(" {{");
    }

    write_doc_comment(field.description.as_ref());
    print!("\n");

    if field.enumeratedValues.len() != 0 {
        for en in field.enumeratedValues.iter() {
            if en.name.len() == 0 { continue } // TODO: this is a <name>, not an <enumeratedValues>
            print!("             {} => {},", en.value, en.name);
            write_doc_comment(en.description.as_ref());
            print!("\n");
        }
        println!("         }}");
    }
}

fn main() {
    let file = File::open(&Path::new("file.xml")).unwrap();
    let reader = BufferedReader::new(file);

    let mut parser = EventReader::new(reader);
    let mut iter = XmlIter::new(parser.events()).unwrap();
    let device: Device = FromXml::from_xml(&mut iter).unwrap();

    write_device(&device);
}
<|endoftext|>


<commit_before>#![recursion_limit = "256"]
#![feature(proc_macro_hygiene, decl_macro)]
#![allow(proc_macro_derive_resolution_fallback)]

#[macro_use]
extern crate diesel;
#[macro_use]
extern crate diesel_migrations;
#[cfg(feature = "profile-index")]
#[macro_use]
extern crate flamer;

#[cfg(unix)]
use log::error;
#[cfg(unix)]
use sd_notify::{self, NotifyState};
#[cfg(unix)]
use std::fs::File;
#[cfg(unix)]
use std::io::prelude::*;
#[cfg(unix)]
use unix_daemonize::{daemonize_redirect, ChdirMode};

use crate::errors::*;
use core::ops::Deref;
use error_chain::bail;
use getopts::Options;
use log::info;
use simplelog::{LevelFilter, SimpleLogger, TermLogger, TerminalMode};
use std::path::Path;
use std::sync::Arc;

mod api;
#[cfg(test)]
mod api_tests;
mod config;
mod db;
mod ddns;
mod errors;
mod index;
mod lastfm;
mod metadata;
mod playlist;
mod serve;
mod server;
mod swagger;
#[cfg(test)]
mod test;
mod thumbnails;
mod ui;
mod user;
mod utils;
mod vfs;
mod web;

fn log_config() -> simplelog::Config {
	simplelog::ConfigBuilder::new()
		.set_location_level(LevelFilter::Error)
		.build()
}

fn main() {
	if let Err(ref e) = run() {
		println!("Error: {}", e);

		for e in e.iter().skip(1) {
			println!("caused by: {}", e);
		}
		if let Some(backtrace) = e.backtrace() {
			println!("backtrace: {:?}", backtrace);
		}
		::std::process::exit(1);
	}
}

#[cfg(unix)]
fn daemonize(options: &getopts::Matches) -> Result<()> {
	if options.opt_present("f") {
		return Ok(());
	}
	let mut log_file = utils::get_data_root()?;
	log_file.push("polaris.log");
	let pid = match daemonize_redirect(Some(&log_file), Some(&log_file), ChdirMode::NoChdir) {
		Ok(p) => p,
		Err(_) => bail!(ErrorKind::DaemonError),
	};
	let mut pid_path = utils::get_data_root()?;
	pid_path.push("polaris.pid");
	let mut file = File::create(pid_path)?;
	file.write_all(pid.to_string().as_bytes())?;
	Ok(())
}

#[cfg(unix)]
fn init_log(log_level: LevelFilter, options: &getopts::Matches) -> Result<()> {
	if options.opt_present("f") {
		if let Err(e) = TermLogger::init(log_level, log_config(), TerminalMode::Stdout) {
			println!("Error starting terminal logger: {}", e);
		} else {
			return Ok(());
		}
	}

	if let Err(e) = SimpleLogger::init(log_level, log_config()) {
		bail!("Error starting simple logger: {}", e);
	}
	Ok(())
}

#[cfg(windows)]
fn init_log(log_level: LevelFilter, _: &getopts::Matches) -> Result<()> {
	if TermLogger::init(log_level, log_config(), TerminalMode::Stdout).is_err() {
		if let Err(e) = SimpleLogger::init(log_level, log_config()) {
			bail!("Error starting simple logger: {}", e);
		}
	};
	Ok(())
}

#[cfg(unix)]
fn notify_ready() {
	if let Ok(true) = sd_notify::booted() {
		if let Err(e) = sd_notify::notify(true, &[NotifyState::Ready]) {
			error!("Unable to send ready notification: {}", e);
		}
	}
}

#[cfg(not(unix))]
fn notify_ready() {}

fn run() -> Result<()> {
	// Parse CLI options
	let args: Vec<String> = std::env::args().collect();
	let mut options = Options::new();
	options.optopt("c", "config", "set the configuration file", "FILE");
	options.optopt("p", "port", "set polaris to run on a custom port", "PORT");
	options.optopt("d", "database", "set the path to index database", "FILE");
	options.optopt("w", "web", "set the path to web client files", "DIRECTORY");
	options.optopt("s", "swagger", "set the path to swagger files", "DIRECTORY");
	options.optopt(
		"l",
		"log",
		"set the log level to a value between 0 (off) and 3 (debug)",
		"LEVEL",
	);

	#[cfg(unix)]
	options.optflag(
		"f",
		"foreground",
		"run polaris in the foreground instead of daemonizing",
	);

	options.optflag("h", "help", "print this help menu");

	let matches = options.parse(&args[1..])?;

	if matches.opt_present("h") {
		let program = args[0].clone();
		let brief = format!("Usage: {} [options]", program);
		print!("{}", options.usage(&brief));
		return Ok(());
	}

	let log_level = match matches.opt_str("l").as_ref().map(String::as_ref) {
		Some("0") => LevelFilter::Off,
		Some("1") => LevelFilter::Error,
		Some("2") => LevelFilter::Info,
		Some("3") => LevelFilter::Debug,
		_ => LevelFilter::Info,
	};

	init_log(log_level, &matches)?;

	#[cfg(unix)]
	daemonize(&matches)?;

	// Init DB
	info!("Starting up database");
	let db_path = matches.opt_str("d");
	let mut default_db_path = utils::get_data_root()?;
	default_db_path.push("db.sqlite");
	let db_path = db_path
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_db_path);
	let db = Arc::new(db::DB::new(&db_path)?);

	// Parse config
	info!("Parsing configuration");
	let config_file_name = matches.opt_str("c");
	let config_file_path = config_file_name.map(|p| Path::new(p.as_str()).to_path_buf());
	if let Some(path) = config_file_path {
		let config = config::parse_toml_file(&path)?;
		info!("Applying configuration");
		config::amend(db.deref(), &config)?;
	}
	let config = config::read(db.deref())?;
	let auth_secret = config::get_auth_secret(db.deref())?;

	// Init index
	info!("Initializing index");
	let command_sender = index::init(db.clone());

	// Trigger auto-indexing
	let db_auto_index = db.clone();
	let command_sender_auto_index = command_sender.clone();
	std::thread::spawn(move || {
		index::self_trigger(db_auto_index.deref(), &command_sender_auto_index);
	});

	// API mount target
	let prefix_url = config.prefix_url.unwrap_or_else(|| "".to_string());
	let api_url = format!("/{}api", &prefix_url);
	info!("Mounting API on {}", api_url);

	// Web client mount target
	let web_dir_name = matches.opt_str("w");
	let mut default_web_dir = utils::get_data_root()?;
	default_web_dir.push("web");
	let web_dir_path = web_dir_name
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_web_dir);
	info!("Static files location is {}", web_dir_path.display());
	let web_url = format!("/{}", &prefix_url);
	info!("Mounting web client files on {}", web_url);

	// Swagger files mount target
	let swagger_dir_name = matches.opt_str("s");
	let mut default_swagger_dir = utils::get_data_root()?;
	default_swagger_dir.push("swagger");
	let swagger_dir_path = swagger_dir_name
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_swagger_dir);
	info!("Swagger files location is {}", swagger_dir_path.display());
	let swagger_url = format!("/{}swagger", &prefix_url);
	info!("Mounting swagger files on {}", swagger_url);

	// Start server
	info!("Starting up server");
	let port: u16 = matches
		.opt_str("p")
		.unwrap_or_else(|| "5050".to_owned())
		.parse()
		.or(Err("invalid port number"))?;

	let server = server::get_server(
		port,
		Some(auth_secret.as_slice()),
		&api_url,
		&web_url,
		&web_dir_path,
		&swagger_url,
		&swagger_dir_path,
		db.clone(),
		command_sender,
	)?;
	std::thread::spawn(move || {
		server.launch();
	});

	// Start DDNS updates
	let db_ddns = db.clone();
	std::thread::spawn(move || {
		ddns::run(db_ddns.deref());
	});

	// Send readiness notification
	notify_ready();

	// Run UI
	ui::run();

	info!("Shutting down server");
	Ok(())
}
<commit_msg>Removed old diesel workaround<commit_after>#![recursion_limit = "256"]
#![feature(proc_macro_hygiene, decl_macro)]

#[macro_use]
extern crate diesel;
#[macro_use]
extern crate diesel_migrations;
#[cfg(feature = "profile-index")]
#[macro_use]
extern crate flamer;

#[cfg(unix)]
use log::error;
#[cfg(unix)]
use sd_notify::{self, NotifyState};
#[cfg(unix)]
use std::fs::File;
#[cfg(unix)]
use std::io::prelude::*;
#[cfg(unix)]
use unix_daemonize::{daemonize_redirect, ChdirMode};

use crate::errors::*;
use core::ops::Deref;
use error_chain::bail;
use getopts::Options;
use log::info;
use simplelog::{LevelFilter, SimpleLogger, TermLogger, TerminalMode};
use std::path::Path;
use std::sync::Arc;

mod api;
#[cfg(test)]
mod api_tests;
mod config;
mod db;
mod ddns;
mod errors;
mod index;
mod lastfm;
mod metadata;
mod playlist;
mod serve;
mod server;
mod swagger;
#[cfg(test)]
mod test;
mod thumbnails;
mod ui;
mod user;
mod utils;
mod vfs;
mod web;

fn log_config() -> simplelog::Config {
	simplelog::ConfigBuilder::new()
		.set_location_level(LevelFilter::Error)
		.build()
}

fn main() {
	if let Err(ref e) = run() {
		println!("Error: {}", e);

		for e in e.iter().skip(1) {
			println!("caused by: {}", e);
		}
		if let Some(backtrace) = e.backtrace() {
			println!("backtrace: {:?}", backtrace);
		}
		::std::process::exit(1);
	}
}

#[cfg(unix)]
fn daemonize(options: &getopts::Matches) -> Result<()> {
	if options.opt_present("f") {
		return Ok(());
	}
	let mut log_file = utils::get_data_root()?;
	log_file.push("polaris.log");
	let pid = match daemonize_redirect(Some(&log_file), Some(&log_file), ChdirMode::NoChdir) {
		Ok(p) => p,
		Err(_) => bail!(ErrorKind::DaemonError),
	};
	let mut pid_path = utils::get_data_root()?;
	pid_path.push("polaris.pid");
	let mut file = File::create(pid_path)?;
	file.write_all(pid.to_string().as_bytes())?;
	Ok(())
}

#[cfg(unix)]
fn init_log(log_level: LevelFilter, options: &getopts::Matches) -> Result<()> {
	if options.opt_present("f") {
		if let Err(e) = TermLogger::init(log_level, log_config(), TerminalMode::Stdout) {
			println!("Error starting terminal logger: {}", e);
		} else {
			return Ok(());
		}
	}

	if let Err(e) = SimpleLogger::init(log_level, log_config()) {
		bail!("Error starting simple logger: {}", e);
	}
	Ok(())
}

#[cfg(windows)]
fn init_log(log_level: LevelFilter, _: &getopts::Matches) -> Result<()> {
	if TermLogger::init(log_level, log_config(), TerminalMode::Stdout).is_err() {
		if let Err(e) = SimpleLogger::init(log_level, log_config()) {
			bail!("Error starting simple logger: {}", e);
		}
	};
	Ok(())
}

#[cfg(unix)]
fn notify_ready() {
	if let Ok(true) = sd_notify::booted() {
		if let Err(e) = sd_notify::notify(true, &[NotifyState::Ready]) {
			error!("Unable to send ready notification: {}", e);
		}
	}
}

#[cfg(not(unix))]
fn notify_ready() {}

fn run() -> Result<()> {
	// Parse CLI options
	let args: Vec<String> = std::env::args().collect();
	let mut options = Options::new();
	options.optopt("c", "config", "set the configuration file", "FILE");
	options.optopt("p", "port", "set polaris to run on a custom port", "PORT");
	options.optopt("d", "database", "set the path to index database", "FILE");
	options.optopt("w", "web", "set the path to web client files", "DIRECTORY");
	options.optopt("s", "swagger", "set the path to swagger files", "DIRECTORY");
	options.optopt(
		"l",
		"log",
		"set the log level to a value between 0 (off) and 3 (debug)",
		"LEVEL",
	);

	#[cfg(unix)]
	options.optflag(
		"f",
		"foreground",
		"run polaris in the foreground instead of daemonizing",
	);

	options.optflag("h", "help", "print this help menu");

	let matches = options.parse(&args[1..])?;

	if matches.opt_present("h") {
		let program = args[0].clone();
		let brief = format!("Usage: {} [options]", program);
		print!("{}", options.usage(&brief));
		return Ok(());
	}

	let log_level = match matches.opt_str("l").as_ref().map(String::as_ref) {
		Some("0") => LevelFilter::Off,
		Some("1") => LevelFilter::Error,
		Some("2") => LevelFilter::Info,
		Some("3") => LevelFilter::Debug,
		_ => LevelFilter::Info,
	};

	init_log(log_level, &matches)?;

	#[cfg(unix)]
	daemonize(&matches)?;

	// Init DB
	info!("Starting up database");
	let db_path = matches.opt_str("d");
	let mut default_db_path = utils::get_data_root()?;
	default_db_path.push("db.sqlite");
	let db_path = db_path
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_db_path);
	let db = Arc::new(db::DB::new(&db_path)?);

	// Parse config
	info!("Parsing configuration");
	let config_file_name = matches.opt_str("c");
	let config_file_path = config_file_name.map(|p| Path::new(p.as_str()).to_path_buf());
	if let Some(path) = config_file_path {
		let config = config::parse_toml_file(&path)?;
		info!("Applying configuration");
		config::amend(db.deref(), &config)?;
	}
	let config = config::read(db.deref())?;
	let auth_secret = config::get_auth_secret(db.deref())?;

	// Init index
	info!("Initializing index");
	let command_sender = index::init(db.clone());

	// Trigger auto-indexing
	let db_auto_index = db.clone();
	let command_sender_auto_index = command_sender.clone();
	std::thread::spawn(move || {
		index::self_trigger(db_auto_index.deref(), &command_sender_auto_index);
	});

	// API mount target
	let prefix_url = config.prefix_url.unwrap_or_else(|| "".to_string());
	let api_url = format!("/{}api", &prefix_url);
	info!("Mounting API on {}", api_url);

	// Web client mount target
	let web_dir_name = matches.opt_str("w");
	let mut default_web_dir = utils::get_data_root()?;
	default_web_dir.push("web");
	let web_dir_path = web_dir_name
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_web_dir);
	info!("Static files location is {}", web_dir_path.display());
	let web_url = format!("/{}", &prefix_url);
	info!("Mounting web client files on {}", web_url);

	// Swagger files mount target
	let swagger_dir_name = matches.opt_str("s");
	let mut default_swagger_dir = utils::get_data_root()?;
	default_swagger_dir.push("swagger");
	let swagger_dir_path = swagger_dir_name
		.map(|n| Path::new(n.as_str()).to_path_buf())
		.unwrap_or(default_swagger_dir);
	info!("Swagger files location is {}", swagger_dir_path.display());
	let swagger_url = format!("/{}swagger", &prefix_url);
	info!("Mounting swagger files on {}", swagger_url);

	// Start server
	info!("Starting up server");
	let port: u16 = matches
		.opt_str("p")
		.unwrap_or_else(|| "5050".to_owned())
		.parse()
		.or(Err("invalid port number"))?;

	let server = server::get_server(
		port,
		Some(auth_secret.as_slice()),
		&api_url,
		&web_url,
		&web_dir_path,
		&swagger_url,
		&swagger_dir_path,
		db.clone(),
		command_sender,
	)?;
	std::thread::spawn(move || {
		server.launch();
	});

	// Start DDNS updates
	let db_ddns = db.clone();
	std::thread::spawn(move || {
		ddns::run(db_ddns.deref());
	});

	// Send readiness notification
	notify_ready();

	// Run UI
	ui::run();

	info!("Shutting down server");
	Ok(())
}
<|endoftext|>


<commit_before>extern crate classreader;
extern crate zip;
extern crate flate2;

use classreader::*;
use std::env;
use std::fs::File;
use flate2::Compression;
use flate2::write::ZlibEncoder;

fn main() {
    env::args().nth(1).expect("usage: javamoose <class or jar file>...");
    let mut args = env::args();
    args.next(); // Skip exe name
    for f in args {
        if f.ends_with("class") {
            process_class_file(&f);
        } else if f.ends_with("jar") {
            process_jar_file(&f);
        } else {
            println!("Ignoring unknown file type {}", f);
        }

    }
    println!("Done!");
}

fn process_class_file(file_name: &String) {
    println!("Loading class file {}", file_name);
    println!("======================================================");
    let class = ClassReader::new_from_path(&file_name).unwrap();
    process_class(&class);
}

fn process_jar_file(file_name: &String) {
    let file = File::open(file_name).expect("couldn't find a file!");
    let mut zip = zip::ZipArchive::new(file).expect("could not read JAR");
    for i in 0..zip.len() {
        let mut class_file = zip.by_index(i).unwrap();
        if class_file.name().ends_with("class") {
            let class = ClassReader::new_from_reader(&mut class_file).unwrap();
            process_class(&class);
        }
    }
}

fn process_class(class: &Class) {
    assert_eq!(0xCAFEBABE, class.magic);
    println!("class: {}", get_class_name(&class));
    println!("method count: {}", class.methods.len());
    println!("field count:  {}", class.fields.len());
    println!("code size:    {}", get_total_code_size(&class));
    for method in &class.methods {
        println!("\tmethod: {}{}", get_string(&class, method.name_index as usize), get_string(&class, method.descriptor_index as usize));
        println!("\t\tsize:       {}", get_method_size(&method));
        println!("\t\tlines:      {}", get_method_lines(&method));
        println!("\t\tcomplexity: {}", get_method_complexity(&method));
    }

    println!("======================================================");
    output_sql(class);
    println!("======================================================");
}

/// Get constant from a pool, correcting for java's 1-based indexes.
fn get_const(class: &Class, i: usize) -> &ConstantPoolInfo {
    &class.constant_pool[i - 1]
}

/// Get string from constant pool
fn get_string(class: &Class, index: usize) -> String {
    match get_const(class, index) {
        &ConstantPoolInfo::Utf8(ref s) => s.clone(),
        _ => "?".to_string()
    }
}

fn get_class_name(class: &Class) -> String {
    match get_const(class, class.this_class as usize) {
        &ConstantPoolInfo::Class(index) => get_string(class, index as usize),
        _ => "?".to_string()
    }
}

fn get_total_code_size(class: &Class) -> usize {
    class.methods.iter().fold(0usize, |sum, method| sum + get_method_size(method))
}

/// Compute method size in byte code instructions
/// If multiple code segments are present in a method (not a javac output) sum it up
fn get_method_size(method: &Method) -> usize {
    method.attributes.iter().fold(0usize, |sum, a| sum + match a {
            &Attribute::Code{ref code, ..} => code.len(),
            _ => 0
        })
}

/// Compute method size in lines of code.
/// If multiple code segments or multiple line number attrbitues are present in a method (not a javac output) sum it up
fn get_method_lines(method: &Method) -> u16 {
    method.attributes.iter().fold(0, |sum, a| sum + match a {
            &Attribute::Code{ref attributes, ..} => attributes.iter().fold(0, |sum, a| sum + match a {
                &Attribute::LineNumberTable(ref line_table) => {
                    let end = get_opt_line_number(line_table.last());
                    let start = get_opt_line_number(line_table.first());
                    if start > end { // TODO: Investigate when it happens
                        0
                    } else {
                        end - start
                    }
                },
                _ => 0
            }),
            _ => 0
        })

}

fn get_opt_line_number(line: Option<&LineNumber>) -> u16 {
    line.map(|x| x.line_number).unwrap_or(0)
}

fn get_method_complexity(method: &Method) -> u16 {
    method.attributes.iter().fold(0, |sum, a| sum + match a {
            &Attribute::Code{ref code, ..} => get_code_complexity(code),
            _ => 0
        })
}

/// Using complexity definition from http://www.leepoint.net/principles_and_practices/complexity/complexity-java-method.html
/// Start with 1 for the method. Add one for each of the following flow-related elements that are found in the method.
/// Returns     Each return that isn't the last statement of a method.
/// Selection   if, else, case, default.
/// Loops   for, while, do-while, break, and continue.
/// Operators   &&, ||, ?, and :
/// Exceptions  catch, finally, throw, or throws clause.
/// Bytecode reference: http://www.angelibrary.com/computer/java_21days/ch32.htm
fn get_code_complexity(code: &Vec<(u32, Instruction)>) -> u16 {
    // println!("{:?}", code);
    // We start from zero to account for always-present final return - it will add the "starting" 1 for us.
    code.iter().fold(0, |sum, instruction| sum + match instruction.1 {
        Instruction::areturn => 1,
        Instruction::athrow => 1,
        Instruction::dreturn => 1,
        Instruction::freturn => 1,
        Instruction::if_acmpeq(..) => 1,
        Instruction::if_acmpne(..) => 1,
        Instruction::if_icmpeq(..) => 1,
        Instruction::if_icmpne(..) => 1,
        Instruction::if_icmplt(..) => 1,
        Instruction::if_icmpge(..) => 1,
        Instruction::if_icmpgt(..) => 1,
        Instruction::if_icmple(..) => 1,
        Instruction::ifeq(..) => 1,
        Instruction::ifne(..) => 1,
        Instruction::iflt(..) => 1,
        Instruction::ifge(..) => 1,
        Instruction::ifgt(..) => 1,
        Instruction::ifle(..) => 1,
        Instruction::ifnonnull(..) => 1,
        Instruction::ifnull(..) => 1,
        Instruction::ireturn => 1,
        Instruction::lookupswitch(_, ref jumps) => jumps.len() as u16, // tricky - lets use the size of the jump table
        Instruction::lreturn => 1,
        Instruction::return_ => 1,
        Instruction::tableswitch(_, _, ref jumps) => jumps.len() as u16, // tricky - lets use the size of the jump table
        // Subroutines in the method. Currently - do not count them towards the complexity. They are used to compile "finally", but I do not see them as branching really. Finally block is executed every time
        // Instruction::jsr(..) => 1,
        // Instruction::jsr_w(..) => 1,
        // Instruction::ret => 1,
        // Instruction::ret_w => 1,
        _ => 0
    })
}

// Minetest/Freemine data model

struct NodeBlob {
    param0: [u16; 4096],
    param1: [u8; 4096],
    param2: [u8; 4096]
}

fn to_bytes(blob: NodeBlob) -> [u8; 16384] {
  use std::mem;
  unsafe { mem::transmute_copy::<NodeBlob, [u8; 16384]>(&blob) }
}

fn hex(v: &Vec<u8>) -> String {
    use std::fmt::Write;
    let mut s = String::new();
    for &byte in v {
        write!(&mut s, "{:02X}", byte).unwrap();
    }
    s
}

fn compute_position(x: i32, y: i32, z: i32) -> i32 {
    x + 4096 * (y + 4096 * z)
}

fn output_sql(class: &Class) {
    use std::io::prelude::*;
    let blob = NodeBlob {
        param0: [2; 4096],
        param1: [0; 4096],
        param2: [0; 4096]
    };
    let blob_encoded = to_bytes(blob);
    let mut e = ZlibEncoder::new(Vec::new(), Compression::Default);
    e.write(&blob_encoded);
    let blob_compressed = e.finish().unwrap();
    let blob_hex = hex(&blob_compressed);
    let block = format!("19020202{}785E636460E458C3C0C0C0CCC091965F945B5C909A0CE489A465A6E6A44497A45694585BAB5483E8DA58068ECCBCB47C101BA8825BC91D06941858A0829C7031D7BC14CFBCB2D4BC92FCA24A2E0021791B940000000000024900000A0000000D64656661756C743A73746F6E650001000C64656661756C743A73616E640002000C64656661756C743A64697274000300036169720004001064656661756C743A646972745F6472790005001764656661756C743A646972745F776974685F67726173730006001564656661756C743A77617465725F666C6F77696E670007000F64656661756C743A67726173735F310008001164656661756C743A7369676E5F77616C6C0009000E64656661756C743A67726176656C0A0000", blob_hex);
    println!("INSERT INTO \"blocks\" VALUES({},X'{}');", compute_position(0, 1, 0), block);
}
<commit_msg>Finally some progress in generating blocks!<commit_after>extern crate classreader;
extern crate zip;
extern crate flate2;

use classreader::*;
use std::env;
use std::fs::File;
use flate2::Compression;
use flate2::write::ZlibEncoder;

fn main() {
    env::args().nth(1).expect("usage: javamoose <class or jar file>...");
    let mut args = env::args();
    args.next(); // Skip exe name
    for f in args {
        if f.ends_with("class") {
            process_class_file(&f);
        } else if f.ends_with("jar") {
            process_jar_file(&f);
        } else {
            println!("Ignoring unknown file type {}", f);
        }

    }
    println!("Done!");
}

fn process_class_file(file_name: &String) {
    println!("Loading class file {}", file_name);
    println!("======================================================");
    let class = ClassReader::new_from_path(&file_name).unwrap();
    process_class(&class);
}

fn process_jar_file(file_name: &String) {
    let file = File::open(file_name).expect("couldn't find a file!");
    let mut zip = zip::ZipArchive::new(file).expect("could not read JAR");
    for i in 0..zip.len() {
        let mut class_file = zip.by_index(i).unwrap();
        if class_file.name().ends_with("class") {
            let class = ClassReader::new_from_reader(&mut class_file).unwrap();
            process_class(&class);
        }
    }
}

fn process_class(class: &Class) {
    assert_eq!(0xCAFEBABE, class.magic);
    println!("class: {}", get_class_name(&class));
    println!("method count: {}", class.methods.len());
    println!("field count:  {}", class.fields.len());
    println!("code size:    {}", get_total_code_size(&class));
    for method in &class.methods {
        println!("\tmethod: {}{}", get_string(&class, method.name_index as usize), get_string(&class, method.descriptor_index as usize));
        println!("\t\tsize:       {}", get_method_size(&method));
        println!("\t\tlines:      {}", get_method_lines(&method));
        println!("\t\tcomplexity: {}", get_method_complexity(&method));
    }

    println!("======================================================");
    output_sql(class);
    println!("======================================================");
}

/// Get constant from a pool, correcting for java's 1-based indexes.
fn get_const(class: &Class, i: usize) -> &ConstantPoolInfo {
    &class.constant_pool[i - 1]
}

/// Get string from constant pool
fn get_string(class: &Class, index: usize) -> String {
    match get_const(class, index) {
        &ConstantPoolInfo::Utf8(ref s) => s.clone(),
        _ => "?".to_string()
    }
}

fn get_class_name(class: &Class) -> String {
    match get_const(class, class.this_class as usize) {
        &ConstantPoolInfo::Class(index) => get_string(class, index as usize),
        _ => "?".to_string()
    }
}

fn get_total_code_size(class: &Class) -> usize {
    class.methods.iter().fold(0usize, |sum, method| sum + get_method_size(method))
}

/// Compute method size in byte code instructions
/// If multiple code segments are present in a method (not a javac output) sum it up
fn get_method_size(method: &Method) -> usize {
    method.attributes.iter().fold(0usize, |sum, a| sum + match a {
            &Attribute::Code{ref code, ..} => code.len(),
            _ => 0
        })
}

/// Compute method size in lines of code.
/// If multiple code segments or multiple line number attrbitues are present in a method (not a javac output) sum it up
fn get_method_lines(method: &Method) -> u16 {
    method.attributes.iter().fold(0, |sum, a| sum + match a {
            &Attribute::Code{ref attributes, ..} => attributes.iter().fold(0, |sum, a| sum + match a {
                &Attribute::LineNumberTable(ref line_table) => {
                    let end = get_opt_line_number(line_table.last());
                    let start = get_opt_line_number(line_table.first());
                    if start > end { // TODO: Investigate when it happens
                        0
                    } else {
                        end - start
                    }
                },
                _ => 0
            }),
            _ => 0
        })

}

fn get_opt_line_number(line: Option<&LineNumber>) -> u16 {
    line.map(|x| x.line_number).unwrap_or(0)
}

fn get_method_complexity(method: &Method) -> u16 {
    method.attributes.iter().fold(0, |sum, a| sum + match a {
            &Attribute::Code{ref code, ..} => get_code_complexity(code),
            _ => 0
        })
}

/// Using complexity definition from http://www.leepoint.net/principles_and_practices/complexity/complexity-java-method.html
/// Start with 1 for the method. Add one for each of the following flow-related elements that are found in the method.
/// Returns     Each return that isn't the last statement of a method.
/// Selection   if, else, case, default.
/// Loops   for, while, do-while, break, and continue.
/// Operators   &&, ||, ?, and :
/// Exceptions  catch, finally, throw, or throws clause.
/// Bytecode reference: http://www.angelibrary.com/computer/java_21days/ch32.htm
fn get_code_complexity(code: &Vec<(u32, Instruction)>) -> u16 {
    // println!("{:?}", code);
    // We start from zero to account for always-present final return - it will add the "starting" 1 for us.
    code.iter().fold(0, |sum, instruction| sum + match instruction.1 {
        Instruction::areturn => 1,
        Instruction::athrow => 1,
        Instruction::dreturn => 1,
        Instruction::freturn => 1,
        Instruction::if_acmpeq(..) => 1,
        Instruction::if_acmpne(..) => 1,
        Instruction::if_icmpeq(..) => 1,
        Instruction::if_icmpne(..) => 1,
        Instruction::if_icmplt(..) => 1,
        Instruction::if_icmpge(..) => 1,
        Instruction::if_icmpgt(..) => 1,
        Instruction::if_icmple(..) => 1,
        Instruction::ifeq(..) => 1,
        Instruction::ifne(..) => 1,
        Instruction::iflt(..) => 1,
        Instruction::ifge(..) => 1,
        Instruction::ifgt(..) => 1,
        Instruction::ifle(..) => 1,
        Instruction::ifnonnull(..) => 1,
        Instruction::ifnull(..) => 1,
        Instruction::ireturn => 1,
        Instruction::lookupswitch(_, ref jumps) => jumps.len() as u16, // tricky - lets use the size of the jump table
        Instruction::lreturn => 1,
        Instruction::return_ => 1,
        Instruction::tableswitch(_, _, ref jumps) => jumps.len() as u16, // tricky - lets use the size of the jump table
        // Subroutines in the method. Currently - do not count them towards the complexity. They are used to compile "finally", but I do not see them as branching really. Finally block is executed every time
        // Instruction::jsr(..) => 1,
        // Instruction::jsr_w(..) => 1,
        // Instruction::ret => 1,
        // Instruction::ret_w => 1,
        _ => 0
    })
}

// Minetest/Freemine data model

struct NodeBlob {
    param0: [u16; 4096],
    param1: [u8; 4096],
    param2: [u8; 4096]
}

fn to_bytes(blob: &NodeBlob) -> Vec<u8> {
    let mut vec: Vec<u8> = Vec::new();
    for i in 0..4096 {
        let p = blob.param0[i];
        vec.push((p >> 8) as u8);
        vec.push(p as u8);
    }
    for i in 0..4096 {
        vec.push(blob.param1[i]);
    }
    for i in 0..4096 {
        vec.push(blob.param2[i]);
    }
    vec
}

fn hex(v: &Vec<u8>) -> String {
    use std::fmt::Write;
    let mut s = String::new();
    for &byte in v {
        write!(&mut s, "{:02X}", byte).unwrap();
    }
    s
}

fn compute_position(x: i32, y: i32, z: i32) -> i32 {
    x + 4096 * (y + 4096 * z)
}

fn output_blob(blob: &NodeBlob, pos: i32) {
    use std::io::prelude::*;
    let blob_encoded = to_bytes(blob);
    let mut e = ZlibEncoder::new(Vec::new(), Compression::Default);
    e.write(&blob_encoded);
    let blob_compressed = e.finish().unwrap();
    let blob_hex = hex(&blob_compressed);
    let block = format!("19020202{}785E636460E458C3C0C0C0CCC091965F945B5C909A0CE489A465A6E6A44497A45694585BAB5483E8DA58068ECCBCB47C101BA8825BC91D06941858A0829C7031D7BC14CFBCB2D4BC92FCA24A2E0021791B940000000000024900000A0000000D64656661756C743A73746F6E650001000C64656661756C743A73616E640002000C64656661756C743A64697274000300036169720004001064656661756C743A646972745F6472790005001764656661756C743A646972745F776974685F67726173730006001564656661756C743A77617465725F666C6F77696E670007000F64656661756C743A67726173735F310008001164656661756C743A7369676E5F77616C6C0009000E64656661756C743A67726176656C0A0000", blob_hex);
    println!("INSERT INTO \"blocks\" VALUES({},X'{}');", pos, block);
}

fn output_sql(class: &Class) {
    // create base
    let blob = NodeBlob {
        param0: [0xe; 4096],
        param1: [0; 4096],
        param2: [0; 4096]
    };
    output_blob(&blob, compute_position(0, 1, 0));
    // create our class
    let mut parr = [0x3; 4096];
    // The location of a node in each of those arrays is (z*16*16 + y*16 + x)
    for x in 4..8 {
        for y in 4..8 {
            for z in 4..8 {
                let i = (z * 16 + y) * 16 + x;
                parr[i] = 0x0;
            }
        }
    }
    let blob2 = NodeBlob {
        param0: parr,
        param1: [0; 4096],
        param2: [0; 4096]
    };
    output_blob(&blob2, compute_position(0, 2, 0));

}
<|endoftext|>


<commit_before>#![feature(io)]

use std::old_io;
//static ITERATIONS: u16 = 5000;
static DEFAULT_GRID: u8 = 10;

fn main() {
	let mut stdin = old_io::stdin();
	//Choose the grid size
	println!("Please give us grid size");
	let grid_input = stdin.lock().lines().next().unwrap().ok().unwrap();
	let grid_size: u8 = match grid_input.trim().parse::<u8>() {
			Ok(0) => DEFAULT_GRID,
			Ok(x) => x,
			Err(_) => DEFAULT_GRID
		};
	println!("Your grid must have a size of {}", grid_size);
	//Build the grid
	let mut grid: Vec<Vec<u8>> = generate_grid(grid_size);

	//Print the grid
	print_grid(grid);

}

//For performances considerations, sides can't be > to 255.
fn generate_grid(side_length: u8) -> Vec<Vec<u8>> {
	let mut vector: Vec<Vec<u8>> = Vec::new();
	for i in 0..side_length {
		let mut vector_internal: Vec<u8> = Vec::new();
		for j in 0..side_length {
			vector_internal.push(0);
		}
		vector.push(vector_internal);
	}
	return vector;
}

fn print_grid(grid: Vec<Vec<u8>>) {
	for x in grid.iter() {
		for y in x.iter() {
			print!(" {}", match y {
				&0u8 => "-",
				&1u8 => "B",
				&2u8 => "W",
				_ => "E"
			});
		}
		print!("\n");
	}
}<commit_msg>fix refs<commit_after>#![feature(io)]

use std::old_io;
//static ITERATIONS: u16 = 5000;
static DEFAULT_GRID: u8 = 10;

fn main() {
	let mut stdin = old_io::stdin();
	//Choose the grid size
	println!("Please give us grid size");
	let grid_input = stdin.lock().lines().next().unwrap().ok().unwrap();
	let grid_size: u8 = match grid_input.trim().parse::<u8>() {
			Ok(0) => DEFAULT_GRID,
			Ok(x) => x,
			Err(_) => DEFAULT_GRID
		};
	println!("Your grid must have a size of {}", grid_size);
	//Build the grid
	let mut grid: Vec<Vec<u8>> = generate_grid(grid_size);

	//Print the grid
	print_grid(&grid);
	edit_grid(&mut grid, 1, 0, 0);
	print_grid(&grid);

}

//For performances considerations, sides can't be > to 255.
fn generate_grid(side_length: u8) -> Vec<Vec<u8>> {
	let mut vector: Vec<Vec<u8>> = Vec::with_capacity(side_length as usize);
	for _ in 0..side_length {
		let mut vector_internal: Vec<u8> = Vec::with_capacity(side_length as usize);
		for _ in 0..side_length {
			vector_internal.push(0);
		}
		vector.push(vector_internal);
	}
	return vector;
}

fn edit_grid(grid: &mut Vec<Vec<u8>>, new_value: u8, x: u8, y: u8) {
	grid[x as usize][y as usize] = new_value;
}

fn print_grid(grid: &Vec<Vec<u8>>) {
	for x in grid.iter() {
		for y in x.iter() {
			print!(" {}", match y {
				&0u8 => "-",
				&1u8 => "B",
				&2u8 => "W",
				_ => "E"
			});
		}
		print!("\n");
	}
}<|endoftext|>


<commit_before>extern crate crypto;
extern crate base64;
extern crate byteorder;
extern crate rand;
extern crate docopt;
extern crate rustc_serialize;

use std::process;
use std::mem;
use std::io::prelude::*;
use std::io::{self, BufReader, Cursor};
use std::fs::File;
use std::convert::AsRef;
use std::path::Path;

use rand::Rng;
use rand::os::OsRng;

use crypto::ed25519;
use crypto::digest::Digest;
use crypto::sha2::Sha512;

use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};

use docopt::Docopt;

const KEYNUMLEN : usize = 8;
const PUBLICBYTES : usize = 32;
const SECRETBYTES : usize = 64;
const SIGBYTES : usize = 64;

const PKGALG : [u8; 2] = *b"Ed";
const KDFALG : [u8; 2] = *b"BK";

const COMMENTHDR : &'static str = "untrusted comment: ";
const COMMENTHDRLEN : usize = 19;
const COMMENTMAXLEN : usize = 1024;

const USAGE: &'static str = "
signify-rs

Usage:
  signify -h
  signify -G [-c <comment>] -p <pubkey> -s <seckey>
  signify -S [-x <sigfile>] -s <seckey> -m <message>
  signify -V [-x <sigfile>] -p <pubkey> -m <message>

Options:
  -h --help              Show this screen.
  -c <comment>  Specify the comment to be added during key generation.
  -m <message>  When signing, the file containing the message to sign.  When verifying, the file containing the
                message to verify.  When verifying with -e, the file to create.
  -p <pubkey>   Public key produced by -G, and used by -V to check a signature.
  -s <seckey>   Secret (private) key produced by -G, and used by -S to sign a message.
  -x <sigfile>  The signature file to create or verify.  The default is <message>.sig.
";

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable)]
struct Args {
    flag_G: bool,
    flag_S: bool,
    flag_V: bool,

    flag_x: Option<String>,
    flag_c: Option<String>,

    flag_p: String,
    flag_s: String,
    flag_m: String,
}

enum FileContent {
    PublicKey(PublicKey),
    PrivateKey(PrivateKey),
    Signature(Signature),
}

struct PublicKey {
    pkgalg: [u8; 2],
    keynum: [u8; KEYNUMLEN],
    publkey: [u8; PUBLICBYTES],
}

struct PrivateKey {
   pkgalg: [u8; 2],
   kdfalg: [u8; 2],
   kdfrounds: u32,
   salt: [u8; 16],
   checksum: [u8; 8],
   keynum: [u8; KEYNUMLEN],
   seckey: [u8; SECRETBYTES],
}

struct Signature {
    pkgalg: [u8; 2],
    keynum: [u8; KEYNUMLEN],
    sig: [u8; SIGBYTES],
}

impl PublicKey {
    fn with_key_and_keynum(key: [u8; PUBLICBYTES], keynum: [u8; KEYNUMLEN]) -> PublicKey {
        PublicKey {
            pkgalg: PKGALG,
            keynum: keynum,
            publkey: key,
        }
    }

    fn write<W: Write>(&self, mut w: W) -> Result<(), io::Error> {
        try!(w.write(&self.pkgalg));
        try!(w.write(&self.keynum));
        try!(w.write(&self.publkey));

        Ok(())
    }

    fn from_buf(buf: &[u8]) -> Result<PublicKey, io::Error> {
        assert!(buf.len() >= mem::size_of::<Self>());

        let mut buf = Cursor::new(buf);

        let mut pkgalg = [0; 2];
        let mut keynum = [0; KEYNUMLEN];
        let mut publkey = [0; PUBLICBYTES];

        try!(buf.read(&mut pkgalg));
        try!(buf.read(&mut keynum));
        try!(buf.read(&mut publkey));

        Ok(PublicKey {
            pkgalg: pkgalg,
            keynum: keynum,
            publkey: publkey,
        })
    }

    fn verify(&self, msg: &[u8], signature: &Signature) -> bool {
        ed25519::verify(msg, &self.publkey, &signature.sig)
    }
}

impl PrivateKey {
    fn write<W: Write>(&self, mut w: W) -> Result<(), io::Error> {
        try!(w.write(&self.pkgalg));
        try!(w.write(&self.kdfalg));
        try!(w.write_u32::<BigEndian>(self.kdfrounds));
        try!(w.write(&self.salt));
        try!(w.write(&self.checksum));
        try!(w.write(&self.keynum));
        try!(w.write(&self.seckey));

        Ok(())
    }

    fn from_buf(buf: &[u8]) -> Result<PrivateKey, io::Error> {
        assert!(buf.len() >= mem::size_of::<Self>());

        let mut buf = Cursor::new(buf);

        let mut pkgalg = [0; 2];
        let mut kdfalg = [0; 2];
        let kdfrounds;
        let mut salt = [0; 16];
        let mut checksum = [0; 8];
        let mut keynum = [0; KEYNUMLEN];
        let mut seckey = [0; SECRETBYTES];

        try!(buf.read(&mut pkgalg));
        try!(buf.read(&mut kdfalg));
        kdfrounds = try!(buf.read_u32::<BigEndian>());
        try!(buf.read(&mut salt));
        try!(buf.read(&mut checksum));
        try!(buf.read(&mut keynum));
        try!(buf.read(&mut seckey));

        Ok(PrivateKey {
            pkgalg: pkgalg,
            kdfalg: kdfalg,
            kdfrounds: kdfrounds,
            salt: salt,
            checksum: checksum,
            keynum: keynum,
            seckey: seckey,
        })
    }

    fn sign(&self, msg: &[u8]) -> Signature {
        let signature = ed25519::signature(msg, &self.seckey);
        Signature {
            pkgalg: PKGALG,
            keynum: self.keynum,
            sig: signature
        }
    }
}

impl Signature {
    fn write<W: Write>(&self, mut w: W) -> Result<(), io::Error> {
        try!(w.write(&self.pkgalg));
        try!(w.write(&self.keynum));
        try!(w.write(&self.sig));

        Ok(())
    }

    fn from_buf(buf: &[u8]) -> Result<Signature, io::Error> {
        assert!(buf.len() >= mem::size_of::<Self>());

        let mut buf = Cursor::new(buf);

        let mut pkgalg = [0; 2];
        let mut keynum = [0; KEYNUMLEN];
        let mut sig = [0; SIGBYTES];

        try!(buf.read(&mut pkgalg));
        try!(buf.read(&mut keynum));
        try!(buf.read(&mut sig));

        Ok(Signature {
            pkgalg: pkgalg,
            keynum: keynum,
            sig: sig,
        })
    }

    fn verify(&self, msg: &[u8], pkey: &PublicKey) -> bool {
        ed25519::verify(msg, &pkey.publkey, &self.sig)
    }
}

fn write_base64_file<P: AsRef<Path>>(file: P, comment: &str, buf: &[u8]) -> Result<(), io::Error> {
    let mut f = File::create(file).unwrap();

    try!(write!(f, "{}", COMMENTHDR));
    try!(write!(f, "{}\n", comment));
    let out = base64::encode(buf);
    try!(write!(f, "{}\n", out));

    Ok(())
}

fn read_base64_file<P: AsRef<Path>>(file: P) -> Result<FileContent, io::Error> {
    let file_display = format!("{}", file.as_ref().display());
    let f = try!(File::open(file));
    let mut reader = BufReader::new(f);

    let mut comment_line = String::new();
    let len = try!(reader.read_line(&mut comment_line));

    if len == 0 || len < COMMENTHDRLEN || !comment_line.starts_with(COMMENTHDR) {
        println!("invalid comment in {}; must start with '{}'", file_display, COMMENTHDR);
        process::exit(1);
    }

    if &comment_line[len-1..len] != "\n" {
        println!("missing new line after comment in '{}'", file_display);
        process::exit(1);
    }

    if len > COMMENTHDRLEN + COMMENTMAXLEN {
        println!("comment too long");
        process::exit(1);
    }

    let mut base64_line = String::new();
    let len = try!(reader.read_line(&mut base64_line));

    if len == 0 {
        println!("missing line in {}", file_display);
        process::exit(1);
    }

    if &base64_line[len-1..len] != "\n" {
        println!("missing new line after comment in '{}'", file_display);
        process::exit(1);
    }

    let base64_line = &base64_line[0..len-1];

    let data = match base64::decode(&base64_line) {
        Ok(data) => data,
        Err(e) => {
            println!("invalid base64 encoding in {}: {:?}", file_display, e);
            process::exit(1);
        }
    };

    if &data[0..2] != PKGALG {
        println!("unsupported file {}", file_display);
        process::exit(1);
    }

    match data.len() {
        x if x == mem::size_of::<PublicKey>() => {
            return PublicKey::from_buf(&data)
                .map(FileContent::PublicKey);
        },
        x if x == mem::size_of::<PrivateKey>() => {
            return PrivateKey::from_buf(&data)
                .map(FileContent::PrivateKey);
        },
        x if x == mem::size_of::<Signature>() => {
            return Signature::from_buf(&data)
                .map(FileContent::Signature);
        },
        _ => {
            println!("unsupported file {}", file_display);
            process::exit(1);
        },
    };
}

fn verify(pubkey_path: String, msg_path: String, signature_path: Option<String>) {
    let pkey = match read_base64_file(&pubkey_path) {
        Ok(FileContent::PublicKey(pkey)) => pkey,
        _ => {
            println!("an error occured.");
            process::exit(2);
        }
    };

    let signature_path = match signature_path {
        Some(path) => path,
        None => format!("{}.sig", msg_path)
    };

    let signature = match read_base64_file(&signature_path) {
        Ok(FileContent::Signature(sig)) => sig,
        _ => {
            println!("Can't read signature from '{}'", signature_path);
            process::exit(2);
        }
    };

    let mut msgfile = File::open(&msg_path).expect(&format!("Can't open message file '{}'", msg_path));
    let mut msg = vec![];
    msgfile.read_to_end(&mut msg).expect(&format!("Can't read file '{}'", msg_path));

    if signature.verify(&msg, &pkey) {
        println!("Signature Verified");
    } else {
        println!("signature verification failed");
        process::exit(1);
    }
}

fn sign(seckey_path: String, msg_path: String, signature_path: Option<String>) {
    let skey = match read_base64_file(&seckey_path) {
        Ok(FileContent::PrivateKey(skey)) => skey,
        _ => {
            println!("an error occured.");
            process::exit(2);
        }
    };

    let mut msgfile = File::open(&msg_path).expect(&format!("Can't open message file '{}'", msg_path));
    let mut msg = vec![];
    msgfile.read_to_end(&mut msg).expect(&format!("Can't read file '{}'", msg_path));

    let signature_path = match signature_path {
        Some(path) => path,
        None => format!("{}.sig", msg_path)
    };

    let sig = skey.sign(&msg);

    let mut out = vec![];
    sig.write(&mut out).expect("Can't write to internal buffer");

    let sig_comment = "signature from signify secret key";
    write_base64_file(&signature_path, sig_comment, &out).unwrap();
}

fn generate(pubkey_path: String, privkey_path: String, comment: Option<String>) {
    let comment = match comment {
        Some(s) => s,
        None    => "signify".into()
    };

    let mut keynum = [0; KEYNUMLEN];

    let mut rng = OsRng::new().expect("Can't create random number generator");
    rng.fill_bytes(&mut keynum);

    let mut seed = [0; 32];
    rng.fill_bytes(&mut seed);
    let (skey, pkey) = ed25519::keypair(&seed);

    // Store private key
    let mut ctx = Sha512::new();
    ctx.input(&skey);
    let mut digest = [0; 64];
    ctx.result(&mut digest);
    let mut checksum = [0; 8];
    checksum.copy_from_slice(&digest[0..8]);

    let mut salt = [0; 16];
    rng.fill_bytes(&mut salt);

    let private_key = PrivateKey {
        pkgalg: PKGALG,
        kdfalg: KDFALG,
        kdfrounds: 0,
        salt: salt,
        checksum: checksum,
        keynum: keynum,
        seckey: skey,
    };

    let mut out = vec![];
    private_key.write(&mut out).expect("Can't write to internal buffer");

    let priv_comment = format!("{} secret key", comment);
    write_base64_file(&privkey_path, &priv_comment, &out).unwrap();

    // Store public key
    let public_key = PublicKey::with_key_and_keynum(pkey, keynum);

    let mut out = vec![];
    public_key.write(&mut out).expect("Can't write to internal buffer");

    let pub_comment = format!("{} public key", comment);
    write_base64_file(&pubkey_path, &pub_comment, &out).unwrap();
}

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

    if args.flag_V {
        verify(args.flag_p, args.flag_m, args.flag_x);
    } else if args.flag_G {
        generate(args.flag_p, args.flag_s, args.flag_c);
    } else if args.flag_S {
        sign(args.flag_s, args.flag_m, args.flag_x);
    }
}
<commit_msg>refactor: Remove unused method<commit_after>extern crate crypto;
extern crate base64;
extern crate byteorder;
extern crate rand;
extern crate docopt;
extern crate rustc_serialize;

use std::process;
use std::mem;
use std::io::prelude::*;
use std::io::{self, BufReader, Cursor};
use std::fs::File;
use std::convert::AsRef;
use std::path::Path;

use rand::Rng;
use rand::os::OsRng;

use crypto::ed25519;
use crypto::digest::Digest;
use crypto::sha2::Sha512;

use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};

use docopt::Docopt;

const KEYNUMLEN : usize = 8;
const PUBLICBYTES : usize = 32;
const SECRETBYTES : usize = 64;
const SIGBYTES : usize = 64;

const PKGALG : [u8; 2] = *b"Ed";
const KDFALG : [u8; 2] = *b"BK";

const COMMENTHDR : &'static str = "untrusted comment: ";
const COMMENTHDRLEN : usize = 19;
const COMMENTMAXLEN : usize = 1024;

const USAGE: &'static str = "
signify-rs

Usage:
  signify -h
  signify -G [-c <comment>] -p <pubkey> -s <seckey>
  signify -S [-x <sigfile>] -s <seckey> -m <message>
  signify -V [-x <sigfile>] -p <pubkey> -m <message>

Options:
  -h --help              Show this screen.
  -c <comment>  Specify the comment to be added during key generation.
  -m <message>  When signing, the file containing the message to sign.  When verifying, the file containing the
                message to verify.  When verifying with -e, the file to create.
  -p <pubkey>   Public key produced by -G, and used by -V to check a signature.
  -s <seckey>   Secret (private) key produced by -G, and used by -S to sign a message.
  -x <sigfile>  The signature file to create or verify.  The default is <message>.sig.
";

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable)]
struct Args {
    flag_G: bool,
    flag_S: bool,
    flag_V: bool,

    flag_x: Option<String>,
    flag_c: Option<String>,

    flag_p: String,
    flag_s: String,
    flag_m: String,
}

enum FileContent {
    PublicKey(PublicKey),
    PrivateKey(PrivateKey),
    Signature(Signature),
}

struct PublicKey {
    pkgalg: [u8; 2],
    keynum: [u8; KEYNUMLEN],
    publkey: [u8; PUBLICBYTES],
}

struct PrivateKey {
   pkgalg: [u8; 2],
   kdfalg: [u8; 2],
   kdfrounds: u32,
   salt: [u8; 16],
   checksum: [u8; 8],
   keynum: [u8; KEYNUMLEN],
   seckey: [u8; SECRETBYTES],
}

struct Signature {
    pkgalg: [u8; 2],
    keynum: [u8; KEYNUMLEN],
    sig: [u8; SIGBYTES],
}

impl PublicKey {
    fn with_key_and_keynum(key: [u8; PUBLICBYTES], keynum: [u8; KEYNUMLEN]) -> PublicKey {
        PublicKey {
            pkgalg: PKGALG,
            keynum: keynum,
            publkey: key,
        }
    }

    fn write<W: Write>(&self, mut w: W) -> Result<(), io::Error> {
        try!(w.write(&self.pkgalg));
        try!(w.write(&self.keynum));
        try!(w.write(&self.publkey));

        Ok(())
    }

    fn from_buf(buf: &[u8]) -> Result<PublicKey, io::Error> {
        assert!(buf.len() >= mem::size_of::<Self>());

        let mut buf = Cursor::new(buf);

        let mut pkgalg = [0; 2];
        let mut keynum = [0; KEYNUMLEN];
        let mut publkey = [0; PUBLICBYTES];

        try!(buf.read(&mut pkgalg));
        try!(buf.read(&mut keynum));
        try!(buf.read(&mut publkey));

        Ok(PublicKey {
            pkgalg: pkgalg,
            keynum: keynum,
            publkey: publkey,
        })
    }
}

impl PrivateKey {
    fn write<W: Write>(&self, mut w: W) -> Result<(), io::Error> {
        try!(w.write(&self.pkgalg));
        try!(w.write(&self.kdfalg));
        try!(w.write_u32::<BigEndian>(self.kdfrounds));
        try!(w.write(&self.salt));
        try!(w.write(&self.checksum));
        try!(w.write(&self.keynum));
        try!(w.write(&self.seckey));

        Ok(())
    }

    fn from_buf(buf: &[u8]) -> Result<PrivateKey, io::Error> {
        assert!(buf.len() >= mem::size_of::<Self>());

        let mut buf = Cursor::new(buf);

        let mut pkgalg = [0; 2];
        let mut kdfalg = [0; 2];
        let kdfrounds;
        let mut salt = [0; 16];
        let mut checksum = [0; 8];
        let mut keynum = [0; KEYNUMLEN];
        let mut seckey = [0; SECRETBYTES];

        try!(buf.read(&mut pkgalg));
        try!(buf.read(&mut kdfalg));
        kdfrounds = try!(buf.read_u32::<BigEndian>());
        try!(buf.read(&mut salt));
        try!(buf.read(&mut checksum));
        try!(buf.read(&mut keynum));
        try!(buf.read(&mut seckey));

        Ok(PrivateKey {
            pkgalg: pkgalg,
            kdfalg: kdfalg,
            kdfrounds: kdfrounds,
            salt: salt,
            checksum: checksum,
            keynum: keynum,
            seckey: seckey,
        })
    }

    fn sign(&self, msg: &[u8]) -> Signature {
        let signature = ed25519::signature(msg, &self.seckey);
        Signature {
            pkgalg: PKGALG,
            keynum: self.keynum,
            sig: signature
        }
    }
}

impl Signature {
    fn write<W: Write>(&self, mut w: W) -> Result<(), io::Error> {
        try!(w.write(&self.pkgalg));
        try!(w.write(&self.keynum));
        try!(w.write(&self.sig));

        Ok(())
    }

    fn from_buf(buf: &[u8]) -> Result<Signature, io::Error> {
        assert!(buf.len() >= mem::size_of::<Self>());

        let mut buf = Cursor::new(buf);

        let mut pkgalg = [0; 2];
        let mut keynum = [0; KEYNUMLEN];
        let mut sig = [0; SIGBYTES];

        try!(buf.read(&mut pkgalg));
        try!(buf.read(&mut keynum));
        try!(buf.read(&mut sig));

        Ok(Signature {
            pkgalg: pkgalg,
            keynum: keynum,
            sig: sig,
        })
    }

    fn verify(&self, msg: &[u8], pkey: &PublicKey) -> bool {
        ed25519::verify(msg, &pkey.publkey, &self.sig)
    }
}

fn write_base64_file<P: AsRef<Path>>(file: P, comment: &str, buf: &[u8]) -> Result<(), io::Error> {
    let mut f = File::create(file).unwrap();

    try!(write!(f, "{}", COMMENTHDR));
    try!(write!(f, "{}\n", comment));
    let out = base64::encode(buf);
    try!(write!(f, "{}\n", out));

    Ok(())
}

fn read_base64_file<P: AsRef<Path>>(file: P) -> Result<FileContent, io::Error> {
    let file_display = format!("{}", file.as_ref().display());
    let f = try!(File::open(file));
    let mut reader = BufReader::new(f);

    let mut comment_line = String::new();
    let len = try!(reader.read_line(&mut comment_line));

    if len == 0 || len < COMMENTHDRLEN || !comment_line.starts_with(COMMENTHDR) {
        println!("invalid comment in {}; must start with '{}'", file_display, COMMENTHDR);
        process::exit(1);
    }

    if &comment_line[len-1..len] != "\n" {
        println!("missing new line after comment in '{}'", file_display);
        process::exit(1);
    }

    if len > COMMENTHDRLEN + COMMENTMAXLEN {
        println!("comment too long");
        process::exit(1);
    }

    let mut base64_line = String::new();
    let len = try!(reader.read_line(&mut base64_line));

    if len == 0 {
        println!("missing line in {}", file_display);
        process::exit(1);
    }

    if &base64_line[len-1..len] != "\n" {
        println!("missing new line after comment in '{}'", file_display);
        process::exit(1);
    }

    let base64_line = &base64_line[0..len-1];

    let data = match base64::decode(&base64_line) {
        Ok(data) => data,
        Err(e) => {
            println!("invalid base64 encoding in {}: {:?}", file_display, e);
            process::exit(1);
        }
    };

    if &data[0..2] != PKGALG {
        println!("unsupported file {}", file_display);
        process::exit(1);
    }

    match data.len() {
        x if x == mem::size_of::<PublicKey>() => {
            return PublicKey::from_buf(&data)
                .map(FileContent::PublicKey);
        },
        x if x == mem::size_of::<PrivateKey>() => {
            return PrivateKey::from_buf(&data)
                .map(FileContent::PrivateKey);
        },
        x if x == mem::size_of::<Signature>() => {
            return Signature::from_buf(&data)
                .map(FileContent::Signature);
        },
        _ => {
            println!("unsupported file {}", file_display);
            process::exit(1);
        },
    };
}

fn verify(pubkey_path: String, msg_path: String, signature_path: Option<String>) {
    let pkey = match read_base64_file(&pubkey_path) {
        Ok(FileContent::PublicKey(pkey)) => pkey,
        _ => {
            println!("an error occured.");
            process::exit(2);
        }
    };

    let signature_path = match signature_path {
        Some(path) => path,
        None => format!("{}.sig", msg_path)
    };

    let signature = match read_base64_file(&signature_path) {
        Ok(FileContent::Signature(sig)) => sig,
        _ => {
            println!("Can't read signature from '{}'", signature_path);
            process::exit(2);
        }
    };

    let mut msgfile = File::open(&msg_path).expect(&format!("Can't open message file '{}'", msg_path));
    let mut msg = vec![];
    msgfile.read_to_end(&mut msg).expect(&format!("Can't read file '{}'", msg_path));

    if signature.verify(&msg, &pkey) {
        println!("Signature Verified");
    } else {
        println!("signature verification failed");
        process::exit(1);
    }
}

fn sign(seckey_path: String, msg_path: String, signature_path: Option<String>) {
    let skey = match read_base64_file(&seckey_path) {
        Ok(FileContent::PrivateKey(skey)) => skey,
        _ => {
            println!("an error occured.");
            process::exit(2);
        }
    };

    let mut msgfile = File::open(&msg_path).expect(&format!("Can't open message file '{}'", msg_path));
    let mut msg = vec![];
    msgfile.read_to_end(&mut msg).expect(&format!("Can't read file '{}'", msg_path));

    let signature_path = match signature_path {
        Some(path) => path,
        None => format!("{}.sig", msg_path)
    };

    let sig = skey.sign(&msg);

    let mut out = vec![];
    sig.write(&mut out).expect("Can't write to internal buffer");

    let sig_comment = "signature from signify secret key";
    write_base64_file(&signature_path, sig_comment, &out).unwrap();
}

fn generate(pubkey_path: String, privkey_path: String, comment: Option<String>) {
    let comment = match comment {
        Some(s) => s,
        None    => "signify".into()
    };

    let mut keynum = [0; KEYNUMLEN];

    let mut rng = OsRng::new().expect("Can't create random number generator");
    rng.fill_bytes(&mut keynum);

    let mut seed = [0; 32];
    rng.fill_bytes(&mut seed);
    let (skey, pkey) = ed25519::keypair(&seed);

    // Store private key
    let mut ctx = Sha512::new();
    ctx.input(&skey);
    let mut digest = [0; 64];
    ctx.result(&mut digest);
    let mut checksum = [0; 8];
    checksum.copy_from_slice(&digest[0..8]);

    let mut salt = [0; 16];
    rng.fill_bytes(&mut salt);

    let private_key = PrivateKey {
        pkgalg: PKGALG,
        kdfalg: KDFALG,
        kdfrounds: 0,
        salt: salt,
        checksum: checksum,
        keynum: keynum,
        seckey: skey,
    };

    let mut out = vec![];
    private_key.write(&mut out).expect("Can't write to internal buffer");

    let priv_comment = format!("{} secret key", comment);
    write_base64_file(&privkey_path, &priv_comment, &out).unwrap();

    // Store public key
    let public_key = PublicKey::with_key_and_keynum(pkey, keynum);

    let mut out = vec![];
    public_key.write(&mut out).expect("Can't write to internal buffer");

    let pub_comment = format!("{} public key", comment);
    write_base64_file(&pubkey_path, &pub_comment, &out).unwrap();
}

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

    if args.flag_V {
        verify(args.flag_p, args.flag_m, args.flag_x);
    } else if args.flag_G {
        generate(args.flag_p, args.flag_s, args.flag_c);
    } else if args.flag_S {
        sign(args.flag_s, args.flag_m, args.flag_x);
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::fs::File;

enum Atom {
  S(String),
  Q(String),
  I(i64),
  F(f64),
}

enum Sexp {
  Atom(Atom),
  List(Vec<Sexp>),
}

impl fmt::Display for Atom {
  fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
    match *self {
      Atom::S(ref s) => write!(f, "{}", s),
      Atom::Q(ref s) => write!(f, "\"{}\"", s),
      Atom::I(i)     => write!(f, "{}", i),
      Atom::F(d)     => write!(f, "{}", d),
    }
  }
}

impl fmt::Display for Sexp {
  fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
    match *self {
      Sexp::Atom(ref a) => write!(f, "{}", a),
      Sexp::List(ref xs) => {
        try!(write!(f, "("));
        for (i, x) in xs.iter().enumerate() {
          let s = if i == 0 { "" } else { " " };
          try!(write!(f, "{}{}", s, x));
        }
        write!(f, ")")
      },
    }
  }
}

fn parse_list(vec: &Vec<char>, mut pos: usize) -> (usize, Sexp) {
    println!("list");
    pos += 1;
    let mut l: Vec<Sexp> = Vec::new();
    loop {
        pos = match vec[pos] {
            ')' => {
                break;
            }
            _ => {
                let (pos, s) = parse_sexp(vec, pos);
                l.push(s);
                pos
            }
        }
    }
    println!("Found list");
    (pos, Sexp::List(l))
}

fn parse_quoted_string(vec: &Vec<char>, mut pos: usize) -> (usize, Atom) {
    println!("qstring");
    pos += 1;
    let mut s = String::new();
    loop {
        match vec[pos] {
            '"' => break,
            x => s.push(x)
        }
        pos += 1;
    }
    println!("Found quoted string {}", s);
    (pos+1, Atom::Q(s))
}

fn parse_string(vec: &Vec<char>, mut pos: usize) -> (usize, Atom) {
    println!("string");
    let mut s = String::new();
    loop {
        match vec[pos] {
            ' ' | ')' => break,
            '"' => panic!("quote in unquoted string"),
            x => s.push(x)
        }
        pos += 1;
    }
    println!("Found string {}", s);
    (pos, Atom::S(s))
}

fn parse_number(vec: &Vec<char>, mut pos: usize) -> (usize, Atom) {
    println!("number");
    let mut s = String::new();
    loop {
        match vec[pos] {
            ' ' | ')' => break,
            '0' ... '9' | '.' | '-' => s.push(vec[pos]),
            _ => panic!("unexpected char in number"),
        }
        pos += 1;
    }
    println!("Found number {}", s);
    let s2: &str = &s[..];
    if s.contains('.') {
        (pos, Atom::F(f64::from_str(s2).unwrap()))
    } else {
        (pos, Atom::I(i64::from_str(s2).unwrap()))
    }
}

fn parse_atom(vec: &Vec<char>, pos: usize) -> (usize, Sexp) {
    println!("atom");
    let (pos, a) = match vec[pos] {
        '"' => {
            parse_quoted_string(vec, pos)
        }
        '0' ... '9' | '.' | '-' => {
            parse_number(vec, pos)
        }
        _ => {
            parse_string(vec, pos)
        }
    };
    (pos, Sexp::Atom(a))
}

fn parse_sexp(vec: &Vec<char>, pos: usize) -> (usize, Sexp) {
    let mut pos = pos;
    loop {
        match vec[pos] {
            '(' => {
                return parse_list(vec, pos)
            }
            ' ' | '\r' | '\t' | '\n' => {
                pos += 1;
            }
            _ => {
                return parse_atom(vec, pos)
            }
        }
    }
}

fn parse(data: &str) -> Sexp {
    let vec: Vec<char> = data.chars().collect();
    let (_, res) = parse_sexp(&vec, 0);
    res
}

fn main() {
    let mut f = try!(File::open("data/SILABS_EFM32_QFN24.kicad_mod"));
    let mut s = String::new();
    try!(f.read_to_string(&mut s));
    let res = parse(s);
    println!("res: {}", res)
}
<commit_msg>fix parsing with new lines; fix nested lists<commit_after>use std::fmt;
use std::str::FromStr;

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

enum Atom {
  S(String),
  Q(String),
  I(i64),
  F(f64),
}

enum Sexp {
  Atom(Atom),
  List(Vec<Sexp>),
}

impl fmt::Display for Atom {
  fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
    match *self {
      Atom::S(ref s) => write!(f, "{}", s),
      Atom::Q(ref s) => write!(f, "\"{}\"", s),
      Atom::I(i)     => write!(f, "{}", i),
      Atom::F(d)     => write!(f, "{}", d),
    }
  }
}

impl fmt::Display for Sexp {
  fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
    match *self {
      Sexp::Atom(ref a) => write!(f, "{}", a),
      Sexp::List(ref xs) => {
        try!(write!(f, "("));
        for (i, x) in xs.iter().enumerate() {
          let s = if i == 0 { "" } else { " " };
          try!(write!(f, "{}{}", s, x));
        }
        write!(f, ")")
      },
    }
  }
}

fn parse_list(vec: &Vec<char>, mut pos: usize) -> (usize, Sexp) {
    println!("list");
    pos += 1;
    let mut l: Vec<Sexp> = Vec::new();
    loop {
        pos = match vec[pos] {
            ')' => {
                break;
            }
            _ => {
                let (pos, s) = parse_sexp(vec, pos);
                l.push(s);
                pos
            }
        }
    }
    println!("Found list");
    (pos+1, Sexp::List(l))
}

fn parse_quoted_string(vec: &Vec<char>, mut pos: usize) -> (usize, Atom) {
    println!("qstring");
    pos += 1;
    let mut s = String::new();
    loop {
        match vec[pos] {
            '"' => break,
            x => s.push(x)
        }
        pos += 1;
    }
    println!("Found quoted string {}", s);
    (pos+1, Atom::Q(s))
}

fn parse_string(vec: &Vec<char>, mut pos: usize) -> (usize, Atom) {
    println!("string");
    let mut s = String::new();
    loop {
        match vec[pos] {
            ' ' | '\t' | '\r' | '\n' | ')' => break,
            '"' => panic!("quote in unquoted string {}", s),
            x => s.push(x)
        }
        pos += 1;
    }
    println!("Found string {}", s);
    (pos, Atom::S(s))
}

fn parse_number(vec: &Vec<char>, mut pos: usize) -> (usize, Atom) {
    println!("number");
    let mut s = String::new();
    loop {
        match vec[pos] {
            ' ' | '\r' | '\n' | '\t' | ')' => break,
            '0' ... '9' | '.' | '-' => s.push(vec[pos]),
            _ => panic!("unexpected char in number"),
        }
        pos += 1;
    }
    println!("Found number {}", s);
    let s2: &str = &s[..];
    if s.contains('.') {
        (pos, Atom::F(f64::from_str(s2).unwrap()))
    } else {
        (pos, Atom::I(i64::from_str(s2).unwrap()))
    }
}

fn parse_atom(vec: &Vec<char>, pos: usize) -> (usize, Sexp) {
    println!("atom");
    let (pos, a) = match vec[pos] {
        '"' => {
            parse_quoted_string(vec, pos)
        }
        '0' ... '9' | '.' | '-' => {
            parse_number(vec, pos)
        }
        _ => {
            parse_string(vec, pos)
        }
    };
    (pos, Sexp::Atom(a))
}

fn parse_sexp(vec: &Vec<char>, pos: usize) -> (usize, Sexp) {
    let mut pos = pos;
    loop {
        match vec[pos] {
            '(' => {
                return parse_list(vec, pos)
            }
            ' ' | '\r' | '\t' | '\n' => {
                pos += 1;
            }
            _ => {
                return parse_atom(vec, pos)
            }
        }
    }
}

fn parse(data: &str) -> Sexp {
    let vec: Vec<char> = data.chars().collect();
    let (_, res) = parse_sexp(&vec, 0);
    res
}

fn read_file(name: &str) -> Result<String,std::io::Error> {
    let mut f = try!(File::open(name));
    let mut s = String::new();
    try!(f.read_to_string(&mut s));
    Ok(s)
}

fn main() {
    let s = read_file("../data/SILABS_EFM32_QFN24.kicad_mod").unwrap();
    let res = parse(&s[..]);
    println!("res: {}", res)
}
<|endoftext|>


<commit_before>#![feature(core)]
#![feature(path)]

#![feature(plugin)]
#![plugin(regex_macros)]
extern crate regex;
extern crate git2;
extern crate "rustc-serialize" as rustc_serialize;
extern crate docopt;

use git2::{Repository, Branch, BranchType, DiffLine,
    Commit, Diff, DiffFormat, DiffDelta, DiffHunk, Error, Oid};
use docopt::Docopt;
use std::old_io as io;
use std::old_io::BufferedReader;
use std::old_io::File;
use std::str;
use regex::Regex;

// Write the Docopt usage string.
static USAGE: &'static str = "
Usage: transit <repo> [<old> <new>]

If no commits are given, transit will revwalk from latest to oldest.
";

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_repo: String,
    arg_old: Option<String>,
    arg_new: Option<String>,
}

fn main() {
    // Parse the args above or die.
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());
    // Pull up the revwalk.
    let path = Path::new(args.arg_repo);
    let repo = Repository::discover(&path)
        .ok().expect("Unable to find repo.");
    // If we can destructures the two optional args into real things.
    if let (Some(old_string), Some(new_string)) = (args.arg_old, args.arg_new) {
        // Compare a specific commit pair.
        // Fist, get the commits. (Error checked)
        let old = Oid::from_str(&old_string[]).and_then(|oid| repo.find_commit(oid));
        let new = Oid::from_str(&new_string[]).and_then(|oid| repo.find_commit(oid));
        if old.is_ok() && new.is_ok() {
            let output = find_moves(&repo, &old.unwrap(), &new.unwrap()).unwrap();
            make_output(output);
        } else {
            panic!("Commit ids were not valid.");
        }
    } else {
        // Revwalk.
        let mut revwalk = repo.revwalk()
            .ok().expect("Unable to get revwalk.");
        // Setup some options.
        revwalk.simplify_first_parent(); // TODO: Maybe remove?
        let mut flags = git2::Sort::empty();
        flags.insert(git2::SORT_TIME);
        flags.insert(git2::SORT_TOPOLOGICAL);
        revwalk.set_sorting(flags);
        // Push HEAD to the revwalk.
        revwalk.push_head()
            .ok().expect("Unable to push HEAD.");
        // We sadly must collect here to use `.windows()`
        let history = revwalk.filter_map(|id| repo.find_commit(id).ok())
            .collect::<Vec<Commit>>();
        // Walk through each pair of commits.
        for pair in history.windows(2) {let (old, new) = (&pair[1], &pair[0]);
			let output = find_moves(&repo, old.clone(), new.clone()).unwrap();
			// mangle the vectors here to make pretty output
			make_output(output);
		}
	}
}

fn make_output(output: Vec<Output>) {
	println!("make_output:");
    println!("\toutput.len()={}", output.len());
    for i in range(0, output.len()) {
            println!("\told_commit={}",         output[i].old_commit);
            println!("\tnew_commit={}",         output[i].new_commit);
            println!("\torigin_line={}",        output[i].origin_line);
            println!("\tdestintation_line={}",  output[i].destination_line);
            println!("\tnum_lines={}",          output[i].num_lines);
    }
}

#[derive(Debug)]
enum FoundState {
    Added, Deleted
}

fn dump_diffline(line: &DiffLine) {
    // 'origin' is wrapped in pipes to ease displaying space characters.
    print!("line: old={:?} new={:?} offset={} |origin|=|{}|\n      content={}",
             line.old_lineno(), line.new_lineno(), line.content_offset(),
             line.origin(), str::from_utf8(line.content()).unwrap());
}

fn dump_diffdelta(delta: &DiffDelta) {
    println!("delta: nfiles={} status={:?} old_file=(id={} path_bytes={:?} path={:?} tsize={}) new_file=(id={} path_bytes={:?} path={:?} tsize={})",
            delta.nfiles(), delta.status(),
            delta.old_file().id(), delta.old_file().path_bytes(), delta.old_file().path(), delta.old_file().size(),
            delta.new_file().id(), delta.new_file().path_bytes(), delta.new_file().path(), delta.new_file().size());
}

fn format_key(key: String) -> String {
    let remove_whitespace = regex!(r"\s{2,}"); // 2 or more whitespaces    // TODO Removes whitespace from a string.
    remove_whitespace.replace_all(key.as_slice(), "")
}

#[derive(Debug)]
struct Found {
    filename: Path,
    key: String,
    state: FoundState,
}

fn find_keys(diff: Diff) -> Vec<Found> {

    #[derive(Debug)]
    enum State {
        Other, Addition, Deletion
    }

    let mut founds: Vec<Found> = Vec::new();

    let mut state = State::Other;
    let mut added = String::new();
    let mut deleted = String::new();
    let mut old_path = Path::new("");
    let mut new_path = Path::new("");

	// Read about this function in http://alexcrichton.com/git2-rs/git2/struct.Diff.html#method.print
	// It's a bit weird, but I think it will provide the necessary information.
	diff.print(DiffFormat::Patch, |delta, maybe_hunk, line| -> bool {

        assert!(delta.nfiles() == 2, "This only works on diffs between exactly 2 files.");

		// Thinking:
		//  * If is not a hunk, keep going.
		//  * If it's a hunk, do regex magic.
		//  * Stick regex output into a hashmap as a hash.
		//  * Later, we will iterate through and output pased on the values.
		// Filter out all the boring context lines.
		// If we're not interested in this line just return since it will iterate to the next.
		if maybe_hunk.is_none() { return true }; // Return early.

        println!("top of loop: founds={:?}", founds);
        println!("top of loop: added={:?} deleted={:?}", added, deleted);

        dump_diffline(&line);
        //dump_diffdelta(&delta);

        old_path = delta.old_file().path().unwrap().clone();
        new_path = delta.new_file().path().unwrap().clone();

		match line.origin() {
			// Additions
			'+' | '>' => {
                println!("In additions. state={:?}", state);

                added.push_str(str::from_utf8(line.content()).unwrap());

                match state {
                    State::Deletion => {
                        founds.push(Found {
                            filename: old_path.clone(),
                            key: format_key(deleted.clone()),
                            state: FoundState::Deleted,
                        });
                        deleted = String::new();
                    },
                    _ => (),
                }

                state = State::Addition;
				true
			},
			// Deletions
			'-' | '<' => {
                println!("In deletion. state={:?}", state);

                deleted.push_str(str::from_utf8(line.content()).unwrap());

                match state {
                    State::Addition => {
                        founds.push(Found {
                            filename: new_path.clone(),
                            key: format_key(added.clone()),
                            state: FoundState::Added,
                        });
                        added = String::new();
                    },
                    _ => (),
                }

                state = State::Deletion;
				true
			},
			// Other
			_         => {
                println!("in _. state={:?}", state);

                match state {
                    State::Addition => {
                        founds.push(Found {
                            filename: new_path.clone(),
                            key: format_key(added.clone()),
                            state: FoundState::Added,
                        });
                        added = String::new();
                    },
                    State::Deletion => {
                        founds.push(Found {
                            filename: old_path.clone(),
                            key: format_key(deleted.clone()),
                            state: FoundState::Deleted,
                        });
                        deleted = String::new();
                    },
                    _ => (),
                }

                state = State::Other;
                true
            }
		}
	});

    // Grab one.
    match state {
        State::Addition => {
            if added.len() > 0 {
                founds.push(Found {
                    filename: new_path,
                    key: format_key(added.clone()),
                    state: FoundState::Added,
                });
            }
        },
        State::Deletion => {
            if deleted.len() > 0 {
                founds.push(Found {
                    filename: old_path,
                    key: format_key(deleted.clone()),
                    state: FoundState::Deleted,
                });
            }
        },
        _ => (),
    }

    return founds;
}

fn find_moves(repo: &Repository, old: &Commit, new: &Commit) -> Result<Vec<Output>, Error> {

    println!("\nFIND MOVES---------------------");

	let old_tree = try!(old.tree());
	let new_tree = try!(new.tree());
	// Build up a diff of the two trees.
	let diff = try!(Diff::tree_to_tree(repo, Some(&old_tree), Some(&new_tree), None));

    let mut founds: Vec<Found> = find_keys(diff);

    println!("FOUNDS={:?}", founds);

    Ok(vec![Output {
	    old_commit: old.id(),
	    new_commit: new.id(),
        old_filename: String::from_str("oldfilename"),
        new_filename: String::from_str("newfilename"),
	    origin_line: 0,
	    destination_line: 0,
	    num_lines: 0
    }])
}

#[derive(Debug)]
struct Output {
    old_commit: Oid,
    new_commit: Oid,
    old_filename: String,
    new_filename: String,
    origin_line: u32,
    destination_line: u32,
    num_lines: u32,
}
<commit_msg>Track line count of additions and deletions.<commit_after>#![feature(core)]
#![feature(path)]

#![feature(plugin)]
#![plugin(regex_macros)]
extern crate regex;
extern crate git2;
extern crate "rustc-serialize" as rustc_serialize;
extern crate docopt;

use git2::{Repository, Branch, BranchType, DiffLine,
    Commit, Diff, DiffFormat, DiffDelta, DiffHunk, Error, Oid};
use docopt::Docopt;
use std::old_io as io;
use std::old_io::BufferedReader;
use std::old_io::File;
use std::str;
use regex::Regex;

// Write the Docopt usage string.
static USAGE: &'static str = "
Usage: transit <repo> [<old> <new>]

If no commits are given, transit will revwalk from latest to oldest.
";

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_repo: String,
    arg_old: Option<String>,
    arg_new: Option<String>,
}

fn main() {
    // Parse the args above or die.
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());
    // Pull up the revwalk.
    let path = Path::new(args.arg_repo);
    let repo = Repository::discover(&path)
        .ok().expect("Unable to find repo.");
    // If we can destructures the two optional args into real things.
    if let (Some(old_string), Some(new_string)) = (args.arg_old, args.arg_new) {
        // Compare a specific commit pair.
        // Fist, get the commits. (Error checked)
        let old = Oid::from_str(&old_string[]).and_then(|oid| repo.find_commit(oid));
        let new = Oid::from_str(&new_string[]).and_then(|oid| repo.find_commit(oid));
        if old.is_ok() && new.is_ok() {
            let output = find_moves(&repo, &old.unwrap(), &new.unwrap()).unwrap();
            make_output(output);
        } else {
            panic!("Commit ids were not valid.");
        }
    } else {
        // Revwalk.
        let mut revwalk = repo.revwalk()
            .ok().expect("Unable to get revwalk.");
        // Setup some options.
        revwalk.simplify_first_parent(); // TODO: Maybe remove?
        let mut flags = git2::Sort::empty();
        flags.insert(git2::SORT_TIME);
        flags.insert(git2::SORT_TOPOLOGICAL);
        revwalk.set_sorting(flags);
        // Push HEAD to the revwalk.
        revwalk.push_head()
            .ok().expect("Unable to push HEAD.");
        // We sadly must collect here to use `.windows()`
        let history = revwalk.filter_map(|id| repo.find_commit(id).ok())
            .collect::<Vec<Commit>>();
        // Walk through each pair of commits.
        for pair in history.windows(2) {let (old, new) = (&pair[1], &pair[0]);
			let output = find_moves(&repo, old.clone(), new.clone()).unwrap();
			// mangle the vectors here to make pretty output
			make_output(output);
		}
	}
}

fn make_output(output: Vec<Output>) {
	println!("make_output:");
    println!("\toutput.len()={}", output.len());
    for i in range(0, output.len()) {
            println!("\told_commit={}",         output[i].old_commit);
            println!("\tnew_commit={}",         output[i].new_commit);
            println!("\torigin_line={}",        output[i].origin_line);
            println!("\tdestintation_line={}",  output[i].destination_line);
            println!("\tnum_lines={}",          output[i].num_lines);
    }
}

#[derive(Debug)]
enum FoundState {
    Added, Deleted
}

fn dump_diffline(line: &DiffLine) {
    // 'origin' is wrapped in pipes to ease displaying space characters.
    print!("line: old={:?} new={:?} offset={} |origin|=|{}|\n      content={}",
             line.old_lineno(), line.new_lineno(), line.content_offset(),
             line.origin(), str::from_utf8(line.content()).unwrap());
}

fn dump_diffdelta(delta: &DiffDelta) {
    println!("delta: nfiles={} status={:?} old_file=(id={} path_bytes={:?} path={:?} tsize={}) new_file=(id={} path_bytes={:?} path={:?} tsize={})",
            delta.nfiles(), delta.status(),
            delta.old_file().id(), delta.old_file().path_bytes(), delta.old_file().path(), delta.old_file().size(),
            delta.new_file().id(), delta.new_file().path_bytes(), delta.new_file().path(), delta.new_file().size());
}

fn format_key(key: String) -> String {
    let remove_whitespace = regex!(r"\s{2,}"); // 2 or more whitespaces    // TODO Removes whitespace from a string.
    remove_whitespace.replace_all(key.as_slice(), "")
}

#[derive(Debug)]
struct Found {
    filename: Path,
    key: String,
    state: FoundState,
    length: u64,
}

fn find_keys(diff: Diff) -> Vec<Found> {

    #[derive(Debug)]
    enum State {
        Other, Addition, Deletion
    }

    let mut founds: Vec<Found> = Vec::new();

    let mut state = State::Other;
    let mut added = String::new();
    let mut deleted = String::new();
    let mut old_path = Path::new("");
    let mut new_path = Path::new("");

    let mut length: u64 = 0;

	// Read about this function in http://alexcrichton.com/git2-rs/git2/struct.Diff.html#method.print
	// It's a bit weird, but I think it will provide the necessary information.
	diff.print(DiffFormat::Patch, |delta, maybe_hunk, line| -> bool {

        assert!(delta.nfiles() == 2, "This only works on diffs between exactly 2 files.");

		// Thinking:
		//  * If is not a hunk, keep going.
		//  * If it's a hunk, do regex magic.
		//  * Stick regex output into a hashmap as a hash.
		//  * Later, we will iterate through and output pased on the values.
		// Filter out all the boring context lines.
		// If we're not interested in this line just return since it will iterate to the next.
		if maybe_hunk.is_none() { return true }; // Return early.

        println!("top of loop: founds={:?}", founds);
        println!("top of loop: added={:?} deleted={:?}", added, deleted);
        println!("top of loop: length={:?}", length);

        dump_diffline(&line);
        //dump_diffdelta(&delta);

        old_path = delta.old_file().path().unwrap().clone();
        new_path = delta.new_file().path().unwrap().clone();

		match line.origin() {
			// Additions
			'+' | '>' => {
                println!("In additions. state={:?}", state);

                added.push_str(str::from_utf8(line.content()).unwrap());

                match state {
                    State::Deletion => {
                        founds.push(Found {
                            filename: old_path.clone(),
                            key: format_key(deleted.clone()),
                            state: FoundState::Deleted,
                            length: length,
                        });
                        deleted = String::new();
                        length = 0;
                    },
                    State::Addition => { length += 1; },
                    State::Other    => { length = 1;  },
                }

                state = State::Addition;
				true
			},
			// Deletions
			'-' | '<' => {
                println!("In deletion. state={:?}", state);

                deleted.push_str(str::from_utf8(line.content()).unwrap());

                match state {
                    State::Addition => {
                        founds.push(Found {
                            filename: new_path.clone(),
                            key: format_key(added.clone()),
                            state: FoundState::Added,
                            length: length,
                        });
                        added = String::new();
                        length = 0;
                    },
                    State::Deletion => { length += 1; },
                    State::Other    => { length = 1;  },
                }

                state = State::Deletion;
				true
			},
			// Other
			_         => {
                println!("in _. state={:?}", state);

                match state {
                    State::Addition => {
                        founds.push(Found {
                            filename: new_path.clone(),
                            key: format_key(added.clone()),
                            state: FoundState::Added,
                            length: length,
                        });
                        added = String::new();
                    },
                    State::Deletion => {
                        founds.push(Found {
                            filename: old_path.clone(),
                            key: format_key(deleted.clone()),
                            state: FoundState::Deleted,
                            length: length,
                        });
                        deleted = String::new();
                    },
                    _ => (),
                }

                state = State::Other;
                true
            }
		}
	});

    // Grab one.
    match state {
        State::Addition => {
            if added.len() > 0 {
                founds.push(Found {
                    filename: new_path,
                    key: format_key(added.clone()),
                    state: FoundState::Added,
                    length: length,
                });
            }
        },
        State::Deletion => {
            if deleted.len() > 0 {
                founds.push(Found {
                    filename: old_path,
                    key: format_key(deleted.clone()),
                    state: FoundState::Deleted,
                    length: length,
                });
            }
        },
        _ => (),
    }

    return founds;
}

fn find_moves(repo: &Repository, old: &Commit, new: &Commit) -> Result<Vec<Output>, Error> {

    println!("\nFIND MOVES---------------------");

	let old_tree = try!(old.tree());
	let new_tree = try!(new.tree());
	// Build up a diff of the two trees.
	let diff = try!(Diff::tree_to_tree(repo, Some(&old_tree), Some(&new_tree), None));

    let mut founds: Vec<Found> = find_keys(diff);

    println!("FOUNDS={:?}", founds);

    Ok(vec![Output {
	    old_commit: old.id(),
	    new_commit: new.id(),
        old_filename: String::from_str("oldfilename"),
        new_filename: String::from_str("newfilename"),
	    origin_line: 0,
	    destination_line: 0,
	    num_lines: 0
    }])
}

#[derive(Debug)]
struct Output {
    old_commit: Oid,
    new_commit: Oid,
    old_filename: String,
    new_filename: String,
    origin_line: u32,
    destination_line: u32,
    num_lines: u32,
}
<|endoftext|>