<commit_before>extern crate rucc;
use rucc::common;

extern crate ansi_term;
use self::ansi_term::Colour;

extern crate clap;
use clap::{App, Arg};

const VERSION_STR: &'static str = env!("CARGO_PKG_VERSION");

fn main() {
    let mut app = App::new("rucc")
        .version(VERSION_STR)
        .author("uint256_t")
        .about("rucc is a small toy C compiler in Rust")
        .arg(
            Arg::with_name("version")
                .short("v")
                .long("version")
                .help("Show version info"),
        )
        .arg(Arg::with_name("FILE").help("Input file").index(1));
    let app_matches = app.clone().get_matches();

    if app_matches.is_present("version") {
        app.write_version(&mut ::std::io::stdout());
        println!();
    } else if let Some(filename) = app_matches.value_of("FILE") {
        common::run_file(filename);
        println!("{}", Colour::Green.paint("Compiling exited successfully."));
    } else {
        app.print_help();
        println!();
    }
}

#[test]
fn compare_with_clang_output() {
    use std::fs;
    use std::process::Command;
    use std::io::{stderr, Write};

    let examples_paths = match fs::read_dir("example") {
        Ok(paths) => paths,
        Err(e) => panic!(format!("error: {:?}", e.kind())),
    };
    for path in examples_paths {
        let name = path.unwrap().path().to_str().unwrap().to_string();
        writeln!(&mut stderr(), "comparing {}...", name).unwrap();

        Command::new("./rucc.sh")
            .arg(name.to_string())
            .spawn()
            .expect("failed to run")
            .wait()
            .expect("failed to run");
        let output1 = Command::new("./a.out").output().expect("failed to run");
        Command::new("clang")
            .arg(name)
            .arg("-lm")
            .arg("-w")
            .spawn()
            .expect("failed to run")
            .wait()
            .expect("failed to run");
        let output2 = Command::new("./a.out").output().expect("failed to run");
        assert!(output1 == output2);
    }
}

#[test]
fn compile_all_examples() {
    use std::fs;
    use rucc::{codegen, lexer, parser};
    use std::io::{stderr, Write};

    let examples_paths = match fs::read_dir("example") {
        Ok(paths) => paths,
        Err(e) => panic!(format!("error: {:?}", e.kind())),
    };
    for path in examples_paths {
        let name = path.unwrap().path().to_str().unwrap().to_string();
        writeln!(&mut stderr(), "compiling {}...", name).unwrap();

        // for coverage...
        unsafe {
            let mut nodes = Vec::new();
            let mut lexer = lexer::Lexer::new(name.to_string());
            let mut parser = parser::Parser::new(&mut lexer);
            let mut codegen = codegen::Codegen::new("test");
            loop {
                match parser.read_toplevel(&mut nodes) {
                    Err(parser::Error::EOF) => break,
                    Err(_) => continue,
                    _ => {}
                }
                for node in &nodes {
                    node.show();
                }
                match codegen.run(&nodes) {
                    Ok(_) => {}
                    Err(e) => panic!(format!("err in codegen: {:?}", e)),
                }
                nodes.clear();
            }
        }
    }
}
<commit_msg>simplify cmd opt<commit_after>extern crate rucc;
use rucc::common;

extern crate ansi_term;
use self::ansi_term::Colour;

extern crate clap;
use clap::{App, Arg};

const VERSION_STR: &'static str = env!("CARGO_PKG_VERSION");

fn main() {
    let mut app = App::new("rucc")
        .version(VERSION_STR)
        .author("uint256_t")
        .about("rucc is a small toy C compiler in Rust")
        .arg(
            Arg::with_name("version")
                .short("v")
                .long("version")
                .help("Show version info"),
        )
        .arg(Arg::with_name("FILE").help("Input file").index(1));
    let app_matches = app.clone().get_matches();

    if let Some(filename) = app_matches.value_of("FILE") {
        common::run_file(filename);
        println!("{}", Colour::Green.paint("Compiling exited successfully."));
    } else {
        app.print_help();
        println!();
    }
}

#[test]
fn compare_with_clang_output() {
    use std::fs;
    use std::process::Command;
    use std::io::{stderr, Write};

    let examples_paths = match fs::read_dir("example") {
        Ok(paths) => paths,
        Err(e) => panic!(format!("error: {:?}", e.kind())),
    };
    for path in examples_paths {
        let name = path.unwrap().path().to_str().unwrap().to_string();
        writeln!(&mut stderr(), "comparing {}...", name).unwrap();

        Command::new("./rucc.sh")
            .arg(name.to_string())
            .spawn()
            .expect("failed to run")
            .wait()
            .expect("failed to run");
        let output1 = Command::new("./a.out").output().expect("failed to run");
        Command::new("clang")
            .arg(name)
            .arg("-lm")
            .arg("-w")
            .spawn()
            .expect("failed to run")
            .wait()
            .expect("failed to run");
        let output2 = Command::new("./a.out").output().expect("failed to run");
        assert!(output1 == output2);
    }
}

#[test]
fn compile_all_examples() {
    use std::fs;
    use rucc::{codegen, lexer, parser};
    use std::io::{stderr, Write};

    let examples_paths = match fs::read_dir("example") {
        Ok(paths) => paths,
        Err(e) => panic!(format!("error: {:?}", e.kind())),
    };
    for path in examples_paths {
        let name = path.unwrap().path().to_str().unwrap().to_string();
        writeln!(&mut stderr(), "compiling {}...", name).unwrap();

        // for coverage...
        unsafe {
            let mut nodes = Vec::new();
            let mut lexer = lexer::Lexer::new(name.to_string());
            let mut parser = parser::Parser::new(&mut lexer);
            let mut codegen = codegen::Codegen::new("test");
            loop {
                match parser.read_toplevel(&mut nodes) {
                    Err(parser::Error::EOF) => break,
                    Err(_) => continue,
                    _ => {}
                }
                for node in &nodes {
                    node.show();
                }
                match codegen.run(&nodes) {
                    Ok(_) => {}
                    Err(e) => panic!(format!("err in codegen: {:?}", e)),
                }
                nodes.clear();
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::fmt;
use std::fs::{File, rename, remove_file};
use std::io::{BufRead, Write};
use std::io;
use std::path::PathBuf;
use std::process::Command;

extern crate tempfile;

use tempfile::NamedTempFile;

enum Operation {
    NoOp,
    Remove,
    Rename { new_path: PathBuf }
}

struct Change {
    path: PathBuf,
    operation: Operation
}

trait Operate {
    fn operate(&self) -> io::Result<()>;
}

impl Operate for Change {
    fn operate(&self) -> io::Result<()> {
        match self.operation {
            Operation::NoOp => Ok(()),
            Operation::Remove => remove_file(&self.path),
            Operation::Rename { ref new_path } => rename(&self.path, new_path)
        }
    }
}

impl fmt::Display for Change {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.operation {
            Operation::NoOp => write!(f, ""),
            Operation::Remove => write!(f, "{}", &self.path.to_str().unwrap()),
            Operation::Rename { ref new_path } => write!(f, "{} → {}", &self.path.to_str().unwrap(), new_path.to_str().unwrap())
        }
    }
}

fn lookup_program() -> String {
    match env::var_os("VISUAL") {
        Some(val) => val,
        None => env::var_os("EDITOR").expect("Set $VISUAL or $EDITOR to use edfp")
    }.into_string().unwrap()
}

fn parse_lines(lines: (String, String)) -> Change {
    let (given, new) = lines;
    Change { operation: Operation::NoOp, path: PathBuf::from(given) }
}

fn describe_modifying_changes<O: io::Write>(header: &str, changes: &Vec<&Change>, mut output: O) -> O {
    if !changes.is_empty() {
        writeln!(output, "{}", header);
        for change in changes {
            writeln!(output, "\t{}", change);
        }
    }
    output
}

fn describe_changes<O: io::Write>(changes: &Vec<Change>, mut output: O) {
    let removals: Vec<&Change> = changes.iter().filter(|c| match c.operation {
        Operation::Remove => true,
        _ => false
    }).collect();
    let renamings: Vec<&Change> = changes.iter().filter(|c| match c.operation {
        Operation::Rename { ref new_path } => true,
        _ => false
    }).collect();

    if renamings.is_empty() && removals.is_empty() {
        writeln!(output, "No changes.");
    }

    let output = describe_modifying_changes("Remove/delete the following files:", &removals, output);
    describe_modifying_changes("Rename/move the following files:", &renamings, output);
}

fn user_approves_changes<I: io::Read>(mut input: I) -> bool {
    true
}

fn edfp<I: io::Read, O: io::Write>(mut input: I, mut output: O) {
    let mut buf = String::new();
    input.read_to_string(&mut buf).expect("Failed to read input");

    let mut tmp: NamedTempFile = NamedTempFile::new().expect("failed to create temporary file");
    tmp.write_all(&buf.as_bytes()).expect("Could not write to tempfile");

    let editor_program = lookup_program();
    let tmp_path_str = tmp.path().to_str().expect("failed to parse tmp path");
    let editor = Command::new(editor_program.as_str()).arg(tmp_path_str).spawn();

    let success = editor
        .ok()
        .expect(format!("failed to launch {}", editor_program).as_str())
        .wait()
        .expect(format!("failed to wait for {}", editor_program).as_str())
        .success();

    if !success {
        panic!(format!("{} exited non-zero", editor_program));
    }

    let commands_file = tmp.reopen().ok().expect("failed to re-open");
    let commands = io::BufReader::new(commands_file).lines()
        .map(|line| line.ok().expect("failed to read line from commands file"));
    let changes: Vec<Change> = buf.lines().map(String::from).zip(commands).map(parse_lines).collect();

    describe_changes(&changes, output);

    if user_approves_changes(input) {
        for change in changes {
            change.operate().ok().expect("failed to change")
        }
    }
}

fn main() {
    let input = io::stdin();
    let mut output = io::stdout();
    edfp(input, output)
}
<commit_msg>Implement parse lines.<commit_after>use std::env;
use std::fmt;
use std::fs::{File, rename, remove_file};
use std::io::{BufRead, Write};
use std::io;
use std::path::PathBuf;
use std::process::Command;

extern crate tempfile;

use tempfile::NamedTempFile;

#[derive(Debug)]
enum Operation {
    NoOp,
    Remove,
    Rename { new_path: PathBuf }
}

#[derive(Debug)]
struct Change {
    path: PathBuf,
    operation: Operation
}

trait Operate {
    fn operate(&self) -> io::Result<()>;
}

impl Operate for Change {
    fn operate(&self) -> io::Result<()> {
        match self.operation {
            Operation::NoOp => Ok(()),
            Operation::Remove => remove_file(&self.path),
            Operation::Rename { ref new_path } => rename(&self.path, new_path)
        }
    }
}

impl fmt::Display for Change {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.operation {
            Operation::NoOp => write!(f, ""),
            Operation::Remove => write!(f, "{}", &self.path.to_str().unwrap()),
            Operation::Rename { ref new_path } => write!(f, "{} → {}", &self.path.to_str().unwrap(), new_path.to_str().unwrap())
        }
    }
}

fn lookup_program() -> String {
    match env::var_os("VISUAL") {
        Some(val) => val,
        None => env::var_os("EDITOR").expect("Set $VISUAL or $EDITOR to use edfp")
    }.into_string().unwrap()
}

fn parse_lines(lines: (String, String)) -> Change {
    let (given, new) = lines;
    let path = PathBuf::from(&given);
    let empty_string = String::new();
    if new == given {
        Change { operation: Operation::NoOp, path }
    } else if new == String::new() {
        Change { operation: Operation::Remove, path }
    } else {
        Change {
            operation: Operation::Rename {
                new_path: PathBuf::from(new)
            },
            path
        }
    }
}

fn describe_modifying_changes<O: io::Write>(header: &str, changes: &Vec<&Change>, mut output: O) -> O {
    if !changes.is_empty() {
        writeln!(output, "{}", header);
        for change in changes {
            writeln!(output, "\t{}", change);
        }
    }
    output
}

fn describe_changes<O: io::Write>(changes: &Vec<Change>, mut output: O) {
    let removals: Vec<&Change> = changes.iter().filter(|c| match c.operation {
        Operation::Remove => true,
        _ => false
    }).collect();
    let renamings: Vec<&Change> = changes.iter().filter(|c| match c.operation {
        Operation::Rename { ref new_path } => true,
        _ => false
    }).collect();

    if renamings.is_empty() && removals.is_empty() {
        writeln!(output, "No changes.");
    }

    let output = describe_modifying_changes("Remove/delete the following files:", &removals, output);
    describe_modifying_changes("Rename/move the following files:", &renamings, output);
}

fn user_approves_changes<I: io::Read>(mut input: I) -> bool {
    true
}

fn edfp<I: io::Read, O: io::Write>(mut input: I, mut output: O) {
    let mut buf = String::new();
    input.read_to_string(&mut buf).expect("Failed to read input");

    let mut tmp: NamedTempFile = NamedTempFile::new().expect("failed to create temporary file");
    tmp.write_all(&buf.as_bytes()).expect("Could not write to tempfile");

    let editor_program = lookup_program();
    let tmp_path_str = tmp.path().to_str().expect("failed to parse tmp path");
    let editor = Command::new(editor_program.as_str()).arg(tmp_path_str).spawn();

    let success = editor
        .ok()
        .expect(format!("failed to launch {}", editor_program).as_str())
        .wait()
        .expect(format!("failed to wait for {}", editor_program).as_str())
        .success();

    if !success {
        panic!(format!("{} exited non-zero", editor_program));
    }

    let commands_file = tmp.reopen().ok().expect("failed to re-open");
    let commands = io::BufReader::new(commands_file).lines()
        .map(|line| line.ok().expect("failed to read line from commands file"));
    let changes: Vec<Change> = buf.lines().map(String::from).zip(commands).map(parse_lines).collect();

    describe_changes(&changes, output);

    if user_approves_changes(input) {
        for change in changes {
            change.operate().ok().expect("failed to change")
        }
    }
}

fn main() {
    let input = io::stdin();
    let mut output = io::stdout();
    edfp(input, output)
}
<|endoftext|>


<commit_before>//
//	main.rs
//	SweetEngine
//
//	Copyright (c) 2015 Infinite
//	Licensed under the terms of the Apache License, v2
//

//----------------------------------------------------------------

//	Feature gates
#![feature(plugin)]
#![feature(core)]

//	Imports
#[plugin] extern crate glium_macros;
#[macro_use] extern crate glium;
extern crate glutin;

//	Global namespace pollution ;P
use std::old_io::timer;
use std::time::Duration;
use glium::{DisplayBuild, Surface};

//----------------------------------------------------------------

//	Our vertex struct
#[vertex_format]
#[derive(Copy)]
struct Vertex
{
	position: [f32; 2],
	color: [f32; 3],
}

//----------------------------------------------------------------

fn main()
{
	let display = glutin::WindowBuilder::new()
		.with_vsync()
		.with_gl_version((4, 1))
		.with_dimensions(960, 540)
		.with_title(format!("SweetWindow"))
		.build_glium().unwrap();

	let vertex_buffer = {
		glium::VertexBuffer::new(&display,
			vec!
			[
				Vertex { position: [-0.5, -0.5], color: [0.0, 1.0, 0.0] },
				Vertex { position: [ 0.0,  0.5], color: [0.0, 0.0, 1.0] },
				Vertex { position: [ 0.5, -0.5], color: [1.0, 0.0, 0.0] },
			]
		)
	};

	let index_buffer = glium::IndexBuffer::new(&display,
		glium::index_buffer::TrianglesList(vec![0u16, 1, 2]));

	let program = glium::Program::from_source(&display,
		"#version 410
		 uniform mat4 matrix;

		 in vec2 position;
		 in vec3 color;

		 out vec3 vColor;

		 void main()
		 {
		 	gl_Position = vec4(position, 0.0, 1.0) * matrix;
		 	vColor = color;
		 }",

		"#version 410
		 in vec3 vColor;

		 out vec4 fragColor;

		 void main()
		 {
		 	fragColor = vec4(vColor, 1.0);
		 }", None).unwrap();

	'main: loop
	{
		let uniforms = uniform!
		{
			matrix:
			[
				[1.0, 0.0, 0.0, 0.0],
				[0.0, 1.0, 0.0, 0.0],
				[0.0, 0.0, 1.0, 0.0],
				[0.0, 0.0, 0.0, 1.0f32]
			]
		};

		let mut target = display.draw();
		target.clear_color(0.0, 0.0, 0.0, 0.0);
		target.draw(&vertex_buffer, &index_buffer, &program, &uniforms, &std::default::Default::default());
		target.finish();

        timer::sleep(Duration::milliseconds(10));

        for event in display.poll_events()
        {
            match event
            {
                glutin::Event::Closed => break 'main,
                _ => ()
            }
        }
	}
}

//----------------------------------------------------------------
<commit_msg>Tab indentation master race.<commit_after>//
//	main.rs
//	SweetEngine
//
//	Copyright (c) 2015 Infinite
//	Licensed under the terms of the Apache License, v2
//

//----------------------------------------------------------------

//	Feature gates
#![feature(plugin)]
#![feature(core)]

//	Imports
#[plugin] extern crate glium_macros;
#[macro_use] extern crate glium;
extern crate glutin;

//	Global namespace pollution ;P
use std::old_io::timer;
use std::time::Duration;
use glium::{DisplayBuild, Surface};

//----------------------------------------------------------------

//	Our vertex struct
#[vertex_format]
#[derive(Copy)]
struct Vertex
{
	position: [f32; 2],
	color: [f32; 3],
}

//----------------------------------------------------------------

fn main()
{
	let display = glutin::WindowBuilder::new()
		.with_vsync()
		.with_gl_version((4, 1))
		.with_dimensions(960, 540)
		.with_title(format!("SweetWindow"))
		.build_glium().unwrap();

	let vertex_buffer = {
		glium::VertexBuffer::new(&display,
			vec!
			[
				Vertex { position: [-0.5, -0.5], color: [0.0, 1.0, 0.0] },
				Vertex { position: [ 0.0,  0.5], color: [0.0, 0.0, 1.0] },
				Vertex { position: [ 0.5, -0.5], color: [1.0, 0.0, 0.0] },
			]
		)
	};

	let index_buffer = glium::IndexBuffer::new(&display,
		glium::index_buffer::TrianglesList(vec![0u16, 1, 2]));

	let program = glium::Program::from_source(&display,
		"#version 410
		 uniform mat4 matrix;

		 in vec2 position;
		 in vec3 color;

		 out vec3 vColor;

		 void main()
		 {
		 	gl_Position = vec4(position, 0.0, 1.0) * matrix;
		 	vColor = color;
		 }",

		"#version 410
		 in vec3 vColor;

		 out vec4 fragColor;

		 void main()
		 {
		 	fragColor = vec4(vColor, 1.0);
		 }", None).unwrap();

	'main: loop
	{
		let uniforms = uniform!
		{
			matrix:
			[
				[1.0, 0.0, 0.0, 0.0],
				[0.0, 1.0, 0.0, 0.0],
				[0.0, 0.0, 1.0, 0.0],
				[0.0, 0.0, 0.0, 1.0f32]
			]
		};

		let mut target = display.draw();
		target.clear_color(0.0, 0.0, 0.0, 0.0);
		target.draw(&vertex_buffer, &index_buffer, &program, &uniforms, &std::default::Default::default());
		target.finish();

		timer::sleep(Duration::milliseconds(10));

		for event in display.poll_events()
		{
			match event
			{
				glutin::Event::Closed => break 'main,
				_ => ()
			}
		}
	}
}

//----------------------------------------------------------------
<|endoftext|>


<commit_before>// ---------------------------------------------------------------------------------------
// Ruthenium, an ack-like searcher, (c) 2015 Georg Brandl.
// Licensed under the MIT license.
// ---------------------------------------------------------------------------------------

#[macro_use]
extern crate clap;
extern crate libc;
extern crate regex_dfa;
extern crate walkdir;
extern crate memmap;
extern crate scoped_threadpool;
extern crate num_cpus;
extern crate glob;

mod search;
mod ignore;
mod display;
mod options;

use std::cmp::max;
use std::sync::mpsc::{channel, Sender};
use std::thread;
use memmap::{Mmap, Protection};
use scoped_threadpool::Pool;
use walkdir::WalkDirIterator;

use display::DisplayMode;
use search::FileResult;
use options::Opts;

/// Walk a directory (given in Opts) and check all found files.
///
/// The channel is used to send result structs to the main thread, which gives
/// them to the DisplayMode for output.
///
/// The thread of this function only does the directory walking, it spawns a
/// number of worker threads in a pool to grep individual files.
fn walk(chan: Sender<FileResult>, opts: &Opts) {
    // thread pool for individual file grep worker threads
    let mut pool = Pool::new(max(opts.workers - 1, 1));
    // create the regex object
    let regex = search::create_rx(&opts);

    let walker = walkdir::WalkDir::new(&opts.path)
        .follow_links(opts.follow_links)
        .max_depth(opts.depth);
    pool.scoped(|scope| {
        let rx = &regex;  // borrow for closures
        // stack of directories being walked, maintained in the filter closure
        let mut parent_stack: Vec<::std::path::PathBuf> = Vec::new();
        // stack of Ignore structs per directory in parent_stack, they accumulate
        // XXX: add global ignores from cmdline and a config file here
        let mut ignore_stack = Vec::new();
        let walker = walker.into_iter().filter_entry(|entry| {
            // remove parents from stack that are not applicable anymore
            let new_parent = entry.path().parent().unwrap();
            while !parent_stack.is_empty() &&
                parent_stack.last().unwrap().as_path() != new_parent
            {
                ignore_stack.pop();
                parent_stack.pop();
            }
            // weed out hidden files (this is separate from ignored)
            let path = entry.path();
            if let Some(fname) = path.file_name() {
                if !opts.do_hidden && fname.to_string_lossy().starts_with(".") {
                    return false;
                }
            }
            // weed out ignored files and directories (if we return false here for
            // directories, the contents are pruned from the iterator)
            if opts.check_ignores && ignore::match_patterns(path, &ignore_stack) {
                return false;
            }
            // we got a new dir? put it onto the stack
            if entry.file_type().is_dir() {
                let new_path = entry.path().to_path_buf();
                // read ignore patterns specific to this directory
                ignore_stack.push(ignore::read_patterns(&new_path));
                parent_stack.push(new_path);
            }
            true
        });
        for entry in walker {
            if let Ok(entry) = entry {
                // only touch normal files
                if !entry.file_type().is_file() {
                    continue;
                }
                // open and search file in one of the worker threads
                let ch = chan.clone();
                scope.execute(move || {
                    let path = entry.path();
                    if let Ok(map) = Mmap::open_path(path, Protection::Read) {
                        let buf = unsafe { map.as_slice() };
                        let res = search::search(rx, &opts, path, buf);
                        ch.send(res).unwrap();
                    }
                });
            }
        }
    });
}

/// Run the main action.  This is separated from `main` so that it can get a generic
/// DisplayMode argument.
///
/// Spawns the walker thread and prints the results.
fn run<D: DisplayMode>(display: &mut D, opts: Opts) {
    let (w_chan, r_chan) = channel();
    thread::spawn(move || {
        walk(w_chan, &opts);
    });
    while let Ok(r) = r_chan.recv() {
        display.print_result(r);
    }
}

/// Main entry point.
fn main() {
    let mut opts = Opts::from_cmdline();
    let colors = opts.colors.take().unwrap();  // guaranteed to be Some()

    // determine which display mode we are using
    if opts.only_count {
        run(&mut display::CountMode::new(colors), opts);
    } else if opts.only_files == Some(true) {
        run(&mut display::FilesOnlyMode::new(colors, true), opts);
    } else if opts.only_files == Some(false) {
        run(&mut display::FilesOnlyMode::new(colors, false), opts);
    } else if opts.ackmate_format {
        run(&mut display::AckMateMode::new(), opts);
    } else if opts.vimgrep_format {
        run(&mut display::VimGrepMode, opts);
    } else {
        run(&mut display::DefaultMode::new(colors, opts.show_break, opts.show_heading), opts);
    }
}
<commit_msg>Use a sync channel between search and print.<commit_after>// ---------------------------------------------------------------------------------------
// Ruthenium, an ack-like searcher, (c) 2015 Georg Brandl.
// Licensed under the MIT license.
// ---------------------------------------------------------------------------------------

#[macro_use]
extern crate clap;
extern crate libc;
extern crate regex_dfa;
extern crate walkdir;
extern crate memmap;
extern crate scoped_threadpool;
extern crate num_cpus;
extern crate glob;

mod search;
mod ignore;
mod display;
mod options;

use std::cmp::max;
use std::sync::mpsc::{sync_channel, SyncSender};
use std::thread;
use memmap::{Mmap, Protection};
use scoped_threadpool::Pool;
use walkdir::WalkDirIterator;

use display::DisplayMode;
use search::FileResult;
use options::Opts;

/// Walk a directory (given in Opts) and check all found files.
///
/// The channel is used to send result structs to the main thread, which gives
/// them to the DisplayMode for output.
///
/// The thread of this function only does the directory walking, it spawns a
/// number of worker threads in a pool to grep individual files.
fn walk(chan: SyncSender<FileResult>, opts: &Opts) {
    // thread pool for individual file grep worker threads
    let mut pool = Pool::new(max(opts.workers - 1, 1));
    // create the regex object
    let regex = search::create_rx(&opts);

    let walker = walkdir::WalkDir::new(&opts.path)
        .follow_links(opts.follow_links)
        .max_depth(opts.depth);
    pool.scoped(|scope| {
        let rx = &regex;  // borrow for closures
        // stack of directories being walked, maintained in the filter closure
        let mut parent_stack: Vec<::std::path::PathBuf> = Vec::new();
        // stack of Ignore structs per directory in parent_stack, they accumulate
        // XXX: add global ignores from cmdline and a config file here
        let mut ignore_stack = Vec::new();
        let walker = walker.into_iter().filter_entry(|entry| {
            // remove parents from stack that are not applicable anymore
            let new_parent = entry.path().parent().unwrap();
            while !parent_stack.is_empty() &&
                parent_stack.last().unwrap().as_path() != new_parent
            {
                ignore_stack.pop();
                parent_stack.pop();
            }
            // weed out hidden files (this is separate from ignored)
            let path = entry.path();
            if let Some(fname) = path.file_name() {
                if !opts.do_hidden && fname.to_string_lossy().starts_with(".") {
                    return false;
                }
            }
            // weed out ignored files and directories (if we return false here for
            // directories, the contents are pruned from the iterator)
            if opts.check_ignores && ignore::match_patterns(path, &ignore_stack) {
                return false;
            }
            // we got a new dir? put it onto the stack
            if entry.file_type().is_dir() {
                let new_path = entry.path().to_path_buf();
                // read ignore patterns specific to this directory
                ignore_stack.push(ignore::read_patterns(&new_path));
                parent_stack.push(new_path);
            }
            true
        });
        for entry in walker {
            if let Ok(entry) = entry {
                // only touch normal files
                if !entry.file_type().is_file() {
                    continue;
                }
                // open and search file in one of the worker threads
                let ch = chan.clone();
                scope.execute(move || {
                    let path = entry.path();
                    if let Ok(map) = Mmap::open_path(path, Protection::Read) {
                        let buf = unsafe { map.as_slice() };
                        let res = search::search(rx, &opts, path, buf);
                        ch.send(res).unwrap();
                    }
                });
            }
        }
    });
}

/// Run the main action.  This is separated from `main` so that it can get a generic
/// DisplayMode argument.
///
/// Spawns the walker thread and prints the results.
fn run<D: DisplayMode>(display: &mut D, opts: Opts) {
    let (w_chan, r_chan) = sync_channel(2 * opts.workers as usize);
    thread::spawn(move || {
        walk(w_chan, &opts);
    });
    while let Ok(r) = r_chan.recv() {
        display.print_result(r);
    }
}

/// Main entry point.
fn main() {
    let mut opts = Opts::from_cmdline();
    let colors = opts.colors.take().unwrap();  // guaranteed to be Some()

    // determine which display mode we are using
    if opts.only_count {
        run(&mut display::CountMode::new(colors), opts);
    } else if opts.only_files == Some(true) {
        run(&mut display::FilesOnlyMode::new(colors, true), opts);
    } else if opts.only_files == Some(false) {
        run(&mut display::FilesOnlyMode::new(colors, false), opts);
    } else if opts.ackmate_format {
        run(&mut display::AckMateMode::new(), opts);
    } else if opts.vimgrep_format {
        run(&mut display::VimGrepMode, opts);
    } else {
        run(&mut display::DefaultMode::new(colors, opts.show_break, opts.show_heading), opts);
    }
}
<|endoftext|>


<commit_before>
extern crate iron;
extern crate router;
extern crate params;
extern crate hyper;

use std::process::Command;
use std::path::Path;

use iron::prelude::*;
use router::{Router};
use iron::status;
use iron::{BeforeMiddleware};

mod md5sum;

use md5sum::md5sum;

#[macro_use]
mod param_rules;

use param_rules::RequiredParam;

fn submit_form_file(req: &mut Request) -> IronResult<Response> {

  use std::fs::{rename,File};

  let passed_md5sum = &String::get_param_value(req, "md5sum").unwrap();
  let file_param = params::File::get_param_value(req, "filename").unwrap();

  let file_path = format!("{}.ods" , file_param.path().display());

  macro_rules! status_from_io_err {
    ($why:expr) => (

      match $why.kind() {
        std::io::ErrorKind::NotFound => status::NotFound,
        std::io::ErrorKind::PermissionDenied => status::Forbidden,
        _ => status::InternalServerError,
      }

    )
  }

  match rename(&file_param.path(), &file_path) {
    Err(why) => {
      let status = status_from_io_err!(why);
      Ok(Response::with((status, format!("failed to elaborate the received file: {}", why))))
    },
    Ok(_) => {
      println!("elaborating the file {}", file_path);

      match File::open(&file_path) {
        Err(why) => {
          let status = status_from_io_err!(why);
          Ok(Response::with((status, format!("failed to opening the received file: {}", why))))
        },
        Ok(ref mut file) => {
          let calculated_md5sum = &md5sum(file);
          if calculated_md5sum != passed_md5sum {
            let msg = format!(
              "the md5sum '{}' calculate for the file {} doesn't correspond to the parameter '{}'",
              calculated_md5sum, file_path, passed_md5sum
            );
            return Ok(Response::with((status::PreconditionRequired, msg)))
          }

          // it seems good
          let res = Command::new("timeout")
          .arg("--kill-after")
          .arg("10s")
          .arg("1m")

          // ----------------------- time it
          .arg("time")
          .arg("-v")
          .arg("-a")
          .arg("-o")
          .arg(format!("{}",file_param.path().parent().unwrap().join("time.log").display()))

          // ----------------------- convert
          .arg("libreoffice")
          .arg("--headless")
          .arg("--convert-to")
          .arg("pdf:writer_pdf_Export")
          .arg("--outdir")
          .arg(format!("{}",file_param.path().parent().unwrap().display()))
          .arg(file_path)
          .status().unwrap_or_else(|e| {
            println!("failed to execute process: {}", e);
            panic!("failed to execute process: {}", e);
          });

          println!("process exited with: {}", res);

          let ref file_path = format!("{}.pdf" , file_param.path().display());
          println!("file_path: {}", file_path);
          Ok(Response::with((status::Ok, Path::new(file_path))))
        }
      }
    }
  }

}

require_param!(RequireMd5sumParam, "md5sum", String);
require_param!(RequireFileParam, "filename", params::File);

mod logger;

use logger::Logger;
use iron::{AroundMiddleware};
fn start_server() {
   let mut router = Router::new();
   let mut chain_form_file = Chain::new(submit_form_file);

   chain_form_file.link_before(RequireMd5sumParam);
   chain_form_file.link_before(RequireFileParam);

   router.post("/openact", Logger::default().around(Box::new(chain_form_file)));

   println!("started server at http://localhost:3000/");
   Iron::new(router).http("localhost:3000").unwrap();
}

#[cfg(test)]
mod tests {

    use std::fs::File;
    use super::md5sum;

#[test]
    fn md5sum_of_file() {
        static FP : &'static str = "/home/costa/pkg/lav/regione/attiweb/attività/20150107/definizione procedura di riavvio/Procedure_Riavvio_omnia.odt";

        let mut odt = match File::open(FP) {
            Err(why) => panic!("Cannot open the test file: {}", why),
            Ok(file) => file,
        };

        assert_eq!(md5sum(&mut odt), "a381cbe043c38a94af0983ffa934f338");
    }

    #[test]
    fn simple_get() {
        use hyper::Client;
        use hyper::header::Connection;
        use std::io::Read;
        use super::start_server;

        // start_server();

        // Create a client.
        let client = Client::new();
        //
        // Creating an outgoing request.
        let mut res = client.get("http://localhost:3000/openact")
            // set a header
            .header(Connection::close())
            // let 'er go!
            .send().unwrap();

        // Read the Response.
        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        println!("Response: {}", body);
        assert_eq!(body, "Hello World");
    }

}

fn main() {
    println!("Hello, world!");
    start_server();
}
<commit_msg>todo: build tests<commit_after>
extern crate iron;
extern crate router;
extern crate params;
extern crate hyper;

use std::process::Command;
use std::path::Path;

use iron::prelude::*;
use router::{Router};
use iron::status;
use iron::{BeforeMiddleware};

mod md5sum;

use md5sum::md5sum;

#[macro_use]
mod param_rules;

use param_rules::RequiredParam;

fn submit_form_file(req: &mut Request) -> IronResult<Response> {

  use std::fs::{rename,File};

  let passed_md5sum = &String::get_param_value(req, "md5sum").unwrap();
  let file_param = params::File::get_param_value(req, "filename").unwrap();

  let file_path = format!("{}.ods" , file_param.path().display());

  macro_rules! status_from_io_err {
    ($why:expr) => (

      match $why.kind() {
        std::io::ErrorKind::NotFound => status::NotFound,
        std::io::ErrorKind::PermissionDenied => status::Forbidden,
        _ => status::InternalServerError,
      }

    )
  }

  match rename(&file_param.path(), &file_path) {
    Err(why) => {
      let status = status_from_io_err!(why);
      Ok(Response::with((status, format!("failed to elaborate the received file: {}", why))))
    },
    Ok(_) => {
      println!("elaborating the file {}", file_path);

      match File::open(&file_path) {
        Err(why) => {
          let status = status_from_io_err!(why);
          Ok(Response::with((status, format!("failed to opening the received file: {}", why))))
        },
        Ok(ref mut file) => {
          let calculated_md5sum = &md5sum(file);
          if calculated_md5sum != passed_md5sum {
            let msg = format!(
              "the md5sum '{}' calculate for the file {} doesn't correspond to the parameter '{}'",
              calculated_md5sum, file_path, passed_md5sum
            );
            return Ok(Response::with((status::PreconditionRequired, msg)))
          }

          // it seems good
          let res = Command::new("timeout")
          .arg("--kill-after")
          .arg("10s")
          .arg("1m")

          // ----------------------- time it
          .arg("time")
          .arg("-v")
          .arg("-a")
          .arg("-o")
          .arg(format!("{}",file_param.path().parent().unwrap().join("time.log").display()))

          // ----------------------- convert
          .arg("libreoffice")
          .arg("--headless")
          .arg("--convert-to")
          .arg("pdf:writer_pdf_Export")
          .arg("--outdir")
          .arg(format!("{}",file_param.path().parent().unwrap().display()))
          .arg(file_path)
          .status().unwrap_or_else(|e| {
            println!("failed to execute process: {}", e);
            panic!("failed to execute process: {}", e);
          });

          println!("process exited with: {}", res);

          let ref file_path = format!("{}.pdf" , file_param.path().display());
          println!("file_path: {}", file_path);
          Ok(Response::with((status::Ok, Path::new(file_path))))
        }
      }
    }
  }

}

require_param!(RequireMd5sumParam, "md5sum", String);
require_param!(RequireFileParam, "filename", params::File);

mod logger;

use logger::Logger;
use iron::{AroundMiddleware};
fn start_server() {
   let mut router = Router::new();
   let mut chain_form_file = Chain::new(submit_form_file);

   chain_form_file.link_before(RequireMd5sumParam);
   chain_form_file.link_before(RequireFileParam);

   router.post("/openact", Logger::default().around(Box::new(chain_form_file)));

   println!("started server at http://localhost:3000/");
   Iron::new(router).http("localhost:3000").unwrap();
}

fn main() {
    println!("Hello, world!");
    start_server();
}
<|endoftext|>


<commit_before>extern crate crypto;
extern crate base64;
extern crate byteorder;
extern crate docopt;
extern crate rustc_serialize;
extern crate rpassword;
extern crate ring;
extern crate untrusted;
extern crate failure;

use std::process;
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::{OpenOptions, File};

use ring::rand::{SecureRandom, SystemRandom};
use ring::signature::Ed25519KeyPair;
use ring::digest;
use crypto::bcrypt_pbkdf::bcrypt_pbkdf;

use docopt::Docopt;

mod structs;
mod errors;

use structs::*;
use errors::*;

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

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

Options:
  -h --help     Show this screen.
  -c <comment>  Specify the comment to be added during key generation.
  -e            When signing, embed the message after the signature. When verifying extract the message from
                the signature.
  -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.
  -n            Do not ask for a passphrase during key generation. Otherwise, signify will prompt the user for a
                passphrase to protect the secret key.
  -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_e: bool,

    flag_p: String,
    flag_s: String,
    flag_m: String,
    flag_n: bool,
}

fn write_base64_file(file: &mut File, comment: &str, buf: &[u8]) -> Result<()> {
    write!(file, "{}", COMMENTHDR)?;
    write!(file, "{}\n", comment)?;
    let out = base64::encode(buf);
    write!(file, "{}\n", out)?;

    Ok(())
}

fn read_base64_file<R: Read>(file_display: &str, reader: &mut BufReader<R>) -> Result<Vec<u8>> {
    let mut comment_line = String::new();
    let len = reader.read_line(&mut comment_line)?;

    if len == 0 || len < COMMENTHDRLEN || !comment_line.starts_with(COMMENTHDR) {
        return Err(err_msg(format!("invalid comment in {}; must start with '{}'", file_display, COMMENTHDR)));
    }

    if &comment_line[len-1..len] != "\n" {
        return Err(err_msg(format!("missing new line after comment in {}", file_display)));
    }

    if len > COMMENTHDRLEN + COMMENTMAXLEN {
        return Err(err_msg("comment too long"));
    }

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

    if len == 0 {
        return Err(err_msg(format!("missing line in {}", file_display)));
    }

    if &base64_line[len-1..len] != "\n" {
        return Err(err_msg(format!("missing new line after comment in {}", file_display)));
    }

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

    let data = base64::decode(base64_line)?;

    if &data[0..2] != PKGALG {
        return Err(err_msg(format!("unsupported file {}", file_display)));
    }

    Ok(data)
}

fn verify(pubkey_path: String, msg_path: String, signature_path: Option<String>, embed: bool) -> Result<()> {
    // TODO: Better error message?

    let pubkey_file = File::open(&pubkey_path)?;
    let mut pubkey = BufReader::new(pubkey_file);
    let serialized_pkey = read_base64_file(&pubkey_path, &mut pubkey)?;
    let pkey = PublicKey::from_buf(&serialized_pkey)?;

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

    let signature_file = File::open(&signature_path)?;
    let mut sig_data = BufReader::new(signature_file);

    // TODO: Better error message?
    let serialized_signature = read_base64_file(&signature_path, &mut sig_data)?;
    let signature = Signature::from_buf(&serialized_signature)?;

    let mut msg = vec![];

    if embed {
        sig_data.read_to_end(&mut msg)?;
    } else {
        let mut msgfile = File::open(&msg_path)?;
        msgfile.read_to_end(&mut msg)?;
    }

    if signature.keynum != pkey.keynum {
        return Err(err_msg("signature verification failed: checked against wrong key"));
    }

    if signature.verify(&msg, &pkey) {
        println!("Signature Verified");
        Ok(())
    } else {
        Err(err_msg("signature verification failed"))
    }
}

fn sign(seckey_path: String, msg_path: String, signature_path: Option<String>, embed: bool) -> Result<()> {
    let seckey_file = File::open(&seckey_path)?;
    let mut seckey = BufReader::new(seckey_file);

    let serialized_skey = read_base64_file(&seckey_path, &mut seckey)?;
    let mut skey = PrivateKey::from_buf(&serialized_skey)?;

    let rounds = skey.kdfrounds;
    let xorkey = kdf(&skey.salt, rounds, false, SECRETBYTES)?;

    for (prv, xor) in skey.seckey.iter_mut().zip(xorkey.iter()) {
        *prv = *prv ^ xor;
    }
    let skey = skey;

    let mut msgfile = File::open(&msg_path)?;
    let mut msg = vec![];
    msgfile.read_to_end(&mut msg)?;

    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)?;

    let sig_comment = "signature from signify secret key";

    let mut file = OpenOptions::new().write(true).create_new(true).open(&signature_path)?;
    write_base64_file(&mut file, sig_comment, &out)?;

    if embed {
        file.write(&msg)?;
    }

    Ok(())
}

fn read_password(prompt: &str) -> Result<String> {
    let mut stdout = std::io::stdout();
    stdout.write_all(prompt.as_bytes())?;
    stdout.flush()?;

    Ok(rpassword::read_password()?)
}

fn kdf(salt: &[u8], rounds: u32, confirm: bool, keylen: usize) -> Result<Vec<u8>> {
    let mut result = vec![0; keylen];
    if rounds == 0 {
        return Ok(result);
    }

    let passphrase = read_password("passphrase: ")?;

    if confirm {
        let confirm_passphrase = read_password("confirm passphrase: ")?;

        if passphrase != confirm_passphrase {
            return Err(err_msg("passwords don't match"));
        }
    }

    bcrypt_pbkdf(passphrase.as_bytes(), salt, rounds, &mut result);
    Ok(result)
}

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

    let mut keynum = [0; KEYNUMLEN];
    SystemRandom.fill(&mut keynum)?;

    let pkcs = Ed25519KeyPair::generate_pkcs8(&SystemRandom)?;
    // FIXME: WHAT A HACK
    // Offsets of both parts of the key are known, but this is baaad to extract
    let mut skey = [0; 32];
    skey.copy_from_slice(&pkcs[16..48]);
    let mut pkey = [0; 32];
    pkey.copy_from_slice(&pkcs[53..]);
    let pkey = pkey;

    let mut salt = [0; 16];
    SystemRandom.fill(&mut salt)?;

    let xorkey = kdf(&salt, kdfrounds, true, SECRETBYTES)?;

    for (prv, xor) in skey.iter_mut().zip(xorkey.iter()) {
        *prv = *prv ^ xor;
    }

    // signify stores the extended key as the private key,
    // that is the 32 byte of the secret key, followed by the 32 byte of the public key,
    // summing up to 64 byte.
    //
    //  *ring* separates them, so we need to stick them together again.
    let mut complete_key = [0; 64];
    complete_key[0..32].copy_from_slice(&skey[0..32]);
    complete_key[32..].copy_from_slice(&pkey);

    // Store private key
    let digest = digest::digest(&digest::SHA512, &complete_key);
    let mut checksum = [0; 8];
    checksum.copy_from_slice(&digest.as_ref()[0..8]);

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

    let mut out = vec![];
    private_key.write(&mut out)?;

    let priv_comment = format!("{} secret key", comment);
    let mut file = OpenOptions::new().write(true).create_new(true).open(&privkey_path)?;
    write_base64_file(&mut file, &priv_comment, &out)?;

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

    let mut out = vec![];
    public_key.write(&mut out)?;

    let pub_comment = format!("{} public key", comment);
    let mut file = OpenOptions::new().write(true).create_new(true).open(&pubkey_path)?;
    write_base64_file(&mut file, &pub_comment, &out)
}

fn human(res: Result<()>) {
    match res {
        Err(e) => {
            println!("error: {}", e.cause());

            process::exit(1);
        },
        Ok(()) => {}
    }
}

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

    if args.flag_V {
        human(verify(args.flag_p, args.flag_m, args.flag_x, args.flag_e));
    } else if args.flag_G {
        let rounds = if args.flag_n { 0 } else { 42 };
        human(generate(args.flag_p, args.flag_s, args.flag_c, rounds));
    } else if args.flag_S {
        human(sign(args.flag_s, args.flag_m, args.flag_x, args.flag_e));
    }
}<commit_msg>fix: New docopt uses serde now<commit_after>extern crate crypto;
extern crate base64;
extern crate byteorder;
extern crate docopt;
#[macro_use]
extern crate serde_derive;
extern crate rpassword;
extern crate ring;
extern crate untrusted;
extern crate failure;

use std::process;
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::{OpenOptions, File};

use ring::rand::{SecureRandom, SystemRandom};
use ring::signature::Ed25519KeyPair;
use ring::digest;
use crypto::bcrypt_pbkdf::bcrypt_pbkdf;

use docopt::Docopt;

mod structs;
mod errors;

use structs::*;
use errors::*;

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

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

Options:
  -h --help     Show this screen.
  -c <comment>  Specify the comment to be added during key generation.
  -e            When signing, embed the message after the signature. When verifying extract the message from
                the signature.
  -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.
  -n            Do not ask for a passphrase during key generation. Otherwise, signify will prompt the user for a
                passphrase to protect the secret key.
  -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, Deserialize)]
struct Args {
    flag_G: bool,
    flag_S: bool,
    flag_V: bool,

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

    flag_p: String,
    flag_s: String,
    flag_m: String,
    flag_n: bool,
}

fn write_base64_file(file: &mut File, comment: &str, buf: &[u8]) -> Result<()> {
    write!(file, "{}", COMMENTHDR)?;
    write!(file, "{}\n", comment)?;
    let out = base64::encode(buf);
    write!(file, "{}\n", out)?;

    Ok(())
}

fn read_base64_file<R: Read>(file_display: &str, reader: &mut BufReader<R>) -> Result<Vec<u8>> {
    let mut comment_line = String::new();
    let len = reader.read_line(&mut comment_line)?;

    if len == 0 || len < COMMENTHDRLEN || !comment_line.starts_with(COMMENTHDR) {
        return Err(err_msg(format!("invalid comment in {}; must start with '{}'", file_display, COMMENTHDR)));
    }

    if &comment_line[len-1..len] != "\n" {
        return Err(err_msg(format!("missing new line after comment in {}", file_display)));
    }

    if len > COMMENTHDRLEN + COMMENTMAXLEN {
        return Err(err_msg("comment too long"));
    }

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

    if len == 0 {
        return Err(err_msg(format!("missing line in {}", file_display)));
    }

    if &base64_line[len-1..len] != "\n" {
        return Err(err_msg(format!("missing new line after comment in {}", file_display)));
    }

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

    let data = base64::decode(base64_line)?;

    if &data[0..2] != PKGALG {
        return Err(err_msg(format!("unsupported file {}", file_display)));
    }

    Ok(data)
}

fn verify(pubkey_path: String, msg_path: String, signature_path: Option<String>, embed: bool) -> Result<()> {
    // TODO: Better error message?

    let pubkey_file = File::open(&pubkey_path)?;
    let mut pubkey = BufReader::new(pubkey_file);
    let serialized_pkey = read_base64_file(&pubkey_path, &mut pubkey)?;
    let pkey = PublicKey::from_buf(&serialized_pkey)?;

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

    let signature_file = File::open(&signature_path)?;
    let mut sig_data = BufReader::new(signature_file);

    // TODO: Better error message?
    let serialized_signature = read_base64_file(&signature_path, &mut sig_data)?;
    let signature = Signature::from_buf(&serialized_signature)?;

    let mut msg = vec![];

    if embed {
        sig_data.read_to_end(&mut msg)?;
    } else {
        let mut msgfile = File::open(&msg_path)?;
        msgfile.read_to_end(&mut msg)?;
    }

    if signature.keynum != pkey.keynum {
        return Err(err_msg("signature verification failed: checked against wrong key"));
    }

    if signature.verify(&msg, &pkey) {
        println!("Signature Verified");
        Ok(())
    } else {
        Err(err_msg("signature verification failed"))
    }
}

fn sign(seckey_path: String, msg_path: String, signature_path: Option<String>, embed: bool) -> Result<()> {
    let seckey_file = File::open(&seckey_path)?;
    let mut seckey = BufReader::new(seckey_file);

    let serialized_skey = read_base64_file(&seckey_path, &mut seckey)?;
    let mut skey = PrivateKey::from_buf(&serialized_skey)?;

    let rounds = skey.kdfrounds;
    let xorkey = kdf(&skey.salt, rounds, false, SECRETBYTES)?;

    for (prv, xor) in skey.seckey.iter_mut().zip(xorkey.iter()) {
        *prv = *prv ^ xor;
    }
    let skey = skey;

    let mut msgfile = File::open(&msg_path)?;
    let mut msg = vec![];
    msgfile.read_to_end(&mut msg)?;

    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)?;

    let sig_comment = "signature from signify secret key";

    let mut file = OpenOptions::new().write(true).create_new(true).open(&signature_path)?;
    write_base64_file(&mut file, sig_comment, &out)?;

    if embed {
        file.write(&msg)?;
    }

    Ok(())
}

fn read_password(prompt: &str) -> Result<String> {
    let mut stdout = std::io::stdout();
    stdout.write_all(prompt.as_bytes())?;
    stdout.flush()?;

    Ok(rpassword::read_password()?)
}

fn kdf(salt: &[u8], rounds: u32, confirm: bool, keylen: usize) -> Result<Vec<u8>> {
    let mut result = vec![0; keylen];
    if rounds == 0 {
        return Ok(result);
    }

    let passphrase = read_password("passphrase: ")?;

    if confirm {
        let confirm_passphrase = read_password("confirm passphrase: ")?;

        if passphrase != confirm_passphrase {
            return Err(err_msg("passwords don't match"));
        }
    }

    bcrypt_pbkdf(passphrase.as_bytes(), salt, rounds, &mut result);
    Ok(result)
}

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

    let mut keynum = [0; KEYNUMLEN];
    SystemRandom.fill(&mut keynum)?;

    let pkcs = Ed25519KeyPair::generate_pkcs8(&SystemRandom)?;
    // FIXME: WHAT A HACK
    // Offsets of both parts of the key are known, but this is baaad to extract
    let mut skey = [0; 32];
    skey.copy_from_slice(&pkcs[16..48]);
    let mut pkey = [0; 32];
    pkey.copy_from_slice(&pkcs[53..]);
    let pkey = pkey;

    let mut salt = [0; 16];
    SystemRandom.fill(&mut salt)?;

    let xorkey = kdf(&salt, kdfrounds, true, SECRETBYTES)?;

    for (prv, xor) in skey.iter_mut().zip(xorkey.iter()) {
        *prv = *prv ^ xor;
    }

    // signify stores the extended key as the private key,
    // that is the 32 byte of the secret key, followed by the 32 byte of the public key,
    // summing up to 64 byte.
    //
    //  *ring* separates them, so we need to stick them together again.
    let mut complete_key = [0; 64];
    complete_key[0..32].copy_from_slice(&skey[0..32]);
    complete_key[32..].copy_from_slice(&pkey);

    // Store private key
    let digest = digest::digest(&digest::SHA512, &complete_key);
    let mut checksum = [0; 8];
    checksum.copy_from_slice(&digest.as_ref()[0..8]);

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

    let mut out = vec![];
    private_key.write(&mut out)?;

    let priv_comment = format!("{} secret key", comment);
    let mut file = OpenOptions::new().write(true).create_new(true).open(&privkey_path)?;
    write_base64_file(&mut file, &priv_comment, &out)?;

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

    let mut out = vec![];
    public_key.write(&mut out)?;

    let pub_comment = format!("{} public key", comment);
    let mut file = OpenOptions::new().write(true).create_new(true).open(&pubkey_path)?;
    write_base64_file(&mut file, &pub_comment, &out)
}

fn human(res: Result<()>) {
    match res {
        Err(e) => {
            println!("error: {}", e.cause());

            process::exit(1);
        },
        Ok(()) => {}
    }
}

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

    if args.flag_V {
        human(verify(args.flag_p, args.flag_m, args.flag_x, args.flag_e));
    } else if args.flag_G {
        let rounds = if args.flag_n { 0 } else { 42 };
        human(generate(args.flag_p, args.flag_s, args.flag_c, rounds));
    } else if args.flag_S {
        human(sign(args.flag_s, args.flag_m, args.flag_x, args.flag_e));
    }
}
<|endoftext|>


<commit_before>extern crate tray_rust;

use std::vec::Vec;
use tray_rust::linalg;
use tray_rust::film;
use tray_rust::geometry;
use tray_rust::geometry::Geometry;
use tray_rust::sampler;
use tray_rust::sampler::{Sampler};

fn main() {
    let width = 800u;
    let height = 600u;

    let mut rt = film::RenderTarget::new(width, height);
    let camera = film::Camera::new(linalg::Transform::look_at(
        &linalg::Point::new(0.0, 0.0, -10.0), &linalg::Point::new(0.0, 0.0, 0.0),
        &linalg::Vector::new(0.0, 1.0, 0.0)), 40.0, rt.dimensions());
    let sphere = geometry::Sphere::new(1.5);
    let instance = geometry::Instance::new(&sphere,
        linalg::Transform::translate(&linalg::Vector::new(0.0, 2.0, 0.0)));

    let mut block_queue = sampler::BlockQueue::new((width as u32, height as u32), (8, 8));
    let mut sampler = sampler::Uniform::new(block_queue.block_dim());
    let mut sample_pos = Vec::with_capacity(sampler.max_spp());
    for b in block_queue {
        sampler.select_block(&b);
        while sampler.has_samples() {
            sampler.get_samples(&mut sample_pos);
            for px in sample_pos.iter() {
                let mut ray = camera.generate_ray(*px);
                match instance.intersect(&mut ray) {
                    Some(_) => rt.write(px.0, px.1, &film::Colorf::broadcast(1.0)),
                    None => rt.write(px.0, px.1, &film::Colorf::new(0.0, 0.0, 1.0)),
                }
            }
        }
    }
    film::write_ppm("out.ppm", width, height, rt.get_render().as_slice());
}

<commit_msg>Threaded test of block queue and multiple sender single receiver channel<commit_after>extern crate tray_rust;

use std::vec::Vec;
use std::sync::{Arc, TaskPool};
use std::io::timer;
use std::time::duration::Duration;
use tray_rust::linalg;
use tray_rust::film;
use tray_rust::geometry;
use tray_rust::geometry::Geometry;
use tray_rust::sampler;
use tray_rust::sampler::{Sampler};

/// Trial of how we might do the render target stuff.
/// Threads are each sent a send end of the channel that is
/// read from by the render target thread which then saves the
/// values recieved to the framebuffer
fn thread_work(tx: Sender<uint>, i: uint, queue: Arc<sampler::BlockQueue>) {
    for _ in queue.iter() {
        tx.send(i);
        // Pretend to do some work
        timer::sleep(Duration::milliseconds(50));
    }
}

/// Hand the workers their own send endpoints to communicate results back
/// to the main thread but drop the sender on the main thread so once
/// all threads finish the channel closes
fn spawn_workers(pool: &TaskPool, n: uint) -> Receiver<uint> {
    let (tx, rx) = channel();
    let block_queue = Arc::new(sampler::BlockQueue::new((10, 10), (2, 2)));
    for i in range(0, n) {
        let t = tx.clone();
        let q = block_queue.clone();
        // Can we just directly pass thread_work here? How would we send the args?
        pool.execute(move || {
            thread_work(t, i, q);
        });
    }
    rx
}

fn thread_test() {
    let n = 8;
    let pool = TaskPool::new(n);
    let rx = spawn_workers(&pool, n);
    for m in rx.iter() {
        println!("Message: {}", m);
    }
}

fn main() {
    thread_test();
    let width = 800u;
    let height = 600u;

    let mut rt = film::RenderTarget::new(width, height);
    let camera = film::Camera::new(linalg::Transform::look_at(
        &linalg::Point::new(0.0, 0.0, -10.0), &linalg::Point::new(0.0, 0.0, 0.0),
        &linalg::Vector::new(0.0, 1.0, 0.0)), 40.0, rt.dimensions());
    let sphere = geometry::Sphere::new(1.5);
    let instance = geometry::Instance::new(&sphere,
        linalg::Transform::translate(&linalg::Vector::new(0.0, 2.0, 0.0)));

    let block_queue = sampler::BlockQueue::new((width as u32, height as u32), (8, 8));
    let mut sampler = sampler::Uniform::new(block_queue.block_dim());
    let mut sample_pos = Vec::with_capacity(sampler.max_spp());
    for b in block_queue.iter() {
        sampler.select_block(&b);
        while sampler.has_samples() {
            sampler.get_samples(&mut sample_pos);
            for px in sample_pos.iter() {
                let mut ray = camera.generate_ray(*px);
                match instance.intersect(&mut ray) {
                    Some(_) => rt.write(px.0, px.1, &film::Colorf::broadcast(1.0)),
                    None => rt.write(px.0, px.1, &film::Colorf::new(0.0, 0.0, 1.0)),
                }
            }
        }
    }
    film::write_ppm("out.ppm", width, height, rt.get_render().as_slice());
}

<|endoftext|>


<commit_before>extern crate device_tree_source;
#[macro_use]
extern crate clap;
extern crate mktemp;

mod change_tracker;

use std::process::Command;
use std::path::{Path, PathBuf};
use std::io::{self, BufRead, Write};
use std::iter::Iterator;
use std::fmt::{self, Display, Formatter};
// use std::fs::File;

use mktemp::Temp;

use device_tree_source::parser::{ParseResult, parse_dt};
use device_tree_source::tree::Offset;

use device_tree_source::include::{IncludeBounds, IncludeMethod, IncludeError, BoundsError,
                                  include_files, get_bounds_containing_offset};

use change_tracker::LabelStore;

// General idea:
//  Run CPP
//  Parse file for DTS includes and replace with include contents
//  Find byte starts/ends for each file
//  Parse file to create device tree
//  create mapping of objects to byte offset starting points
//  - not perfect with offsets stored in object, but it will do
//  create mapping of full paths to objects
//  create mapping of labels to full paths
//  Parse device tree to create changes
//  Use mapping and file starts to pair changes to file byte offsets
//  Turn file byte offsets to file lines/cols
//  TODO: ???
//  TODO: Profit!
//  Oh, and somehow display the damn information
fn main() {
    let matches = clap_app!(dts_viewer =>
            (version: crate_version!())
            (author: "Gabriel s. <ga29smith@gmail.com>")
            (@arg file: +required "DTS file to parse")
            (@arg no_defaults: -n --no_defaults "Disable default includes. \
                An 'include' directory, if it exists, is automatically included")
            (@arg include: -I ... +takes_value "Additional files to pass to CPP as an include")
        )
        .get_matches();

    let file_name = matches.value_of("file").unwrap();
    let parent = Path::new(file_name).parent().expect("Could not get parent directory of file");

    let cpp_temp_out = Temp::new_file().expect("Could not create temp file");

    let mut cpp_command = Command::new("gcc");
    cpp_command.args(&["-E", "-nostdinc"])
        .args(&["-undef", "-D__DTS__", "-x", "assembler-with-cpp"])
        .args(&["-o", cpp_temp_out.as_ref().to_str().unwrap()])
        .arg(&file_name);

    if !matches.is_present("no_defaults") {
        cpp_command.args(&["-I", parent.to_str().unwrap()]);
        let include_dir = parent.join("include/");
        if include_dir.is_dir() {
            cpp_command.args(&["-I", include_dir.to_str().unwrap()]);
        }
    }

    if let Some(includes) = matches.values_of("include") {
        for include in includes {
            let include_dir = parent.join(include);
            if include_dir.is_dir() {
                cpp_command.args(&["-I", include_dir.to_str().unwrap()]);
            }
        }
    }

    let include_output = cpp_command.output().expect("Failed to start CPP");
    let cpp_stderr = String::from_utf8_lossy(&include_output.stderr);
    if !include_output.status.success() {
        println!("Failed to execute CPP. Error message is below.");
        print!("{}", cpp_stderr);
        return;
    }

    let (buffer, bounds) = match include_files(&cpp_temp_out) {
        Ok(x) => x,
        Err(e) => {
            match e {
                IncludeError::IOError(err, path) => {
                    print!("IO error: {}", err);
                    if let Some(path) = path {
                        println!(" {}", path.display());
                    }
                }
                IncludeError::LinemarkerInDtsi(path) =>
                    println!("Extraneous linemarker found in DT include: {}",
                             path.to_string_lossy()),
                IncludeError::ParseError(_) =>
                    println!("Failed to convert line to byte offset for bounds tracking."),
                IncludeError::NoBoundReturned(path) =>
                    println!("No bounds returned after parsing file: {}", path.to_string_lossy()),
            }
            return;
        }
    };

    // println!("{:#?}", bounds);
    // {
    //     let mut total_dts_dump = File::create("total_dts_dump.dts").unwrap();
    //     total_dts_dump.write_all(&buffer).unwrap()
    // }

    let include_tree = IncludeTree::bounds_to_tree(&bounds);
    if let Some(tree) = include_tree {
        println!("{}", tree);
    } else {
        println!("-- Could not constuct include tree from bounds!");
    }

    let (boot_info, amends) = match parse_dt(&buffer) {
        Ok(ParseResult::Complete(boot_info, amends)) => (boot_info, amends),
        Ok(ParseResult::RemainingInput(boot_info, amends, rem)) => {
            println!("Input remaining after parsing:\n\"{}\"", String::from_utf8_lossy(rem));
            (boot_info, amends)
        }
        Err(err) => {
            println!("{:?}", err);
            return;
        }
    };

    // TODO: perform secondary checks and jazz (only smooth) - issue 9

    let mut store = LabelStore::new();
    store.fill(&boot_info, &amends);

    loop {
        print!("Enter alias or path: ");
        io::stdout().flush().expect("Error flushing stdout");

        let mut line = String::new();
        let stdin = io::stdin();
        stdin.lock().read_line(&mut line).expect("Error reading from stdin");
        let line = line.trim();

        if line.is_empty() {
            break;
        }

        let path = if line.starts_with('/') {
            Some(PathBuf::from(line))
        } else {
            let line = if line.starts_with('&') {
                &line[1..]
            } else {
                line
            };
            // TODO:
            // if label covers multiple paths (after saving old aliases is implemented)
            //     ask user which one they want as well as why this is being asked
            // show all changes along the way
            match store.path_from_label(line) {
                Some(path) => {
                    println!("Path: {}", path.to_string_lossy());
                    Some(path.to_owned())
                }
                None => {
                    println!("Label points to no path");
                    None
                }
            }
        };

        if let Some(path) = path {
            match store.changes_from_path(&path) {
                Some(changes) => {
                    for change in changes {
                        let offset = change.get_offset();
                        // println!("Start offset: {}", offset);
                        match get_bounds_containing_offset(&bounds, offset) {
                            Ok(bound) => {
                                print!("File: {}", bound.child_path().to_string_lossy());

                                match bound.file_line_from_global(&buffer, offset) {
                                    Ok((line, col)) => {
                                        println!(", Line: {}, Column: {}", line, col)
                                    }
                                    Err(err) => match err {
                                        BoundsError::ParseError(_) =>
                                            println!("Offset ({}) could not be converted to line.",
                                                     offset),
                                        BoundsError::IOError(..) =>
                                            println!("Failed to open file: {}",
                                                     bound.child_path().to_string_lossy()),
                                        BoundsError::NotWithinBounds =>
                                            println!("File offset ({}) was supposed to be in\
                                                         bound. {:?}",
                                                     offset,
                                                     bound),
                                    }
                                }
                            }
                            Err(_) => println!("-- Could not find file for offset {}", offset),
                        }
                        println!("{}\n", change);
                    }
                }
                None => println!("Nothing at path"),
            }
        }
    }
}

#[derive(Debug)]
struct IncludeTree {
    path: PathBuf,
    method: IncludeMethod,
    includes: Vec<IncludeTree>,
}

impl IncludeTree {
    fn bounds_to_tree(bounds: &[IncludeBounds]) -> Option<IncludeTree> {
        if let Some(first) = bounds.first() {
            let mut tree = IncludeTree {
                path: first.child_path().to_owned(),
                includes: Vec::new(),
                method: first.include_method().clone(),
            };

            //TODO: we don't really need the filter, benchmark speed w/wo
            for sub_bounds in bounds.split(|b| b.child_path() == first.child_path())
                                    .filter(|s| !s.is_empty()) {
                if let Some(sub_tree) = Self::bounds_to_tree(sub_bounds) {
                    tree.includes.push(sub_tree);
                }
            }

            Some(tree)
        } else {
            None
        }
    }

    fn write(&self, f: &mut Formatter, prefix: &str) -> fmt::Result {
        let mut next_prefix = prefix.to_owned();
        next_prefix.push_str(" |-");

        let method = match self.method {
            IncludeMethod::CPP => "CPP",
            IncludeMethod::DTS => "DTS",
        };
        writeln!(f, "{} {}: {}", prefix, self.path.to_string_lossy(), method)?;
        for t in &self.includes {
            t.write(f, &next_prefix)?;
        }

        Ok(())
    }
}

impl Display for IncludeTree {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.write(f, "")
    }
}
<commit_msg>Random cleanup of main<commit_after>extern crate device_tree_source;
#[macro_use]
extern crate clap;
extern crate mktemp;

mod change_tracker;

use std::process::Command;
use std::path::{Path, PathBuf};
use std::io::{self, BufRead, Write};
use std::iter::Iterator;
use std::fmt::{self, Display, Formatter};

use mktemp::Temp;

use device_tree_source::parser::{ParseResult, parse_dt};
use device_tree_source::tree::Offset;
use device_tree_source::include::{IncludeBounds, IncludeMethod, IncludeError, BoundsError,
                                  include_files, get_bounds_containing_offset};

use change_tracker::LabelStore;

// General idea:
//  Run CPP
//  Parse file for DTS includes and replace with include contents
//  Find byte starts/ends for each file
//  Parse file to create device tree
//  create mapping of objects to byte offset starting points
//  - not perfect with offsets stored in object, but it will do
//  create mapping of full paths to objects
//  create mapping of labels to full paths
//  Parse device tree to create changes
//  Use mapping and file starts to pair changes to file byte offsets
//  Turn file byte offsets to file lines/cols
//  TODO: ???
//  TODO: Profit!
//  Oh, and somehow display the damn information
fn main() {
    let matches = clap_app!(dts_viewer =>
            (version: crate_version!())
            (author: "Gabriel s. <ga29smith@gmail.com>")
            (@arg file: +required "DTS file to parse")
            (@arg no_defaults: -n --no_defaults "Disable default includes. \
                An 'include' directory, if it exists, is automatically included")
            (@arg include: -I ... +takes_value "Additional files to pass to CPP as an include")
        )
        .get_matches();

    let file_name = matches.value_of("file").unwrap();
    let parent = Path::new(file_name).parent().expect("Could not get parent directory of file");

    let mut cpp_temp_out = Temp::new_file().expect("Could not create temp file");

    let mut cpp_command = Command::new("gcc");
    cpp_command.args(&["-E", "-nostdinc"])
        .args(&["-undef", "-D__DTS__", "-x", "assembler-with-cpp"])
        .args(&["-o", cpp_temp_out.as_ref().to_str().unwrap()])
        .arg(&file_name);

    if !matches.is_present("no_defaults") {
        cpp_command.args(&["-I", parent.to_str().unwrap()]);
        let include_dir = parent.join("include/");
        if include_dir.is_dir() {
            cpp_command.args(&["-I", include_dir.to_str().unwrap()]);
        }
    }

    if let Some(includes) = matches.values_of("include") {
        for include in includes {
            let include_dir = parent.join(include);
            if include_dir.is_dir() {
                cpp_command.args(&["-I", include_dir.to_str().unwrap()]);
            }
        }
    }

    // println!("{:?}", cpp_command);

    let include_output = cpp_command.output().expect("Failed to start CPP");
    if !include_output.status.success() {
        // Done to prevent a panic as the file will not have been written to
        cpp_temp_out.release();
        println!("Failed to execute CPP. Error message is below.");
        print!("{}", String::from_utf8_lossy(&include_output.stderr));
        return;
    }

    let (buffer, bounds) = match include_files(&cpp_temp_out) {
        Ok(x) => x,
        Err(e) => {
            match e {
                IncludeError::IOError(err, path) => {
                    print!("IO error: {}", err);
                    if let Some(path) = path {
                        println!(" {}", path.display());
                    }
                }
                IncludeError::LinemarkerInDtsi(path) =>
                    println!("Extraneous linemarker found in DT include: {}",
                             path.to_string_lossy()),
                IncludeError::ParseError(_) =>
                    println!("Failed to convert line to byte offset for bounds tracking."),
                IncludeError::NoBoundReturned(path) =>
                    println!("No bounds returned after parsing file: {}", path.to_string_lossy()),
            }
            return;
        }
    };

    // println!("{:#?}", bounds);
    // {
    //     use std::fs::File;
    //     let mut total_dts_dump = File::create("total_dts_dump.dts").unwrap();
    //     total_dts_dump.write_all(&buffer).unwrap()
    // }

    let include_tree = IncludeTree::bounds_to_tree(&bounds);
    if let Some(tree) = include_tree {
        println!("{}", tree);
    } else {
        println!("-- Could not constuct include tree from bounds!");
    }

    let (boot_info, amends) = match parse_dt(&buffer) {
        Ok(ParseResult::Complete(boot_info, amends)) => (boot_info, amends),
        Ok(ParseResult::RemainingInput(boot_info, amends, rem)) => {
            println!("Input remaining after parsing:\n\"{}\"", String::from_utf8_lossy(rem));
            (boot_info, amends)
        }
        Err(err) => {
            println!("{:?}", err);
            return;
        }
    };

    // TODO: perform secondary checks and jazz (only smooth) - issue 9

    let mut store = LabelStore::new();
    store.fill(&boot_info, &amends);

    loop {
        print!("Enter alias or path: ");
        io::stdout().flush().expect("Error flushing stdout");

        let mut line = String::new();
        let stdin = io::stdin();
        stdin.lock().read_line(&mut line).expect("Error reading from stdin");
        let line = line.trim();

        if line.is_empty() {
            break;
        }

        let path = if line.starts_with('/') {
            Some(PathBuf::from(line))
        } else {
            let line = if line.starts_with('&') {
                &line[1..]
            } else {
                line
            };
            // TODO:
            // if label covers multiple paths (after saving old aliases is implemented)
            //     ask user which one they want as well as why this is being asked
            // show all changes along the way
            match store.path_from_label(line) {
                Some(path) => {
                    println!("Path: {}", path.to_string_lossy());
                    Some(path.to_owned())
                }
                None => {
                    println!("Label points to no path");
                    None
                }
            }
        };

        if let Some(path) = path {
            match store.changes_from_path(&path) {
                Some(changes) => {
                    for change in changes {
                        let offset = change.get_offset();
                        // println!("Start offset: {}", offset);
                        match get_bounds_containing_offset(&bounds, offset) {
                            Ok(bound) => {
                                print!("File: {}", bound.child_path().to_string_lossy());

                                match bound.file_line_from_global(&buffer, offset) {
                                    Ok((line, col)) => {
                                        println!(", Line: {}, Column: {}", line, col)
                                    }
                                    Err(err) => match err {
                                        BoundsError::ParseError(_) =>
                                            println!("Offset ({}) could not be converted to line.",
                                                     offset),
                                        BoundsError::IOError(..) =>
                                            println!("Failed to open file: {}",
                                                     bound.child_path().to_string_lossy()),
                                        BoundsError::NotWithinBounds =>
                                            println!("File offset ({}) was supposed to be in\
                                                         bound. {:?}",
                                                     offset,
                                                     bound),
                                    }
                                }
                            }
                            Err(_) => println!("-- Could not find file for offset {}", offset),
                        }
                        println!("{}\n", change);
                    }
                }
                None => println!("Nothing at path"),
            }
        }
    }
}

#[derive(Debug)]
struct IncludeTree {
    path: PathBuf,
    method: IncludeMethod,
    includes: Vec<IncludeTree>,
}

impl IncludeTree {
    fn bounds_to_tree(bounds: &[IncludeBounds]) -> Option<IncludeTree> {
        if let Some(first) = bounds.first() {
            let mut tree = IncludeTree {
                path: first.child_path().to_owned(),
                includes: Vec::new(),
                method: first.include_method().clone(),
            };

            //TODO: we don't really need the filter, benchmark speed w/wo
            for sub_bounds in bounds.split(|b| b.child_path() == first.child_path())
                                    .filter(|s| !s.is_empty()) {
                if let Some(sub_tree) = Self::bounds_to_tree(sub_bounds) {
                    tree.includes.push(sub_tree);
                }
            }

            Some(tree)
        } else {
            None
        }
    }

    fn write(&self, f: &mut Formatter, prefix: &str) -> fmt::Result {
        let mut next_prefix = prefix.to_owned();
        next_prefix.push_str(" |-");

        let method = match self.method {
            IncludeMethod::CPP => "CPP",
            IncludeMethod::DTS => "DTS",
        };
        writeln!(f, "{} {}: {}", prefix, self.path.to_string_lossy(), method)?;
        for t in &self.includes {
            t.write(f, &next_prefix)?;
        }

        Ok(())
    }
}

impl Display for IncludeTree {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.write(f, "")
    }
}
<|endoftext|>