<commit_before>#![feature(box_syntax)]

#[macro_use]
extern crate objc;

#[macro_use]
extern crate log;

extern crate simplelog;
extern crate libc;
extern crate cocoa;
extern crate objc_foundation;
extern crate open;

mod app;
mod window;
mod view;
mod servo;
mod platform;
mod commands;

use app::AppEvent;
use window::WindowEvent;
use view::ViewEvent;
use servo::ServoEvent;
use simplelog::{CombinedLogger, Config, LogLevel, LogLevelFilter, TermLogger, WriteLogger};
use std::fs::File;
use std::env::args;
use app::App;
use servo::{Servo, ServoUrl, FollowLinkPolicy};
use commands::{AppCommand, WindowCommand, CommandState};

fn main() {

    // FIXME: can we use NSLog instead of a file?
    let log_file = File::create("/tmp/servoshell.log").unwrap();
    let log_config = Config {
        time: None,
        level: Some(LogLevel::Info),
        target: Some(LogLevel::Info),
        location: Some(LogLevel::Info),
    };

    let _ = match TermLogger::new(LogLevelFilter::Info, log_config) {
        Some(logger) => CombinedLogger::init(vec![
            logger,
            WriteLogger::new(LogLevelFilter::Info, log_config, log_file)
        ]),
        None => WriteLogger::init(LogLevelFilter::Info, log_config, log_file)
    };

    info!("starting");

    platform::init();

    let app = App::load().unwrap();
    let (window, view) = app.create_window().unwrap();

    // Skip first argument (executable), and find the first
    // argument that doesn't start with `-`
    let url = args().skip(1).find(|arg| {
        !arg.starts_with("-")
    }).unwrap_or("http://servo.org".to_owned());

    Servo::configure(&url).unwrap();
    let servo = {
        let geometry = view.get_geometry();
        let riser = window.create_eventloop_riser();
        // let policy = FollowLinkPolicy::FollowOriginalDomain;
        let policy = FollowLinkPolicy::FollowAnyLink;
        Servo::new(geometry, riser, &url, policy)
    };

    info!("Servo version: {}", servo.version());

    window.set_command_state(WindowCommand::OpenLocation, CommandState::Enabled);
    window.set_command_state(WindowCommand::ZoomIn, CommandState::Enabled);
    window.set_command_state(WindowCommand::ZoomOut, CommandState::Enabled);
    window.set_command_state(WindowCommand::ZoomToActualSize, CommandState::Enabled);
    app.set_command_state(AppCommand::ClearHistory, CommandState::Enabled);

    let mut last_mouse_point = (0, 0);
    let mut last_mouse_down_point = (0, 0);
    let mut last_mouse_down_button: Option<view::MouseButton> = None;

    app.run(|| {

        // Loop until no events are available anymore.
        loop {

            let app_events = app.get_events();
            let win_events = window.get_events();
            let view_events = view.get_events();
            let servo_events = servo.get_events();

            if app_events.is_empty() &&
               win_events.is_empty() &&
               view_events.is_empty() &&
               servo_events.is_empty() {
                   break
            }

            // FIXME: it's really annoying we need this
            let mut force_sync = false;

            for event in app_events {
                match event {
                    AppEvent::DidFinishLaunching => {
                        // FIXME: does this work?
                    }
                    AppEvent::WillTerminate => {
                        // FIXME: does this work?
                    }
                    AppEvent::DidChangeScreenParameters => {
                        // FIXME: does this work?
                        servo.update_geometry(view.get_geometry());
                        view.update_drawable();
                    }
                    AppEvent::DoCommand(cmd) => {
                        match cmd {
                            AppCommand::ClearHistory => {
                                // FIXME
                            }
                        }
                    }
                }
            }

            for event in win_events {
                match event {
                    WindowEvent::EventLoopRised => {
                        force_sync = true;
                    }
                    WindowEvent::GeometryDidChange => {
                        servo.update_geometry(view.get_geometry());
                        view.update_drawable();
                    }
                    WindowEvent::DidEnterFullScreen => {
                        // FIXME
                    }
                    WindowEvent::DidExitFullScreen => {
                        // FIXME
                    }
                    WindowEvent::WillClose => {
                        // FIXME
                    }
                    WindowEvent::DoCommand(cmd) => {
                        match cmd {
                            WindowCommand::Stop => {
                                // FIXME
                            }
                            WindowCommand::Reload => {
                                servo.reload();
                            }
                            WindowCommand::NavigateBack => {
                                servo.go_back();
                            }
                            WindowCommand::NavigateForward => {
                                servo.go_forward();
                            }
                            WindowCommand::OpenLocation => {
                                window.focus_urlbar();
                            }
                            WindowCommand::ZoomIn => {
                                servo.zoom(1.1);
                            }
                            WindowCommand::ZoomOut => {
                                servo.zoom(1.0 / 1.1);
                            }
                            WindowCommand::ZoomToActualSize => {
                                servo.reset_zoom();
                            }
                            WindowCommand::Load(request) => {
                                let url = ServoUrl::parse(&request).or_else(|error| {
                                    // FIXME: weak
                                    if request.ends_with(".com") || request.ends_with(".org") || request.ends_with(".net") {
                                        ServoUrl::parse(&format!("http://{}", request))
                                    } else {
                                        Err(error)
                                    }
                                }).or_else(|_| {
                                    ServoUrl::parse(&format!("https://duckduckgo.com/html/?q={}", request))
                                });
                                match url {
                                    Ok(url) => {
                                        servo.load_url(url)
                                    },
                                    Err(err) => warn!("Can't parse url: {}", err),
                                }
                            }
                        }
                    }
                }
            }

            for event in view_events {
                match event {
                    ViewEvent::MouseWheel(delta, phase) => {
                        let (x, y) = match delta {
                            view::MouseScrollDelta::PixelDelta(x, y) => {
                                (x, y)
                            },
                            _ => (0.0, 0.0),
                        };
                        servo.perform_scroll(0, 0, x, y, phase);
                    }
                    ViewEvent::MouseMoved(x, y) => {
                        last_mouse_point = (x, y);
                        servo.perform_mouse_move(x, y);
                    }
                    ViewEvent::MouseInput(state, button) => {
                        let (x, y) = last_mouse_point;
                        let (org_x, org_y) = last_mouse_down_point;
                        servo.perform_click(x, y, org_x, org_y, state, button, last_mouse_down_button);
                        last_mouse_down_point = (x, y);
                        if state == view::ElementState::Pressed {
                            last_mouse_down_button = Some(button);
                        }
                    }
                }
            }

            for event in servo_events {
                match event {
                    ServoEvent::SetWindowInnerSize(..) => {
                        // ignore
                    }
                    ServoEvent::SetWindowPosition(..) => {
                        // ignore
                    }
                    ServoEvent::SetFullScreenState(fullscreen) => {
                        if fullscreen {
                            view.enter_fullscreen();
                        } else {
                            view.exit_fullscreen();
                        }
                    }
                    ServoEvent::Present => {
                        view.swap_buffers();
                    }
                    ServoEvent::TitleChanged(title) => {
                        window.set_title(&title.unwrap_or("No Title".to_owned()));

                    }
                    ServoEvent::UnhandledURL(url) => {
                        open::that(url.as_str()).ok();

                    }
                    ServoEvent::StatusChanged(..) => {
                        // FIXME
                    }
                    ServoEvent::LoadStart(..) => {
                        window.set_command_state(WindowCommand::Reload, CommandState::Disabled);
                        window.set_command_state(WindowCommand::Stop, CommandState::Enabled);
                    }
                    ServoEvent::LoadEnd(..) => {
                        window.set_command_state(WindowCommand::Reload, CommandState::Enabled);
                        window.set_command_state(WindowCommand::Stop, CommandState::Disabled);
                    }
                    ServoEvent::LoadError(..) => {
                        // FIXME
                    }
                    ServoEvent::HeadParsed(url) => {
                        window.set_url(url.as_str());
                    }
                    ServoEvent::CursorChanged(cursor) => {
                        window.set_cursor(cursor);
                    }
                    ServoEvent::FaviconChanged(..) => {
                        // FIXME
                    }
                    ServoEvent::Key(..) => {
                        // FIXME
                    }
                }
            }

            servo.sync(force_sync);
        }
    });

}
<commit_msg>update history command state<commit_after>#![feature(box_syntax)]

#[macro_use]
extern crate objc;

#[macro_use]
extern crate log;

extern crate simplelog;
extern crate libc;
extern crate cocoa;
extern crate objc_foundation;
extern crate open;

mod app;
mod window;
mod view;
mod servo;
mod platform;
mod commands;

use app::AppEvent;
use window::WindowEvent;
use view::ViewEvent;
use servo::ServoEvent;
use simplelog::{CombinedLogger, Config, LogLevel, LogLevelFilter, TermLogger, WriteLogger};
use std::fs::File;
use std::env::args;
use app::App;
use servo::{Servo, ServoUrl, FollowLinkPolicy};
use commands::{AppCommand, WindowCommand, CommandState};

fn main() {

    // FIXME: can we use NSLog instead of a file?
    let log_file = File::create("/tmp/servoshell.log").unwrap();
    let log_config = Config {
        time: None,
        level: Some(LogLevel::Info),
        target: Some(LogLevel::Info),
        location: Some(LogLevel::Info),
    };

    let _ = match TermLogger::new(LogLevelFilter::Info, log_config) {
        Some(logger) => CombinedLogger::init(vec![
            logger,
            WriteLogger::new(LogLevelFilter::Info, log_config, log_file)
        ]),
        None => WriteLogger::init(LogLevelFilter::Info, log_config, log_file)
    };

    info!("starting");

    platform::init();

    let app = App::load().unwrap();
    let (window, view) = app.create_window().unwrap();

    // Skip first argument (executable), and find the first
    // argument that doesn't start with `-`
    let url = args().skip(1).find(|arg| {
        !arg.starts_with("-")
    }).unwrap_or("http://servo.org".to_owned());

    Servo::configure(&url).unwrap();
    let servo = {
        let geometry = view.get_geometry();
        let riser = window.create_eventloop_riser();
        // let policy = FollowLinkPolicy::FollowOriginalDomain;
        let policy = FollowLinkPolicy::FollowAnyLink;
        Servo::new(geometry, riser, &url, policy)
    };

    info!("Servo version: {}", servo.version());

    window.set_command_state(WindowCommand::OpenLocation, CommandState::Enabled);
    window.set_command_state(WindowCommand::ZoomIn, CommandState::Enabled);
    window.set_command_state(WindowCommand::ZoomOut, CommandState::Enabled);
    window.set_command_state(WindowCommand::ZoomToActualSize, CommandState::Enabled);
    app.set_command_state(AppCommand::ClearHistory, CommandState::Enabled);

    let mut last_mouse_point = (0, 0);
    let mut last_mouse_down_point = (0, 0);
    let mut last_mouse_down_button: Option<view::MouseButton> = None;

    app.run(|| {

        // Loop until no events are available anymore.
        loop {

            let app_events = app.get_events();
            let win_events = window.get_events();
            let view_events = view.get_events();
            let servo_events = servo.get_events();

            if app_events.is_empty() &&
               win_events.is_empty() &&
               view_events.is_empty() &&
               servo_events.is_empty() {
                   break
            }

            // FIXME: it's really annoying we need this
            let mut force_sync = false;

            for event in app_events {
                match event {
                    AppEvent::DidFinishLaunching => {
                        // FIXME: does this work?
                    }
                    AppEvent::WillTerminate => {
                        // FIXME: does this work?
                    }
                    AppEvent::DidChangeScreenParameters => {
                        // FIXME: does this work?
                        servo.update_geometry(view.get_geometry());
                        view.update_drawable();
                    }
                    AppEvent::DoCommand(cmd) => {
                        match cmd {
                            AppCommand::ClearHistory => {
                                // FIXME
                            }
                        }
                    }
                }
            }

            for event in win_events {
                match event {
                    WindowEvent::EventLoopRised => {
                        force_sync = true;
                    }
                    WindowEvent::GeometryDidChange => {
                        servo.update_geometry(view.get_geometry());
                        view.update_drawable();
                    }
                    WindowEvent::DidEnterFullScreen => {
                        // FIXME
                    }
                    WindowEvent::DidExitFullScreen => {
                        // FIXME
                    }
                    WindowEvent::WillClose => {
                        // FIXME
                    }
                    WindowEvent::DoCommand(cmd) => {
                        match cmd {
                            WindowCommand::Stop => {
                                // FIXME
                            }
                            WindowCommand::Reload => {
                                servo.reload();
                            }
                            WindowCommand::NavigateBack => {
                                servo.go_back();
                            }
                            WindowCommand::NavigateForward => {
                                servo.go_forward();
                            }
                            WindowCommand::OpenLocation => {
                                window.focus_urlbar();
                            }
                            WindowCommand::ZoomIn => {
                                servo.zoom(1.1);
                            }
                            WindowCommand::ZoomOut => {
                                servo.zoom(1.0 / 1.1);
                            }
                            WindowCommand::ZoomToActualSize => {
                                servo.reset_zoom();
                            }
                            WindowCommand::Load(request) => {
                                let url = ServoUrl::parse(&request).or_else(|error| {
                                    // FIXME: weak
                                    if request.ends_with(".com") || request.ends_with(".org") || request.ends_with(".net") {
                                        ServoUrl::parse(&format!("http://{}", request))
                                    } else {
                                        Err(error)
                                    }
                                }).or_else(|_| {
                                    ServoUrl::parse(&format!("https://duckduckgo.com/html/?q={}", request))
                                });
                                match url {
                                    Ok(url) => {
                                        servo.load_url(url)
                                    },
                                    Err(err) => warn!("Can't parse url: {}", err),
                                }
                            }
                        }
                    }
                }
            }

            for event in view_events {
                match event {
                    ViewEvent::MouseWheel(delta, phase) => {
                        let (x, y) = match delta {
                            view::MouseScrollDelta::PixelDelta(x, y) => {
                                (x, y)
                            },
                            _ => (0.0, 0.0),
                        };
                        servo.perform_scroll(0, 0, x, y, phase);
                    }
                    ViewEvent::MouseMoved(x, y) => {
                        last_mouse_point = (x, y);
                        servo.perform_mouse_move(x, y);
                    }
                    ViewEvent::MouseInput(state, button) => {
                        let (x, y) = last_mouse_point;
                        let (org_x, org_y) = last_mouse_down_point;
                        servo.perform_click(x, y, org_x, org_y, state, button, last_mouse_down_button);
                        last_mouse_down_point = (x, y);
                        if state == view::ElementState::Pressed {
                            last_mouse_down_button = Some(button);
                        }
                    }
                }
            }

            for event in servo_events {
                match event {
                    ServoEvent::SetWindowInnerSize(..) => {
                        // ignore
                    }
                    ServoEvent::SetWindowPosition(..) => {
                        // ignore
                    }
                    ServoEvent::SetFullScreenState(fullscreen) => {
                        if fullscreen {
                            view.enter_fullscreen();
                        } else {
                            view.exit_fullscreen();
                        }
                    }
                    ServoEvent::Present => {
                        view.swap_buffers();
                    }
                    ServoEvent::TitleChanged(title) => {
                        window.set_title(&title.unwrap_or("No Title".to_owned()));

                    }
                    ServoEvent::UnhandledURL(url) => {
                        open::that(url.as_str()).ok();

                    }
                    ServoEvent::StatusChanged(..) => {
                        // FIXME
                    }
                    ServoEvent::LoadStart(can_go_back, can_go_forward) => {
                        window.set_command_state(WindowCommand::Reload, CommandState::Disabled);
                        window.set_command_state(WindowCommand::Stop, CommandState::Enabled);

                        // FIXME: See https://github.com/servo/servo/issues/15643
                        window.set_command_state(WindowCommand::NavigateBack, if can_go_back {
                            CommandState::Enabled
                        } else {
                            CommandState::Disabled
                        });
                        window.set_command_state(WindowCommand::NavigateForward, if can_go_forward {
                            CommandState::Enabled
                        } else {
                            CommandState::Disabled
                        });
                    }
                    ServoEvent::LoadEnd(can_go_back, can_go_forward, root) => {
                        window.set_command_state(WindowCommand::Reload, CommandState::Enabled);
                        window.set_command_state(WindowCommand::Stop, CommandState::Disabled);

                        if root {
                            // FIXME: See https://github.com/servo/servo/issues/15643
                            window.set_command_state(WindowCommand::NavigateBack, if can_go_back {
                                CommandState::Enabled
                            } else {
                                CommandState::Disabled
                            });
                            window.set_command_state(WindowCommand::NavigateForward, if can_go_forward {
                                CommandState::Enabled
                            } else {
                                CommandState::Disabled
                            });
                        }
                    }
                    ServoEvent::LoadError(..) => {
                        // FIXME
                    }
                    ServoEvent::HeadParsed(url) => {
                        window.set_url(url.as_str());
                    }
                    ServoEvent::CursorChanged(cursor) => {
                        window.set_cursor(cursor);
                    }
                    ServoEvent::FaviconChanged(..) => {
                        // FIXME
                    }
                    ServoEvent::Key(..) => {
                        // FIXME
                    }
                }
            }

            servo.sync(force_sync);
        }
    });

}
<|endoftext|>


<commit_before>#![feature(box_syntax)]
#![feature(unsafe_destructor)]
#![feature(unboxed_closures)]
#![feature(collections)]
#![feature(core)]
#![feature(path)]
#![feature(io)]
#![feature(old_io)]
#![feature(old_path)]
#![feature(fs)]
#![feature(os)]
#![feature(libc)]
#![feature(std_misc)]
#![feature(unicode)]
#![feature(rustc_private)]
#![feature(plugin)]
#![plugin(regex_macros)]
extern crate sodiumoxide;
extern crate libc;
extern crate serialize;
extern crate unicode;
extern crate regex;
extern crate core;
#[no_link]
extern crate regex_macros;

use reader::*;
use constants::*;
use builtins::*;
use types::*;
use ast::*;
use env::*;
use handlers::*;

use types::InputValue::*;

mod constants;
#[macro_use]
mod util;
mod termios;
mod signal;
mod controls;
mod input;
mod reader;
mod script;
mod builtins;
mod command;
mod types;
mod env;
mod ioctl;
mod ast;
mod handlers;

// public so no warnings when we run tests
pub fn main() {
    let mut reader = LineReader::new();
    let mut env = WashEnv::new();
    let mut ast = AST::new();
    let mut cleaned_jobs;
    match load_builtins(&mut env) {
        Err(e) => env.errf(format_args!("Could not load builtings: {}\n", e)),
        _ => {}
    }
    load_handlers(&mut ast);
    env.update_terminal();
    loop {
        env.flush();
        cleaned_jobs = env.clean_jobs();
        match cleaned_jobs {
            WashArgs::Long(v) => {
                for status in v.iter() {
                    env.outf(format_args!("{}\n", status.flatten()));
                }
            },
            _ => {/* nothing */}
        }
        if ast.in_block() {
            match env.runf(&format!("subprompt"), &WashArgs::Empty) {
                Err(_) => reader.controls.outs("prompt failed => run("),
                Ok(v) => reader.controls.outs(v.flatten().as_slice())
            }
        } else {
            match env.runf(&format!("prompt"), &WashArgs::Empty) {
                Err(_) => reader.controls.outs("prompt failed => run("),
                Ok(v) => reader.controls.outs(v.flatten().as_slice())
            }
        }
        match reader.read_line() {
            None => {
                if reader.eof {
                    break;
                } else if !reader.line.is_empty() {
                    env.outc(BEL);
                    reader.restart();
                } else {
                    env.outc(NL);
                    reader.clear();
                }
            },
            Some(mut line) => {
                env.outc(NL);
                match ast.add_line(&mut line) {
                    Err(ref e) if *e == STOP => {
                        // the silent error
                        ast.clear();
                    },
                    Err(e) => {
                        println!("Error: {}", e);
                        ast.clear();
                    },
                    Ok(_) => {
                        if !ast.in_block() {
                            //println!("{:?}", ast);
                            match ast.optimize() {
                                Err(e) => {
                                    println!("Optimization error: {}", e);
                                },
                                Ok(_) => {
                                    //println!("{:?}", ast);
                                }
                            }
                            match ast.into_runner().evaluate(&WashArgs::Empty, &mut env) {
                                Err(ref e) if *e == STOP => {
                                    // the silent error
                                }
                                Err(e) => {
                                    println!("Error: {}", e);
                                },
                                Ok(WashArgs::Empty) => {
                                    // print nothing
                                },
                                Ok(v) => {
                                    println!("{}", v.flatten());
                                }
                            };
                        }
                    }
                }
                reader.clear();
            }
        }
    }
    env.outs("\nExiting\n");
    env.flush();
}
<commit_msg>Update for rust nightlies<commit_after>#![feature(box_syntax)]
// we have to use the old process module, because the new one doesn't support
// inheritfd, which is needed for process piping
#![allow(deprecated)]
#![feature(unsafe_destructor)]
#![feature(unboxed_closures)]
#![feature(collections)]
#![feature(core)]
#![feature(path_ext)]
#![feature(path)]
#![feature(io)]
#![feature(old_io)]
#![feature(old_path)]
#![feature(libc)]
#![feature(std_misc)]
#![feature(unicode)]
#![feature(rustc_private)]
#![feature(plugin)]
#![plugin(regex_macros)]
extern crate sodiumoxide;
extern crate libc;
extern crate serialize;
extern crate unicode;
extern crate regex;
extern crate core;
#[no_link]
extern crate regex_macros;

use reader::*;
use constants::*;
use builtins::*;
use types::*;
use ast::*;
use env::*;
use handlers::*;

use types::InputValue::*;

mod constants;
#[macro_use]
mod util;
mod termios;
mod signal;
mod controls;
mod input;
mod reader;
mod script;
mod builtins;
mod command;
mod types;
mod env;
mod ioctl;
mod ast;
mod handlers;

// public so no warnings when we run tests
pub fn main() {
    let mut reader = LineReader::new();
    let mut env = WashEnv::new();
    let mut ast = AST::new();
    let mut cleaned_jobs;
    match load_builtins(&mut env) {
        Err(e) => env.errf(format_args!("Could not load builtings: {}\n", e)),
        _ => {}
    }
    load_handlers(&mut ast);
    env.update_terminal();
    loop {
        env.flush();
        cleaned_jobs = env.clean_jobs();
        match cleaned_jobs {
            WashArgs::Long(v) => {
                for status in v.iter() {
                    env.outf(format_args!("{}\n", status.flatten()));
                }
            },
            _ => {/* nothing */}
        }
        if ast.in_block() {
            match env.runf(&format!("subprompt"), &WashArgs::Empty) {
                Err(_) => reader.controls.outs("prompt failed => run("),
                Ok(v) => reader.controls.outs(v.flatten().as_slice())
            }
        } else {
            match env.runf(&format!("prompt"), &WashArgs::Empty) {
                Err(_) => reader.controls.outs("prompt failed => run("),
                Ok(v) => reader.controls.outs(v.flatten().as_slice())
            }
        }
        match reader.read_line() {
            None => {
                if reader.eof {
                    break;
                } else if !reader.line.is_empty() {
                    env.outc(BEL);
                    reader.restart();
                } else {
                    env.outc(NL);
                    reader.clear();
                }
            },
            Some(mut line) => {
                env.outc(NL);
                match ast.add_line(&mut line) {
                    Err(ref e) if *e == STOP => {
                        // the silent error
                        ast.clear();
                    },
                    Err(e) => {
                        println!("Error: {}", e);
                        ast.clear();
                    },
                    Ok(_) => {
                        if !ast.in_block() {
                            //println!("{:?}", ast);
                            match ast.optimize() {
                                Err(e) => {
                                    println!("Optimization error: {}", e);
                                },
                                Ok(_) => {
                                    //println!("{:?}", ast);
                                }
                            }
                            match ast.into_runner().evaluate(&WashArgs::Empty, &mut env) {
                                Err(ref e) if *e == STOP => {
                                    // the silent error
                                }
                                Err(e) => {
                                    println!("Error: {}", e);
                                },
                                Ok(WashArgs::Empty) => {
                                    // print nothing
                                },
                                Ok(v) => {
                                    println!("{}", v.flatten());
                                }
                            };
                        }
                    }
                }
                reader.clear();
            }
        }
    }
    env.outs("\nExiting\n");
    env.flush();
}
<|endoftext|>


<commit_before>extern crate rucc;
use rucc::version_info;
use rucc::parser;
use rucc::codegen;

extern crate regex;
use regex::Regex;

fn main() {
    let args: Vec<String> = std::env::args().collect();

    if args.len() < 2 {
        version_info::show_version();
        version_info::show_usage();
        let ref input_file_name = "./a.c";
        let ast = parser::Parser::run_file(input_file_name.to_string());

        for node in &ast {
            node.show();
        }

        println!("\nllvm-ir test output:");
        unsafe {
            let mut codegen = codegen::Codegen::new("rucc");
            codegen.run(ast);

            let output_file_name = Regex::new(r"\..*$")
                .unwrap()
                .replace_all(input_file_name, ".ll");
            codegen.write_llvmir_to_file(output_file_name.to_string().as_str());
        }
    } else {
        let ref input_file_name = args[1];
        let ast = parser::Parser::run_file(input_file_name.to_string());

        for node in &ast {
            node.show();
        }

        println!("\nllvm-ir test output:");
        unsafe {
            let mut codegen = codegen::Codegen::new("rucc");
            codegen.run(ast);

            let output_file_name = Regex::new(r"\..*$")
                .unwrap()
                .replace_all(input_file_name, ".ll");
            codegen.write_llvmir_to_file(output_file_name.to_string().as_str());
        }
    }
}
<commit_msg>deleted extra code<commit_after>extern crate rucc;
use rucc::version_info;
use rucc::parser;
use rucc::codegen;

extern crate regex;
use regex::Regex;

fn main() {
    let args: Vec<String> = std::env::args().collect();

    if args.len() < 2 {
        version_info::show_version();
        version_info::show_usage();
    } else {
        let ref input_file_name = args[1];
        let ast = parser::Parser::run_file(input_file_name.to_string());

        for node in &ast {
            node.show();
        }

        println!("\nllvm-ir test output:");
        unsafe {
            let mut codegen = codegen::Codegen::new("rucc");
            codegen.run(ast);

            let output_file_name = Regex::new(r"\..*$")
                .unwrap()
                .replace_all(input_file_name, ".ll");
            codegen.write_llvmir_to_file(output_file_name.to_string().as_str());
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;

mod lib;
use lib::Petnames;

use std::collections::HashSet;
use std::fmt;
use std::fs;
use std::io::{self, Write};
use std::path;
use std::process;
use std::str::FromStr;

use clap::Arg;
use rand::seq::IteratorRandom;

fn main() {
    let matches = app().get_matches();
    match run(matches) {
        Err(Error::Disconnected) => {
            process::exit(0);
        }
        Err(e) => {
            eprintln!("Error: {}", e);
            process::exit(1);
        }
        Ok(()) => {
            process::exit(0);
        }
    }
}

enum Error {
    Io(io::Error),
    FileIo(path::PathBuf, io::Error),
    Cardinality(String),
    Alliteration(String),
    Disconnected,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Error::Io(ref e) => write!(f, "{}", e),
            Error::FileIo(ref path, ref e) => write!(f, "{}: {}", e, path.display()),
            Error::Cardinality(ref message) => write!(f, "cardinality is zero: {}", message),
            Error::Alliteration(ref message) => write!(f, "cannot alliterate: {}", message),
            Error::Disconnected => write!(f, "caller disconnected / stopped reading"),
        }
    }
}

impl From<io::Error> for Error {
    fn from(error: io::Error) -> Self {
        Error::Io(error)
    }
}

fn app<'a, 'b>() -> clap::App<'a, 'b> {
    clap::App::new("rust-petname")
        .version(crate_version!())
        .author(crate_authors!())
        .about("Generate human readable random names.")
        .after_help(concat!(
            "Based on Dustin Kirkland's petname project ",
            "<https://github.com/dustinkirkland/petname>."
        ))
        .arg(
            Arg::with_name("words")
                .short("w")
                .long("words")
                .value_name("WORDS")
                .default_value("2")
                .help("Number of words in name")
                .takes_value(true)
                .validator(can_be_parsed::<u8>),
        )
        .arg(
            Arg::with_name("separator")
                .short("s")
                .long("separator")
                .value_name("SEP")
                .default_value("-")
                .help("Separator between words")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("complexity")
                .short("c")
                .long("complexity")
                .value_name("COM")
                .possible_values(&["0", "1", "2"])
                .hide_possible_values(true)
                .default_value("0")
                .help("Use small words (0), medium words (1), or large words (2)")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("directory")
                .short("d")
                .long("dir")
                .value_name("DIR")
                .help("Directory containing adjectives.txt, adverbs.txt, names.txt")
                .conflicts_with("complexity")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("count")
                .long("count")
                .value_name("COUNT")
                .default_value("1")
                .help("Generate multiple names; pass 0 to produce infinite names!")
                .takes_value(true)
                .validator(can_be_parsed::<usize>),
        )
        .arg(
            Arg::with_name("letters")
                .short("l")
                .long("letters")
                .value_name("LETTERS")
                .default_value("0")
                .help("Maxiumum number of letters in each word; 0 for unlimited")
                .takes_value(true)
                .validator(can_be_parsed::<usize>),
        )
        .arg(
            Arg::with_name("alliterate")
                .short("a")
                .long("alliterate")
                .help("Generate names where each word begins with the same letter")
                .takes_value(false),
        )
        .arg(
            // For compatibility with upstream.
            Arg::with_name("ubuntu")
                .short("u")
                .long("ubuntu")
                .help("Alias; see --alliterate")
                .takes_value(false),
        )
}

fn run(matches: clap::ArgMatches) -> Result<(), Error> {
    // Unwrapping is safe because these options have defaults.
    let opt_separator = matches.value_of("separator").unwrap();
    let opt_words = matches.value_of("words").unwrap();
    let opt_complexity = matches.value_of("complexity").unwrap();
    let opt_count = matches.value_of("count").unwrap();
    let opt_letters = matches.value_of("letters").unwrap();
    let opt_alliterate = matches.is_present("alliterate") || matches.is_present("ubuntu");

    // Optional arguments without defaults.
    let opt_directory = matches.value_of("directory");

    // Parse numbers. Validated so unwrapping is okay.
    let opt_words: u8 = opt_words.parse().unwrap();
    let opt_count: usize = opt_count.parse().unwrap();
    let opt_letters: usize = opt_letters.parse().unwrap();

    // Load custom word lists, if specified.
    let words = match opt_directory {
        Some(dirname) => Words::load(dirname)?,
        None => Words::Builtin,
    };

    // Select the appropriate word list.
    let mut petnames = match words {
        Words::Custom(ref adjectives, ref adverbs, ref names) => {
            Petnames::init(&adjectives, &adverbs, &names)
        }
        Words::Builtin => match opt_complexity {
            "0" => Petnames::small(),
            "1" => Petnames::medium(),
            "2" => Petnames::large(),
            _ => Petnames::small(),
        },
    };

    // If requested, limit the number of letters.
    if opt_letters != 0 {
        petnames.retain(|s| s.len() <= opt_letters);
    }

    // Check cardinality.
    if petnames.cardinality(opt_words) == 0 {
        return Err(Error::Cardinality(
            "no petnames to choose from; try relaxing constraints".to_string(),
        ));
    }

    // We're going to need a source of randomness.
    let mut rng = rand::thread_rng();

    // If requested, choose a random letter then discard all words that do not
    // begin with that letter.
    if opt_alliterate {
        // We choose the first letter from the intersection of the first letters
        // of each word list in `petnames`.
        let firsts =
            common_first_letters(&petnames.adjectives, &[&petnames.adverbs, &petnames.names]);
        // Choose the first letter at random; fails if there are no letters.
        match firsts.iter().choose(&mut rng) {
            Some(c) => petnames.retain(|s| s.starts_with(*c)),
            None => {
                return Err(Error::Alliteration(
                    "word lists have no initial letters in common".to_string(),
                ))
            }
        };
    }

    // Get an iterator for the names we want to print out.
    let names = petnames.iter(&mut rng, opt_words, opt_separator);

    // Manage stdout.
    let stdout = io::stdout();
    let mut handle = stdout.lock();

    // Stream if count is 0.
    if opt_count == 0 {
        for name in names {
            writeln!(handle, "{}", name).map_err(suppress_disconnect)?;
        }
    } else {
        for name in names.take(opt_count) {
            writeln!(handle, "{}", name)?;
        }
    }

    Ok(())
}

fn can_be_parsed<INTO>(value: String) -> Result<(), String>
where
    INTO: FromStr,
    <INTO as FromStr>::Err: std::fmt::Display,
{
    match value.parse::<INTO>() {
        Err(e) => Err(format!("{}", e)),
        Ok(_) => Ok(()),
    }
}

fn common_first_letters(init: &[&str], more: &[&[&str]]) -> HashSet<char> {
    let mut firsts = first_letters(init);
    let firsts_other: Vec<HashSet<char>> = more.iter().map(|list| first_letters(list)).collect();
    firsts.retain(|c| firsts_other.iter().all(|fs| fs.contains(c)));
    firsts
}

fn first_letters(names: &[&str]) -> HashSet<char> {
    names.iter().filter_map(|s| s.chars().next()).collect()
}

enum Words {
    Custom(String, String, String),
    Builtin,
}

impl Words {
    // Load word lists from the given directory. This function expects to find three
    // files in that directory: `adjectives.txt`, `adverbs.txt`, and `names.txt`.
    // Each should be valid UTF-8, and contain words separated by whitespace.
    fn load<T: AsRef<path::Path>>(dirname: T) -> Result<Self, Error> {
        let dirname = dirname.as_ref();
        Ok(Self::Custom(
            read_file_to_string(dirname.join("adjectives.txt"))?,
            read_file_to_string(dirname.join("adverbs.txt"))?,
            read_file_to_string(dirname.join("names.txt"))?,
        ))
    }
}

fn read_file_to_string<P: AsRef<path::Path>>(path: P) -> Result<String, Error> {
    fs::read_to_string(&path).map_err(|error| Error::FileIo(path.as_ref().to_path_buf(), error))
}

fn suppress_disconnect(err: io::Error) -> Error {
    match err.kind() {
        io::ErrorKind::BrokenPipe => Error::Disconnected,
        _ => err.into(),
    }
}
<commit_msg>Buffer stdout for a 5x speed-up when producing high name counts.<commit_after>#[macro_use]
extern crate clap;

mod lib;
use lib::Petnames;

use std::collections::HashSet;
use std::fmt;
use std::fs;
use std::io::{self, Write};
use std::path;
use std::process;
use std::str::FromStr;

use clap::Arg;
use rand::seq::IteratorRandom;

fn main() {
    let matches = app().get_matches();
    match run(matches) {
        Err(Error::Disconnected) => {
            process::exit(0);
        }
        Err(e) => {
            eprintln!("Error: {}", e);
            process::exit(1);
        }
        Ok(()) => {
            process::exit(0);
        }
    }
}

enum Error {
    Io(io::Error),
    FileIo(path::PathBuf, io::Error),
    Cardinality(String),
    Alliteration(String),
    Disconnected,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Error::Io(ref e) => write!(f, "{}", e),
            Error::FileIo(ref path, ref e) => write!(f, "{}: {}", e, path.display()),
            Error::Cardinality(ref message) => write!(f, "cardinality is zero: {}", message),
            Error::Alliteration(ref message) => write!(f, "cannot alliterate: {}", message),
            Error::Disconnected => write!(f, "caller disconnected / stopped reading"),
        }
    }
}

impl From<io::Error> for Error {
    fn from(error: io::Error) -> Self {
        Error::Io(error)
    }
}

fn app<'a, 'b>() -> clap::App<'a, 'b> {
    clap::App::new("rust-petname")
        .version(crate_version!())
        .author(crate_authors!())
        .about("Generate human readable random names.")
        .after_help(concat!(
            "Based on Dustin Kirkland's petname project ",
            "<https://github.com/dustinkirkland/petname>."
        ))
        .arg(
            Arg::with_name("words")
                .short("w")
                .long("words")
                .value_name("WORDS")
                .default_value("2")
                .help("Number of words in name")
                .takes_value(true)
                .validator(can_be_parsed::<u8>),
        )
        .arg(
            Arg::with_name("separator")
                .short("s")
                .long("separator")
                .value_name("SEP")
                .default_value("-")
                .help("Separator between words")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("complexity")
                .short("c")
                .long("complexity")
                .value_name("COM")
                .possible_values(&["0", "1", "2"])
                .hide_possible_values(true)
                .default_value("0")
                .help("Use small words (0), medium words (1), or large words (2)")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("directory")
                .short("d")
                .long("dir")
                .value_name("DIR")
                .help("Directory containing adjectives.txt, adverbs.txt, names.txt")
                .conflicts_with("complexity")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("count")
                .long("count")
                .value_name("COUNT")
                .default_value("1")
                .help("Generate multiple names; pass 0 to produce infinite names!")
                .takes_value(true)
                .validator(can_be_parsed::<usize>),
        )
        .arg(
            Arg::with_name("letters")
                .short("l")
                .long("letters")
                .value_name("LETTERS")
                .default_value("0")
                .help("Maxiumum number of letters in each word; 0 for unlimited")
                .takes_value(true)
                .validator(can_be_parsed::<usize>),
        )
        .arg(
            Arg::with_name("alliterate")
                .short("a")
                .long("alliterate")
                .help("Generate names where each word begins with the same letter")
                .takes_value(false),
        )
        .arg(
            // For compatibility with upstream.
            Arg::with_name("ubuntu")
                .short("u")
                .long("ubuntu")
                .help("Alias; see --alliterate")
                .takes_value(false),
        )
}

fn run(matches: clap::ArgMatches) -> Result<(), Error> {
    // Unwrapping is safe because these options have defaults.
    let opt_separator = matches.value_of("separator").unwrap();
    let opt_words = matches.value_of("words").unwrap();
    let opt_complexity = matches.value_of("complexity").unwrap();
    let opt_count = matches.value_of("count").unwrap();
    let opt_letters = matches.value_of("letters").unwrap();
    let opt_alliterate = matches.is_present("alliterate") || matches.is_present("ubuntu");

    // Optional arguments without defaults.
    let opt_directory = matches.value_of("directory");

    // Parse numbers. Validated so unwrapping is okay.
    let opt_words: u8 = opt_words.parse().unwrap();
    let opt_count: usize = opt_count.parse().unwrap();
    let opt_letters: usize = opt_letters.parse().unwrap();

    // Load custom word lists, if specified.
    let words = match opt_directory {
        Some(dirname) => Words::load(dirname)?,
        None => Words::Builtin,
    };

    // Select the appropriate word list.
    let mut petnames = match words {
        Words::Custom(ref adjectives, ref adverbs, ref names) => {
            Petnames::init(&adjectives, &adverbs, &names)
        }
        Words::Builtin => match opt_complexity {
            "0" => Petnames::small(),
            "1" => Petnames::medium(),
            "2" => Petnames::large(),
            _ => Petnames::small(),
        },
    };

    // If requested, limit the number of letters.
    if opt_letters != 0 {
        petnames.retain(|s| s.len() <= opt_letters);
    }

    // Check cardinality.
    if petnames.cardinality(opt_words) == 0 {
        return Err(Error::Cardinality(
            "no petnames to choose from; try relaxing constraints".to_string(),
        ));
    }

    // We're going to need a source of randomness.
    let mut rng = rand::thread_rng();

    // If requested, choose a random letter then discard all words that do not
    // begin with that letter.
    if opt_alliterate {
        // We choose the first letter from the intersection of the first letters
        // of each word list in `petnames`.
        let firsts =
            common_first_letters(&petnames.adjectives, &[&petnames.adverbs, &petnames.names]);
        // Choose the first letter at random; fails if there are no letters.
        match firsts.iter().choose(&mut rng) {
            Some(c) => petnames.retain(|s| s.starts_with(*c)),
            None => {
                return Err(Error::Alliteration(
                    "word lists have no initial letters in common".to_string(),
                ))
            }
        };
    }

    // Get an iterator for the names we want to print out.
    let names = petnames.iter(&mut rng, opt_words, opt_separator);

    // Manage stdout.
    let stdout = io::stdout();
    let mut writer = io::BufWriter::new(stdout.lock());

    // Stream if count is 0.
    if opt_count == 0 {
        for name in names {
            writeln!(writer, "{}", name).map_err(suppress_disconnect)?;
        }
    } else {
        for name in names.take(opt_count) {
            writeln!(writer, "{}", name)?;
        }
    }

    Ok(())
}

fn can_be_parsed<INTO>(value: String) -> Result<(), String>
where
    INTO: FromStr,
    <INTO as FromStr>::Err: std::fmt::Display,
{
    match value.parse::<INTO>() {
        Err(e) => Err(format!("{}", e)),
        Ok(_) => Ok(()),
    }
}

fn common_first_letters(init: &[&str], more: &[&[&str]]) -> HashSet<char> {
    let mut firsts = first_letters(init);
    let firsts_other: Vec<HashSet<char>> = more.iter().map(|list| first_letters(list)).collect();
    firsts.retain(|c| firsts_other.iter().all(|fs| fs.contains(c)));
    firsts
}

fn first_letters(names: &[&str]) -> HashSet<char> {
    names.iter().filter_map(|s| s.chars().next()).collect()
}

enum Words {
    Custom(String, String, String),
    Builtin,
}

impl Words {
    // Load word lists from the given directory. This function expects to find three
    // files in that directory: `adjectives.txt`, `adverbs.txt`, and `names.txt`.
    // Each should be valid UTF-8, and contain words separated by whitespace.
    fn load<T: AsRef<path::Path>>(dirname: T) -> Result<Self, Error> {
        let dirname = dirname.as_ref();
        Ok(Self::Custom(
            read_file_to_string(dirname.join("adjectives.txt"))?,
            read_file_to_string(dirname.join("adverbs.txt"))?,
            read_file_to_string(dirname.join("names.txt"))?,
        ))
    }
}

fn read_file_to_string<P: AsRef<path::Path>>(path: P) -> Result<String, Error> {
    fs::read_to_string(&path).map_err(|error| Error::FileIo(path.as_ref().to_path_buf(), error))
}

fn suppress_disconnect(err: io::Error) -> Error {
    match err.kind() {
        io::ErrorKind::BrokenPipe => Error::Disconnected,
        _ => err.into(),
    }
}
<|endoftext|>


<commit_before>extern crate filetime;
extern crate rustc_serialize;
extern crate crypto;

use std::path::Path;
use std::collections::HashMap;

mod metadata;
mod workingdirectory;
mod store;
mod config;

fn main() {
	let mut args = std::env::args();
	match args.nth(1) {
		Some(option) => dispatch_option(&option),
		None => println!("No option")
	}
}

fn dispatch_option(option: &str) {
	match option {
		"new-config" => new_config(),
		"new" => new_repo(),
		"update" => update(),
		"update-remote" => update_remote(),
		"commit" => commit(),
		_ => println!("Unknown option {}", option)
	}
}

fn new_config() {
	println!("Creation of a new config file");
	let json_path = Path::new("config.json");
	config::create_default_config_file(json_path);
}

fn load_config() -> config::Config {
	config::read_config_file(Path::new("config.json"))
}

fn new_repo() {
	println!("Creation of a new repo");
	let json_path = load_config().get_local_metadata_path();
	metadata::create_emty_metadata_file(&json_path);
}

fn update() {
	let config = load_config();
	let data_path = config.get_data_path();
	let json_path = config.get_local_metadata_path();
	let store_path = config.get_store_path();

	let wd_hierarchy : HashMap<String, model::MetaData> = workingdirectory::read_working_directory(&data_path);
	println!("{} files in the working directory", wd_hierarchy.len());

	let mt_hierarchy = metadata::read_metadata_file(&json_path);
	println!("{} files in the metadata", mt_hierarchy.get_number_of_files());

	let file_top_update = files_to_update(wd_hierarchy, &mt_hierarchy);

	for (filename, metadata) in file_top_update.iter() {
		store::extract_file(&store_path, &metadata.get_hash(), &data_path, filename, metadata.get_timestamp());
	}
}

fn update_remote() {
	let config = load_config();
	let data_path = config.get_data_path();
	let json_path = config.get_local_metadata_path();
	let json_remote_path = config.get_remote_metadata_path();
	let store_path = config.get_store_path();

	let wd_hierarchy : HashMap<String, model::MetaData> = workingdirectory::read_working_directory(&data_path);
	println!("{} files in the working directory", wd_hierarchy.len());

	let mt_hierarchy = metadata::read_metadata_file(&json_path);
	println!("{} files in the metadata", mt_hierarchy.get_number_of_files());

	let mt_remote_hierarchy = metadata::read_metadata_file(&json_remote_path);
	println!("{} files in the remote metadata", mt_remote_hierarchy.get_number_of_files());

	let file_top_update = files_to_update_remote(wd_hierarchy, &mt_hierarchy, &mt_remote_hierarchy);
	match file_top_update {
		Some(x) => {
			println!("OK to update");
			for (filename, metadata) in x.iter() {
				store::extract_file(&store_path, &metadata.get_hash(), &data_path, filename, metadata.get_timestamp());
			}
		},
		None => println!("IMPOSSIBLE to update")
	}
}

fn files_to_update(wd_hierarchy: HashMap<String, model::MetaData>, mt_hierarchy: &model::Hierarchy) -> HashMap<String, model::MetaData>  {
	let mut file_to_update : HashMap<String, model::MetaData> = HashMap::new();

	for (filename, metadataset) in mt_hierarchy.get_files().iter() {
		let wd_metadata = wd_hierarchy.get(filename);

		match wd_metadata {
			Some(x) => {
				let wd_timestamp = x.get_timestamp();
				let last_md_timestamp = metadataset.get_last().unwrap().get_timestamp();

				if wd_timestamp == last_md_timestamp {
					println!("- No need to update because timestamps are equal {}", filename);
				} else if metadataset.has_metadata_with_timestamp(wd_timestamp) {
					println!("- Existing file to update {}", filename);
					file_to_update.insert(filename.clone(), metadataset.get_last().unwrap().clone());
				} else { //timestamp unknown
					if wd_timestamp > last_md_timestamp {
						println!("- Working directory file is more recent {}", filename);
					} else {
						print!(" - No !! Working directory file is older. It makes no sense {}", filename);
					}
				}
			    ()},
			None => {
				println!("- New file to update {}", filename);
			    file_to_update.insert(filename.clone(), metadataset.get_last().unwrap().clone());
			    () }
		}
	}

	file_to_update
}

fn files_to_update_remote(wd_hierarchy: HashMap<String, model::MetaData>, mt_local_hierarchy: &model::Hierarchy, mt_remote_hierarchy: &model::Hierarchy) -> Option<HashMap<String, model::MetaData>>  {
	let mut file_to_update : HashMap<String, model::MetaData> = HashMap::new();

	for (filename, metadataset) in mt_remote_hierarchy.get_files().iter() {
		let wd_metadata = wd_hierarchy.get(filename);

		match wd_metadata {
			Some(x) => {
				let wd_timestamp = x.get_timestamp();
				let last_md_timestamp = metadataset.get_last().unwrap().get_timestamp();

				if wd_timestamp == last_md_timestamp {
					println!("- No need to update because timestamps are equal {}", filename);
				} else if metadataset.has_metadata_with_timestamp(wd_timestamp) {
					println!("- Existing file to update {}", filename);
					file_to_update.insert(filename.clone(), metadataset.get_last().unwrap().clone());
				} else { //timestamp unknown

					match mt_local_hierarchy.get_latest_meta_data(&filename) {
						Some(m) => {
							if m.get_timestamp() == last_md_timestamp {
								println!("- No need to update because working directory file is a correct new version {}", filename);
							} else {
								println!("- CONFLICT ! The remove and the working directory file have changed {}", filename);
								return Option::None;
							}
						}
						None => {
							println!("- CONFLICT ! New file in the working directory but a remote version exists {}", filename);
							return Option::None;
						}
					};
				}
			    ()},
			None => {
				println!("- New file to update {}", filename);
			    file_to_update.insert(filename.clone(), metadataset.get_last().unwrap().clone());
			    () }
		}
	}

	Option::Some(file_to_update)
}

fn commit() {
	let config = load_config();
	let data_path = config.get_data_path();
	let json_path = config.get_local_metadata_path();
	let store_path = config.get_store_path();

	let wd_hierarchy : HashMap<String, model::MetaData> = workingdirectory::read_working_directory(&data_path);
	println!("{} files in the working directory", wd_hierarchy.len());

	let mt_hierarchy = metadata::read_metadata_file(&json_path);
	println!("{} files in the metadata", mt_hierarchy.get_number_of_files());

	let files_to_commit = files_to_commit(wd_hierarchy, &mt_hierarchy);
	println!("{} files to commit", files_to_commit.len());

	let mut updated_metadata : HashMap<String, model::MetaData> = HashMap::new();
	for (filename, mut metadata) in files_to_commit {
		let hash = store::store_file(&store_path, Path::new(&filename));
		metadata.add_hash(hash);

		updated_metadata.insert(filename, metadata);
	}
	let updated_metadata = updated_metadata;

	let mut mt_hierarchy = mt_hierarchy;
	mt_hierarchy.update(updated_metadata);

	metadata::write_metadata_file(&json_path, mt_hierarchy);
}

fn files_to_commit(wd_hierarchy: HashMap<String, model::MetaData>, mt_hierarchy: &model::Hierarchy) -> HashMap<String, model::MetaData>  {
	let mut files_to_commit: HashMap<String, model::MetaData> = HashMap::new();

	for (filename, metadata) in wd_hierarchy.iter() {
		let actual_metadata = mt_hierarchy.get_latest_meta_data(&filename);

		match actual_metadata {
			Some(x) => {
				if x.is_more_recent(&metadata) {
					println!("- File to update {}", filename);
					files_to_commit.insert(filename.clone(), metadata.clone());
				} else {
					println!("- No need to update {}", filename);
				}
			    ()},
			None => {
				println!("- New file {}", filename);
			    files_to_commit.insert(filename.clone(), metadata.clone());
			    () }
		}
	}

	files_to_commit
}

mod model {

	use std::collections::HashMap;

	#[derive(Debug, RustcEncodable, RustcDecodable)]
	pub struct Hierarchy {
		nb_revision: i32,
	    files: HashMap<String, MetaDataSet>
	}

	#[derive(Debug, RustcEncodable, RustcDecodable)]
	pub struct MetaDataSet {
	    metadata: Vec<MetaData>
	}

	#[derive(Debug, RustcEncodable, RustcDecodable, Clone)]
	pub struct MetaData {
	   timestamp: u64,
	   size: u64,
	   hash: String,
	   stored_hash: String
	}

	impl Hierarchy {
		pub fn new_empty() -> Hierarchy {
			let empty_hierarchy_map : HashMap<String, MetaDataSet> = HashMap::new();
			Hierarchy {nb_revision: 1, files: empty_hierarchy_map}
		}
		pub fn get_number_of_files(&self) -> usize {
			self.files.len()
		}
		pub fn get_latest_meta_data(&self, filename: &String) -> Option<&MetaData> {
			match self.files.get(filename) {
				Some(x) => x.get_last(),
				None => None
			}
		}
		pub fn update(&mut self, new_metadata_map: HashMap<String, MetaData>) {
			self.nb_revision = self.nb_revision + 1;

			for (filename, metadata) in new_metadata_map {

				let new_metadata = self.new_metadata(&filename);

				if new_metadata {
					self.files.insert(filename, MetaDataSet::new_simple_meta_data_set(metadata));
				} else {
					let mut m = self.files.get_mut(&filename).unwrap();
					m.add_revision(metadata);
				}
			}
		}

		fn new_metadata(&self, filename: &String) -> bool {
			let actual_metadata = self.files.get(filename);

			match actual_metadata {
				Some(_) => false,
				None => true
			}
		}

		pub fn get_files(&self) -> &HashMap<String, MetaDataSet> {
			&self.files
		}
	}

	impl MetaDataSet {
		pub fn get_last(&self) -> Option<&MetaData> {
			self.metadata.last()
		}
		pub fn new_simple_meta_data_set(m: MetaData) -> MetaDataSet {
			let mut v: Vec<MetaData> = Vec::new();
			v.push(m);
			MetaDataSet {metadata: v }
		}
		pub fn add_revision(&mut self, m: MetaData) {
			self.metadata.push(m);
		}
		pub fn has_metadata_with_timestamp(&self, timestamp: u64) -> bool {
			let mut it = self.metadata.iter();
			match it.find(|&m| m.get_timestamp() == timestamp) {
				Some(_) => true,
				None => false
			}
		}
	}

	impl MetaData {
		pub fn new_without_hash(timestamp: u64, size: u64) -> MetaData {
			MetaData {timestamp: timestamp, size: size, hash: "".to_string(), stored_hash: "".to_string()}
		}
		pub fn add_hash(&mut self, hash: String) {
			self.hash = hash;
		}
		pub fn is_more_recent(&self, other: &MetaData) -> bool {
			self.timestamp < other.timestamp
		}
		pub fn get_timestamp(&self) -> u64 {
			self.timestamp
		}
		pub fn get_hash(&self) -> String {
			self.hash.clone()
		}
	}

}<commit_msg>First draft of update-remote and commit-remote<commit_after>extern crate filetime;
extern crate rustc_serialize;
extern crate crypto;

use std::path::Path;
use std::collections::HashMap;
use std::fs::*;

mod metadata;
mod workingdirectory;
mod store;
mod config;

fn main() {
	let mut args = std::env::args();
	match args.nth(1) {
		Some(option) => dispatch_option(&option),
		None => println!("No option")
	}
}

fn dispatch_option(option: &str) {
	match option {
		"new-config" => new_config(),
		"new" => new_repo(),
		"update" => update(),
		"update-remote" => update_remote(),
		"commit" => commit(),
		"commit-remote" => commit_remote(),
		_ => println!("Unknown option {}", option)
	}
}

fn new_config() {
	println!("Creation of a new config file");
	let json_path = Path::new("config.json");
	config::create_default_config_file(json_path);
}

fn load_config() -> config::Config {
	config::read_config_file(Path::new("config.json"))
}

fn new_repo() {
	println!("Creation of a new repo");
	let json_path = load_config().get_local_metadata_path();
	metadata::create_emty_metadata_file(&json_path);
}

fn update() {
	let config = load_config();
	let data_path = config.get_data_path();
	let json_path = config.get_local_metadata_path();
	let store_path = config.get_store_path();

	let wd_hierarchy : HashMap<String, model::MetaData> = workingdirectory::read_working_directory(&data_path);
	println!("{} files in the working directory", wd_hierarchy.len());

	let mt_hierarchy = metadata::read_metadata_file(&json_path);
	println!("{} files in the metadata", mt_hierarchy.get_number_of_files());

	let file_top_update = files_to_update(wd_hierarchy, &mt_hierarchy);

	for (filename, metadata) in file_top_update.iter() {
		store::extract_file(&store_path, &metadata.get_hash(), &data_path, filename, metadata.get_timestamp());
	}
}

fn update_remote() {
	let config = load_config();
	let data_path = config.get_data_path();
	let json_path = config.get_local_metadata_path();
	let json_remote_path = config.get_remote_metadata_path();
	let store_path = config.get_store_path();

	let wd_hierarchy : HashMap<String, model::MetaData> = workingdirectory::read_working_directory(&data_path);
	println!("{} files in the working directory", wd_hierarchy.len());

	let mt_hierarchy = metadata::read_metadata_file(&json_path);
	println!("{} files in the metadata", mt_hierarchy.get_number_of_files());

	let mt_remote_hierarchy = metadata::read_metadata_file(&json_remote_path);
	println!("{} files in the remote metadata", mt_remote_hierarchy.get_number_of_files());

	let file_top_update = files_to_update_remote(wd_hierarchy, &mt_hierarchy, &mt_remote_hierarchy);
	match file_top_update {
		Some(x) => {
			println!("OK to update");
			for (filename, metadata) in x.iter() {
				store::extract_file(&store_path, &metadata.get_hash(), &data_path, filename, metadata.get_timestamp());
			}
			println!("Replace local metadata by remote metadata");
			remove_file(&json_path);
			copy(&json_remote_path, &json_path);
		},
		None => println!("IMPOSSIBLE to update")
	}
}

fn files_to_update(wd_hierarchy: HashMap<String, model::MetaData>, mt_hierarchy: &model::Hierarchy) -> HashMap<String, model::MetaData>  {
	let mut file_to_update : HashMap<String, model::MetaData> = HashMap::new();

	for (filename, metadataset) in mt_hierarchy.get_files().iter() {
		let wd_metadata = wd_hierarchy.get(filename);

		match wd_metadata {
			Some(x) => {
				let wd_timestamp = x.get_timestamp();
				let last_md_timestamp = metadataset.get_last().unwrap().get_timestamp();

				if wd_timestamp == last_md_timestamp {
					println!("- No need to update because timestamps are equal {}", filename);
				} else if metadataset.has_metadata_with_timestamp(wd_timestamp) {
					println!("- Existing file to update {}", filename);
					file_to_update.insert(filename.clone(), metadataset.get_last().unwrap().clone());
				} else { //timestamp unknown
					if wd_timestamp > last_md_timestamp {
						println!("- Working directory file is more recent {}", filename);
					} else {
						print!(" - No !! Working directory file is older. It makes no sense {}", filename);
					}
				}
			    ()},
			None => {
				println!("- New file to update {}", filename);
			    file_to_update.insert(filename.clone(), metadataset.get_last().unwrap().clone());
			    () }
		}
	}

	file_to_update
}

fn files_to_update_remote(wd_hierarchy: HashMap<String, model::MetaData>, mt_local_hierarchy: &model::Hierarchy, mt_remote_hierarchy: &model::Hierarchy) -> Option<HashMap<String, model::MetaData>>  {
	let mut file_to_update : HashMap<String, model::MetaData> = HashMap::new();

	for (filename, metadataset) in mt_remote_hierarchy.get_files().iter() {
		let wd_metadata = wd_hierarchy.get(filename);

		match wd_metadata {
			Some(x) => {
				let wd_timestamp = x.get_timestamp();
				let last_md_timestamp = metadataset.get_last().unwrap().get_timestamp();

				if wd_timestamp == last_md_timestamp {
					println!("- No need to update because timestamps are equal {}", filename);
				} else if metadataset.has_metadata_with_timestamp(wd_timestamp) {
					println!("- Existing file to update {}", filename);
					file_to_update.insert(filename.clone(), metadataset.get_last().unwrap().clone());
				} else { //timestamp unknown

					match mt_local_hierarchy.get_latest_meta_data(&filename) {
						Some(m) => {
							if m.get_timestamp() == last_md_timestamp {
								println!("- No need to update because working directory file is a correct new version {}", filename);
							} else {
								println!("- CONFLICT ! The remove and the working directory file have changed {}", filename);
								return Option::None;
							}
						}
						None => {
							println!("- CONFLICT ! New file in the working directory but a remote version exists {}", filename);
							return Option::None;
						}
					};
				}
			    ()},
			None => {
				println!("- New file to update {}", filename);
			    file_to_update.insert(filename.clone(), metadataset.get_last().unwrap().clone());
			    () }
		}
	}

	Option::Some(file_to_update)
}

fn commit_remote() {
	commit();

	let config = load_config();
	let json_path = config.get_local_metadata_path();
	let json_remote_path = config.get_remote_metadata_path();

	remove_file(&json_remote_path);
	copy(&json_path, &json_remote_path);
}

fn commit() {
	let config = load_config();
	let data_path = config.get_data_path();
	let json_path = config.get_local_metadata_path();
	let store_path = config.get_store_path();

	let wd_hierarchy : HashMap<String, model::MetaData> = workingdirectory::read_working_directory(&data_path);
	println!("{} files in the working directory", wd_hierarchy.len());

	let mt_hierarchy = metadata::read_metadata_file(&json_path);
	println!("{} files in the metadata", mt_hierarchy.get_number_of_files());

	let files_to_commit = files_to_commit(wd_hierarchy, &mt_hierarchy);
	println!("{} files to commit", files_to_commit.len());

	let mut updated_metadata : HashMap<String, model::MetaData> = HashMap::new();
	for (filename, mut metadata) in files_to_commit {
		let hash = store::store_file(&store_path, Path::new(&filename));
		metadata.add_hash(hash);

		updated_metadata.insert(filename, metadata);
	}
	let updated_metadata = updated_metadata;

	let mut mt_hierarchy = mt_hierarchy;
	mt_hierarchy.update(updated_metadata);

	metadata::write_metadata_file(&json_path, mt_hierarchy);
}

fn files_to_commit(wd_hierarchy: HashMap<String, model::MetaData>, mt_hierarchy: &model::Hierarchy) -> HashMap<String, model::MetaData>  {
	let mut files_to_commit: HashMap<String, model::MetaData> = HashMap::new();

	for (filename, metadata) in wd_hierarchy.iter() {
		let actual_metadata = mt_hierarchy.get_latest_meta_data(&filename);

		match actual_metadata {
			Some(x) => {
				if x.is_more_recent(&metadata) {
					println!("- File to update {}", filename);
					files_to_commit.insert(filename.clone(), metadata.clone());
				} else {
					println!("- No need to update {}", filename);
				}
			    ()},
			None => {
				println!("- New file {}", filename);
			    files_to_commit.insert(filename.clone(), metadata.clone());
			    () }
		}
	}

	files_to_commit
}

mod model {

	use std::collections::HashMap;

	#[derive(Debug, RustcEncodable, RustcDecodable)]
	pub struct Hierarchy {
		nb_revision: i32,
	    files: HashMap<String, MetaDataSet>
	}

	#[derive(Debug, RustcEncodable, RustcDecodable)]
	pub struct MetaDataSet {
	    metadata: Vec<MetaData>
	}

	#[derive(Debug, RustcEncodable, RustcDecodable, Clone)]
	pub struct MetaData {
	   timestamp: u64,
	   size: u64,
	   hash: String,
	   stored_hash: String
	}

	impl Hierarchy {
		pub fn new_empty() -> Hierarchy {
			let empty_hierarchy_map : HashMap<String, MetaDataSet> = HashMap::new();
			Hierarchy {nb_revision: 1, files: empty_hierarchy_map}
		}
		pub fn get_number_of_files(&self) -> usize {
			self.files.len()
		}
		pub fn get_latest_meta_data(&self, filename: &String) -> Option<&MetaData> {
			match self.files.get(filename) {
				Some(x) => x.get_last(),
				None => None
			}
		}
		pub fn update(&mut self, new_metadata_map: HashMap<String, MetaData>) {
			self.nb_revision = self.nb_revision + 1;

			for (filename, metadata) in new_metadata_map {

				let new_metadata = self.new_metadata(&filename);

				if new_metadata {
					self.files.insert(filename, MetaDataSet::new_simple_meta_data_set(metadata));
				} else {
					let mut m = self.files.get_mut(&filename).unwrap();
					m.add_revision(metadata);
				}
			}
		}

		fn new_metadata(&self, filename: &String) -> bool {
			let actual_metadata = self.files.get(filename);

			match actual_metadata {
				Some(_) => false,
				None => true
			}
		}

		pub fn get_files(&self) -> &HashMap<String, MetaDataSet> {
			&self.files
		}
	}

	impl MetaDataSet {
		pub fn get_last(&self) -> Option<&MetaData> {
			self.metadata.last()
		}
		pub fn new_simple_meta_data_set(m: MetaData) -> MetaDataSet {
			let mut v: Vec<MetaData> = Vec::new();
			v.push(m);
			MetaDataSet {metadata: v }
		}
		pub fn add_revision(&mut self, m: MetaData) {
			self.metadata.push(m);
		}
		pub fn has_metadata_with_timestamp(&self, timestamp: u64) -> bool {
			let mut it = self.metadata.iter();
			match it.find(|&m| m.get_timestamp() == timestamp) {
				Some(_) => true,
				None => false
			}
		}
	}

	impl MetaData {
		pub fn new_without_hash(timestamp: u64, size: u64) -> MetaData {
			MetaData {timestamp: timestamp, size: size, hash: "".to_string(), stored_hash: "".to_string()}
		}
		pub fn add_hash(&mut self, hash: String) {
			self.hash = hash;
		}
		pub fn is_more_recent(&self, other: &MetaData) -> bool {
			self.timestamp < other.timestamp
		}
		pub fn get_timestamp(&self) -> u64 {
			self.timestamp
		}
		pub fn get_hash(&self) -> String {
			self.hash.clone()
		}
	}

}<|endoftext|>


<commit_before>/*
    srtcli
    Utility to playback subtitles on the command line.

    Copyright 2016 Sam Saint-Pettersen.
    Released under the MIT/X11 License.
*/

mod subtitle;
extern crate stopwatch;
extern crate clock;
extern crate clioptions;
extern crate regex;
use subtitle::Subtitle;
use stopwatch::Stopwatch;
use clock::Clock;
use clioptions::CliOptions;
use regex::Regex;
use std::io::{BufRead, BufReader};
use std::fs::File;
use std::thread;
use std::process::exit;

fn parse_unit(unit: &str) -> i64 {
    let n = unit.parse::<i64>().ok();
    let unit = match n {
        Some(unit) => unit as i64,
        None => 0 as i64,
    };
    unit
}

fn clear_text(lines: u32) {
    for _ in 0..lines {
        println!("");
    }
}

fn convert_time_to_ms(timestamp: &str) -> i64 {
    let mut t: i64 = 0;
    let p = Regex::new(r"(\d{2}):(\d{2}):(\d{2}),(\d{3})").unwrap();
    for cap in p.captures_iter(&timestamp) {
        let hours = parse_unit(&cap.at(1).unwrap());
        let minutes = parse_unit(&cap.at(2).unwrap());
        let seconds = parse_unit(&cap.at(3).unwrap());
        let ms = parse_unit(&cap.at(4).unwrap());
        t = (hours * 3600) + (minutes * 60) + seconds;
        t = (t * 1000) + ms;
    }
    t
}

fn parse_subtitles(input: &str) -> Vec<Subtitle> {
    let f = File::open(input).unwrap();
    let file = BufReader::new(&f);
    let mut lines: Vec<String> = Vec::new();
    for line in file.lines() {
        let l = line.unwrap().to_string();
        if !l.is_empty() {
            lines.push(l);
        }
    }

    let mut seqs: Vec<i64> = Vec::new();
    let mut starts: Vec<i64> = Vec::new();
    let mut ends: Vec<i64> = Vec::new();
    let mut contents: Vec<String> = Vec::new();
    for l in lines {
        let mut p = Regex::new(r"^\d+$").unwrap();
        let mut is_timecode = false;
        if p.is_match(&l) {
            seqs.push(parse_unit(&l));
            continue;
        }
        p = Regex::new(r"(\d{2}:\d{2}:\d{2},\d{3})\s-->\s(\d{2}:\d{2}:\d{2},\d{3})").unwrap();
        for cap in p.captures_iter(&l) {
            starts.push(convert_time_to_ms(&cap.at(1).unwrap()));
            ends.push(convert_time_to_ms(&cap.at(2).unwrap()));
            is_timecode = true;
            continue;
        }

        p = Regex::new(r"^[\d-A-Za-z'\s]+").unwrap();
        if p.is_match(&l) && !is_timecode {
            contents.push(l.clone());
            continue;
        }
        else {
            contents.push("|".to_string());
        }
    }

    let contents = contents.join("\n");
    let split = contents.split("|");
    let mut text: Vec<String> = Vec::new();
    for c in split {
        if !c.is_empty() {
            text.push(c.to_string());
        }
    }

    let mut subtitles: Vec<Subtitle> = Vec::new();
    for i in 0..seqs.len() {
        subtitles.push(Subtitle::new(seqs[i], starts[i], ends[i], &text[i]));
    }
    subtitles
}

fn playback_subtitles(input: &str, use_clock: bool) {
    let subtitles: Vec<Subtitle> = parse_subtitles(&input);
    let runtime = subtitles[subtitles.len() - 1].get_end();
    let mut clock = Clock::new();
    clock.set_time_ms(runtime);
    clear_text(50);
    println!("Playing back: '{}' (Runtime: {} [{}ms])...", input, clock.get_time(), runtime);
    thread::sleep_ms(3000);
    clock.set_time_ms(0);
    println!("{}", clock.get_time());
    clear_text(50);
    let sw = Stopwatch::start_new();
    let mut i: usize = 0;
    let mut in_subtitle = false;
    loop {
        let time = sw.elapsed_ms();
        clock.set_time_ms(time);

        if time % 1000 == 0 && use_clock && !in_subtitle {
            clear_text(40);
            println!("{}", clock.get_time());
        }

        if time == subtitles[i].get_start() {
            clear_text(50);
            in_subtitle = true;
            println!("{}", subtitles[i].get_text());
        }
        if time == subtitles[i].get_end() {
            i += 1;
            in_subtitle = false;
            clear_text(50);
        }

        if i == subtitles.len() {
            break;
        }
    }
    exit(0);
}

fn display_usage(program: &str, exit_code: i32) {
    println!("\nsrtcli");
    println!("Utility to playback subtitles on the command line.");
    println!("\nCopyright 2016 Sam Saint-Pettersen.");
    println!("Released under the MIT/X11 License.");
    println!("\nUsage {} -f|--file <file.srt> -c|--clock [-h|--help]", program);
    println!("\n-f|--file: Subtitle file (SubRip Text) to playback.");
    println!("-c|--clock: Display a playback clock.");
    println!("-h|--help: Display this help information and exit.");
    exit(exit_code);
}

fn display_error(program: &str, err: &str) {
    println!("Error: {}.", err);
    display_usage(&program, -1);
}

fn main() {
    let cli = CliOptions::new("srtcli");
    let program = cli.get_program();
    let mut input = String::new();
    let mut use_clock = false;

    if cli.get_num() > 1 {
        for (i, a) in cli.get_args().iter().enumerate() {
            match a.trim() {
                "-h" | "--help" => display_usage(&program, 0),
                "-f" | "--file" => input = cli.next_argument(i),
                "-c" | "--clock" => use_clock = true,
                _ => continue,
            }
        }

        if input.is_empty() {
            display_error(&program, "No subtitle file specified");
        }

        playback_subtitles(&input, use_clock);
    }
    else {
        display_error(&program, "No options specified");
    }
}
<commit_msg>Check file begins with number as a valid subtitles file would.<commit_after>/*
    srtcli
    Utility to playback subtitles on the command line.

    Copyright 2016 Sam Saint-Pettersen.
    Released under the MIT/X11 License.
*/

mod subtitle;
extern crate stopwatch;
extern crate clock;
extern crate clioptions;
extern crate regex;
use subtitle::Subtitle;
use stopwatch::Stopwatch;
use clock::Clock;
use clioptions::CliOptions;
use regex::Regex;
use std::io::{BufRead, BufReader};
use std::fs::File;
use std::thread;
use std::process::exit;

fn parse_unit(unit: &str) -> i64 {
    let n = unit.parse::<i64>().ok();
    let unit = match n {
        Some(unit) => unit as i64,
        None => 0 as i64,
    };
    unit
}

fn clear_text(lines: u32) {
    for _ in 0..lines {
        println!("");
    }
}

fn convert_time_to_ms(timestamp: &str) -> i64 {
    let mut t: i64 = 0;
    let p = Regex::new(r"(\d{2}):(\d{2}):(\d{2}),(\d{3})").unwrap();
    for cap in p.captures_iter(&timestamp) {
        let hours = parse_unit(&cap.at(1).unwrap());
        let minutes = parse_unit(&cap.at(2).unwrap());
        let seconds = parse_unit(&cap.at(3).unwrap());
        let ms = parse_unit(&cap.at(4).unwrap());
        t = (hours * 3600) + (minutes * 60) + seconds;
        t = (t * 1000) + ms;
    }
    t
}

fn is_valid(data: &str) -> bool {
    let mut valid = false;
    let p = Regex::new(r"^\d+$").unwrap();
    if p.is_match(&data) {
        valid = true
    }
    valid
}

fn parse_subtitles(program: &str, input: &str) -> Vec<Subtitle> {
    let f = File::open(input).unwrap();
    let file = BufReader::new(&f);
    let mut lines: Vec<String> = Vec::new();
    for line in file.lines() {
        let l = line.unwrap().to_string();
        if !l.is_empty() {
            lines.push(l);
        }
    }
    if !is_valid(&lines[0]) {
        display_error(&program, "Input file is not valid subtitles");
    }

    let mut seqs: Vec<i64> = Vec::new();
    let mut starts: Vec<i64> = Vec::new();
    let mut ends: Vec<i64> = Vec::new();
    let mut contents: Vec<String> = Vec::new();
    for l in lines {
        let mut p = Regex::new(r"^\d+$").unwrap();
        let mut is_timecode = false;
        if p.is_match(&l) {
            seqs.push(parse_unit(&l));
            continue;
        }
        p = Regex::new(r"(\d{2}:\d{2}:\d{2},\d{3})\s-->\s(\d{2}:\d{2}:\d{2},\d{3})").unwrap();
        for cap in p.captures_iter(&l) {
            starts.push(convert_time_to_ms(&cap.at(1).unwrap()));
            ends.push(convert_time_to_ms(&cap.at(2).unwrap()));
            is_timecode = true;
            continue;
        }

        p = Regex::new(r"^[\d-A-Za-z'\s]+").unwrap();
        if p.is_match(&l) && !is_timecode {
            contents.push(l.clone());
            continue;
        }
        else {
            contents.push("|".to_string());
        }
    }

    let contents = contents.join("\n");
    let split = contents.split("|");
    let mut text: Vec<String> = Vec::new();
    for c in split {
        if !c.is_empty() {
            text.push(c.to_string());
        }
    }

    let mut subtitles: Vec<Subtitle> = Vec::new();
    for i in 0..seqs.len() {
        subtitles.push(Subtitle::new(seqs[i], starts[i], ends[i], &text[i]));
    }
    subtitles
}

fn playback_subtitles(program: &str, input: &str, use_clock: bool) {
    let subtitles: Vec<Subtitle> = parse_subtitles(&program, &input);
    let runtime = subtitles[subtitles.len() - 1].get_end();
    let mut clock = Clock::new();
    clock.set_time_ms(runtime);
    clear_text(50);
    println!("Playing back: '{}' (Runtime: {} [{}ms])...", input, clock.get_time(), runtime);
    thread::sleep_ms(3000);
    clock.set_time_ms(0);
    println!("{}", clock.get_time());
    clear_text(50);
    let sw = Stopwatch::start_new();
    let mut i: usize = 0;
    let mut in_subtitle = false;
    loop {
        let time = sw.elapsed_ms();
        clock.set_time_ms(time);

        if time % 1000 == 0 && use_clock && !in_subtitle {
            clear_text(40);
            println!("{}", clock.get_time());
        }

        if time == subtitles[i].get_start() {
            clear_text(50);
            in_subtitle = true;
            println!("{}", subtitles[i].get_text());
        }
        if time == subtitles[i].get_end() {
            i += 1;
            in_subtitle = false;
            clear_text(50);
        }

        if i == subtitles.len() {
            break;
        }
    }
    exit(0);
}

fn display_usage(program: &str, exit_code: i32) {
    println!("\nsrtcli");
    println!("Utility to playback subtitles on the command line.");
    println!("\nCopyright 2016 Sam Saint-Pettersen.");
    println!("Released under the MIT/X11 License.");
    println!("\nUsage {} -f|--file <file.srt> -c|--clock [-h|--help]", program);
    println!("\n-f|--file: Subtitle file (SubRip Text) to playback.");
    println!("-c|--clock: Display a playback clock.");
    println!("-h|--help: Display this help information and exit.");
    exit(exit_code);
}

fn display_error(program: &str, err: &str) {
    println!("Error: {}.", err);
    display_usage(&program, -1);
}

fn main() {
    let cli = CliOptions::new("srtcli");
    let program = cli.get_program();
    let mut input = String::new();
    let mut use_clock = false;

    if cli.get_num() > 1 {
        for (i, a) in cli.get_args().iter().enumerate() {
            match a.trim() {
                "-h" | "--help" => display_usage(&program, 0),
                "-f" | "--file" => input = cli.next_argument(i),
                "-c" | "--clock" => use_clock = true,
                _ => continue,
            }
        }

        if input.is_empty() {
            display_error(&program, "No subtitle file specified");
        }

        playback_subtitles(&program, &input, use_clock);
    }
    else {
        display_error(&program, "No options specified");
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate glium;

extern crate cgmath;
extern crate rand;
extern crate num;
extern crate time;

mod world;
mod draw;

use world::terrain::Terrain;
use draw::shaders::ShaderManager;
use draw::display_object::{Drawable,Frame};
use cgmath::{Matrix4,Point3,Vector3};

fn main() {
	use glium::{DisplayBuild, Surface};
	// can not do multisampling due to glutin bug with_multisampling(16)
	let display = glium::glutin::WindowBuilder::new().with_vsync().with_depth_buffer(24).build_glium().unwrap();

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

	// perspective_matrix
	let display_size = display.get_window().unwrap().get_inner_size_pixels().unwrap();
	let mut perspective_matrix:Matrix4<f32> = cgmath::perspective(cgmath::deg(45.0),display_size.0 as f32/display_size.1 as f32,0.0001,100.0);

	// view matrix
	let mut camera_position:Point3<f32> = Point3::new(0.0, 2.0, 2.0);
	let mut camera_target:Point3<f32> = Point3::new(0.0, 0.0, 0.0);
	let mut camera_up:Vector3<f32> = Vector3::unit_y();
	let mut view_matrix:Matrix4<f32> = cgmath::Matrix4::look_at(camera_position, camera_target, camera_up);

	// setup the shaders
	let mut shader_manager = ShaderManager::new(&display);

	// create terrain
	let terrain = Terrain::new(&display,&mut shader_manager,5);

    // listen for events produced in the window and wait to be received
    let mut t:u64 = time::precise_time_ns();
    loop {
    	let nt = time::precise_time_ns();
    	let dt = nt - t;
    	t = nt;

    	// update position
    	camera_position.y += (dt as f32/16000000 as f32) / 5 as f32;
    	camera_position.z += (dt as f32/16000000 as f32) / 5 as f32;
    	view_matrix = cgmath::Matrix4::look_at(camera_position, camera_target, camera_up);
    	//z += (dt as f32/16000000 as f32) / 5 as f32;

    	// get reference to the frame
    	let mut target = display.draw();

    	// clear the background
    	target.clear_color_and_depth((0.0, 0.0, 0.0, 1.0),1.0);

    	// draw the terrain
    	let mvp_matrix = perspective_matrix * view_matrix;
    	terrain.draw(&mut target,&params,&mvp_matrix);

    	// finish drawing and destroy frame object
    	target.finish().unwrap();

    	// render loop
	    for ev in display.poll_events(){
	    	match ev {
	    		glium::glutin::Event::Closed => return,
	    		glium::glutin::Event::Resized(width, height) => {
	    			// update the perspective_matrix
	    			perspective_matrix = cgmath::perspective(cgmath::deg(45.0),width as f32/height as f32,0.0001,100.0);
	    		},
	    		_ => ()
	    	}
	    }
    }
}<commit_msg>Multisampling is back<commit_after>#[macro_use]
extern crate glium;

extern crate cgmath;
extern crate rand;
extern crate num;
extern crate time;

mod world;
mod draw;

use world::terrain::Terrain;
use draw::shaders::ShaderManager;
use draw::display_object::{Drawable,Frame};
use cgmath::{Matrix4,Point3,Vector3};

fn main() {
	use glium::{DisplayBuild, Surface};
	// can not do multisampling due to glutin bug with_multisampling(16)
	let display = glium::glutin::WindowBuilder::new().with_vsync().with_multisampling(16).with_depth_buffer(24).build_glium().unwrap();

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

	// perspective_matrix
	let display_size = display.get_window().unwrap().get_inner_size_pixels().unwrap();
	let mut perspective_matrix:Matrix4<f32> = cgmath::perspective(cgmath::deg(45.0),display_size.0 as f32/display_size.1 as f32,0.0001,100.0);

	// view matrix
	let mut camera_position:Point3<f32> = Point3::new(0.0, 2.0, 2.0);
	let mut camera_target:Point3<f32> = Point3::new(0.0, 0.0, 0.0);
	let mut camera_up:Vector3<f32> = Vector3::unit_y();
	let mut view_matrix:Matrix4<f32> = cgmath::Matrix4::look_at(camera_position, camera_target, camera_up);

	// setup the shaders
	let mut shader_manager = ShaderManager::new(&display);

	// create terrain
	let terrain = Terrain::new(&display,&mut shader_manager,5);

    // listen for events produced in the window and wait to be received
    let mut t:u64 = time::precise_time_ns();
    loop {
    	let nt = time::precise_time_ns();
    	let dt = nt - t;
    	t = nt;

    	// update position
    	camera_position.y += (dt as f32/16000000 as f32) / 5 as f32;
    	camera_position.z += (dt as f32/16000000 as f32) / 5 as f32;
    	view_matrix = cgmath::Matrix4::look_at(camera_position, camera_target, camera_up);
    	//z += (dt as f32/16000000 as f32) / 5 as f32;

    	// get reference to the frame
    	let mut target = display.draw();

    	// clear the background
    	target.clear_color_and_depth((0.0, 0.0, 0.0, 1.0),1.0);

    	// draw the terrain
    	let mvp_matrix = perspective_matrix * view_matrix;
    	terrain.draw(&mut target,&params,&mvp_matrix);

    	// finish drawing and destroy frame object
    	target.finish().unwrap();

    	// render loop
	    for ev in display.poll_events(){
	    	match ev {
	    		glium::glutin::Event::Closed => return,
	    		glium::glutin::Event::Resized(width, height) => {
	    			// update the perspective_matrix
	    			perspective_matrix = cgmath::perspective(cgmath::deg(45.0),width as f32/height as f32,0.0001,100.0);
	    		},
	    		_ => ()
	    	}
	    }
    }
}<|endoftext|>