<commit_before>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::path::posix::Path;
use std::io::stdin;
use std::option::Option;
use std::io::process;
use extra::getopts;

struct Shell {
    cmd_prompt: ~str,
    history: ~[~str],
}

struct Process {
    command: ~str,
    args: ~[~str],
    exit_status: Option<process::ProcessExit>,
}

struct BackgroundProcess {
    command: ~str,
    args: ~[~str],
    background: bool,
    exit_status: Option<process::ProcessExit>,
    io_port: Option<Port<Option <process::ProcessExit>>>,
}

trait Command {
    fn run(&mut self);
    fn cmd_exists(&mut self) -> bool;
}

impl Process {
    fn new(program: &str, args: ~[~str]) -> Process {
        let cmd = Process {
            command: program.to_owned(),
            args: args.to_owned(),
            exit_status: None,
        };
        cmd
    }
}

impl BackgroundProcess {
    fn new(program: &str, args: ~[~str]) -> BackgroundProcess {
        let cmd = BackgroundProcess {
            command: program.to_owned(),
            args: args.to_owned(),
            background: false,
            exit_status: None,
            io_port: None,
        };
        cmd
    }
}

impl Command for Process {
    fn run(&mut self) {
        if self.cmd_exists() {
            run::process_status(self.command, self.args);
        }
        else {
            println!("{:s}: command not found", self.command);
        }
    }

    fn cmd_exists(&mut self) -> bool {
        let ret = run::process_output("which", [self.command.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }
}

impl Command for BackgroundProcess {
    fn run(&mut self) {
        if self.cmd_exists() {
            match self.background {
                true => {
                    let (port, chan) :
                        (Port<Option<process::ProcessExit>>,
                         Chan<Option<process::ProcessExit>>)
                        = Chan::new();
                    let command = self.command.to_owned();
                    let args = self.args.to_owned();
                    spawn(proc() {
                        chan.send(run::process_status(command, args));
                    });
                    self.io_port = Some(port);
                }
                false => {
                    run::process_status(self.command, self.args);
                }
            }
        } else {
            println!("{:s}: command not found", self.command);
        }
    }

    fn cmd_exists(&mut self) -> bool {
        let ret = run::process_output("which", [self.command.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            history: ~[]
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            // Push run commands onto the history stack
            match program {
                "" => {}
                _  => { self.push_hist(cmd_line) }
            }
            match program {
                ""        =>  { continue; }
                "exit"    =>  { return; }
                "history" =>  { self.show_hist(); }
                "cd"      =>  { self.chdir(cmd_line); }
                _         =>  { self.run_cmdline(cmd_line); }
            }
        }
    }

    fn push_hist(&mut self, cmd_line: &str) {
        &self.history.push(cmd_line.to_owned());
    }

    fn show_hist(&mut self) {
        println!("{:s}", self.get_hist());
    }

    fn get_hist(&mut self) -> ~str {
        let mut hist = ~"";
        for i in self.history.iter() {
            let s = i.to_owned();
            match hist {
                ~"" => { hist = s; }
                _   => { hist = hist + "\n" + s; }
            }
        }
        return hist
    }

    fn chdir(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != ""
                {
                    Some(x.to_owned())
                }
                else {
                    None
                }).to_owned_vec();
        if argv.len() > 0 {
            argv.remove(0);
            let path = Path::new(argv[0]);
            os::change_dir(&path);
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != ""
                {
                    Some(x.to_owned())
                }
                else {
                    None
                }).to_owned_vec();
        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            if argv.len() > 0 {
                let last = argv.last().to_owned();
                if last == ~"&" {
                    argv.pop();
                    let mut process = BackgroundProcess::new(program, argv);
                    process.run();
                }
                else {
                    let mut process = Process::new(program, argv);
                    process.run();
                }
            }
        }
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<commit_msg>theoretically kind of working backgrounding<commit_after>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::path::posix::Path;
use std::io::stdin;
use std::option::Option;
use std::io::process;
use std::io::process::ProcessExit;
use std::run::ProcessOptions;
use extra::getopts;

struct Shell {
    cmd_prompt: ~str,
    history: ~[~str],
    processes : ~[~Command],
}

struct Process {
    command: ~str,
    args: ~[~str],
    exit_status: Option<process::ProcessExit>,
}

struct BackgroundProcess {
    command: ~str,
    args: ~[~str],
    exit_status: Option<ProcessExit>,
    io_port: Option<Port<Option <ProcessExit>>>,
}

trait Command {
    fn run(&mut self);
    fn cmd_exists(&mut self) -> bool;
}

impl Process {
    fn new(program: &str, args: ~[~str]) -> Process {
        let cmd = Process {
            command: program.to_owned(),
            args: args.to_owned(),
            exit_status: None,
        };
        cmd
    }
}

impl BackgroundProcess {
    fn new(program: &str, args: ~[~str]) -> BackgroundProcess {
        let cmd = BackgroundProcess {
            command: program.to_owned(),
            args: args.to_owned(),
            exit_status: None,
            io_port: None,
        };
        cmd
    }
}

impl Command for Process {
    fn run(&mut self) {
        if self.cmd_exists() {
            println("Running process.");
            run::process_status(self.command, self.args);
        }
        else {
            println!("{:s}: command not found", self.command);
        }
    }

    fn cmd_exists(&mut self) -> bool {
        let ret = run::process_output("which", [self.command.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }
}

impl Command for BackgroundProcess {
    fn run(&mut self) {
        if self.cmd_exists() {
            println!("Running {:s} in background.", self.command);
            let (port, chan) :
                (Port<Option<ProcessExit>>,
                    Chan<Option<ProcessExit>>)
                = Chan::new();
            let command = self.command.to_owned();
            let args = self.args.to_owned();
            spawn(proc() {
                let output = run::process_status(command, args);
                match output {
                    Some(ecode) => {
                        if (ecode.success()) {
                            println("Process returned success.");
                        }
                        else {
                            println("Process returned failure.");
                        }
                    }
                    None => {
                        println!("Process returned nothing.");
                    }
                };
                chan.send(output);
            });
            self.io_port = Some(port);
        }
        else {
            println!("{:s}: command not found", self.command);
        }
    }

    fn cmd_exists(&mut self) -> bool {
        let ret = run::process_output("which", [self.command.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            history: ~[],
            processes: ~[],
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            // Push run commands onto the history stack
            match program {
                "" => {}
                _  => { self.push_hist(cmd_line) }
            }
            match program {
                ""        =>  { continue; }
                "exit"    =>  { return; }
                "history" =>  { self.show_hist(); }
                "cd"      =>  { self.chdir(cmd_line); }
                _         =>  { self.run_cmdline(cmd_line); }
            }
        }
    }

    fn push_hist(&mut self, cmd_line: &str) {
        &self.history.push(cmd_line.to_owned());
    }

    fn show_hist(&mut self) {
        println!("{:s}", self.get_hist());
    }

    fn get_hist(&mut self) -> ~str {
        let mut hist = ~"";
        for i in self.history.iter() {
            let s = i.to_owned();
            match hist {
                ~"" => { hist = s; }
                _   => { hist = hist + "\n" + s; }
            }
        }
        return hist
    }

    fn chdir(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != ""
                {
                    Some(x.to_owned())
                }
                else {
                    None
                }).to_owned_vec();
        if argv.len() > 0 {
            argv.remove(0);
            let path = Path::new(argv[0]);
            os::change_dir(&path);
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != ""
                {
                    Some(x.to_owned())
                }
                else {
                    None
                }).to_owned_vec();
        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            if argv.len() > 0 {
                let last = argv.last().to_owned();
                if last == ~"&" {
                    argv.pop();
                    let mut process = BackgroundProcess::new(program, argv);
                    process.run();
                }
                else {
                    let mut process = Process::new(program, argv);
                    process.run();
                }
            }
            else {
                self.add_process(~Process::new(program, ~[]) as ~Command);
            }
        }
    }

    fn add_process(&mut self, mut process : ~Command) {
        &process.run();
        self.processes.push(process);
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<|endoftext|>


<commit_before>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::path::posix::Path;
use std::io::stdin;
use std::option::Option;
use std::io::process;
use std::io::{IoError, io_error};
use std::run::Process;
use std::io::process::ProcessExit;
use std::run::ProcessOptions;
use extra::getopts;

struct Shell {
    cmd_prompt : ~str,
    history    : ~[~str],
    processes  : ~[~BackgroundProcess],
}

struct CmdProcess {
    command     : ~str,
    args        : ~[~str],
    exit_status : Option<process::ProcessExit>,
}

struct BackgroundProcess {
    command      : ~str,
    args         : ~[~str],
    exit_status  : Option<ProcessExit>,
    exit_port    : Option<Port<ProcessExit>>,
    kill_chan    : Option<Chan<int>>,
}

fn cmd_exists(command : &str) -> bool {
    let ret = run::process_output("which", [command.to_owned()]);
    return ret.expect("exit code error.").status.success();
}

fn is_dead(exit_port : &Option<Port<ProcessExit>>) -> bool {
    let mut dead = false;
    match *exit_port {
        Some(ref p) => {
            match p.try_recv() {
                Some (exitstatus) => {
                    if (exitstatus.success()) {
                        dead = true;
                    }
                },
                _ => {}
            }
        },
        _ => {},
    };
    dead
}

trait Command {
    fn run(&mut self);
}

impl CmdProcess {
    fn new(command: &str, args: ~[~str]) -> Option<CmdProcess> {
        if (cmd_exists(command)) {
            Some(CmdProcess {
                command: command.to_owned(),
                args: args.to_owned(),
                exit_status: None,
            })
        }
        else { None }
    }
}

impl BackgroundProcess {
    fn new(command: &str, args: ~[~str]) -> Option<BackgroundProcess> {
        if (cmd_exists(command)) {
            Some(BackgroundProcess {
                command: command.to_owned(),
                args: args.to_owned(),
                exit_status: None,
                exit_port: None,
                kill_chan: None,
            })
        }
        else { None }
    }
}

impl Command for CmdProcess {
    fn run(&mut self) {
        self.exit_status = run::process_status(self.command, self.args);
    }
}

impl Command for BackgroundProcess {
    fn run(&mut self) {
        let (port, chan) : (Port<ProcessExit>, Chan<ProcessExit>)
                = Chan::new();
        let (killport, killchan) : (Port<int>, Chan<int>) = Chan::new();
        let command = self.command.to_owned();
        let args = self.args.to_owned();
        spawn(proc() {
            let options = ProcessOptions {
                env    : None,
                dir    : None,
                in_fd  : None,
                out_fd : None,
                err_fd : None,
            };
            let maybe_process = Process::new(command, args, options);
            match maybe_process {
                Some(mut process) => {
                    let signal = killport.recv();
                    let mut error = None;
                    match signal {
                        9 => {
                            io_error::cond.trap(|e: IoError| {
                                error = Some(e);
                                }).inside(|| {
                                    process.force_destroy()
                                })
                        }
                        15 => {
                            io_error::cond.trap(|e: IoError| {
                                error = Some(e);
                                }).inside(|| {
                                    process.force_destroy()
                                })
                        }
                        _ => {}
                    }
                    chan.try_send_deferred(process.finish());
                }
                None => {
                }
            }
        });
        self.exit_port = Some(port);
        self.kill_chan = Some(killchan);
    }

}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            history: ~[],
            processes: ~[],
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");
            self.kill_dead();
            match program {
                "" => {}
                _  => { self.push_hist(cmd_line) }
            }
            match program {
                ""        =>  { continue; }
                "exit"    =>  {
                    self.kill_all();
                    return;
                }
                "history" =>  { self.show_hist(); }
                "cd"      =>  { self.chdir(cmd_line); }
                _         =>  { self.run_cmdline(cmd_line); }
            }
        }
    }

    fn kill_dead(&mut self) {
        let mut dead : ~[uint];
        dead = ~[];
        let mut i = 0;
        for cmd in self.processes.iter() {
            if is_dead(&cmd.exit_port) {
                dead.push(i);
            }
            i += 1;
        }
        for &p in dead.iter() {
            self.processes.remove(p);
        }
    }

    fn kill_all(&mut self) {
        for p in self.processes.iter() {
            match p.kill_chan {
                Some(ref kill_channel) => {
                    kill_channel.try_send_deferred(15);
                }
                None => {}
            }

        }
    }

    fn push_hist(&mut self, cmd_line: &str) {
        &self.history.push(cmd_line.to_owned());
    }

    fn show_hist(&mut self) {
        println!("{:s}", self.get_hist());
    }

    fn get_hist(&mut self) -> ~str {
        let mut hist = ~"";
        for i in self.history.iter() {
            let s = i.to_owned();
            match hist {
                ~"" => { hist = s; }
                _   => { hist = hist + "\n" + s; }
            }
        }
        return hist
    }

    fn chdir(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != ""
                {
                    Some(x.to_owned())
                }
                else {
                    None
                }).to_owned_vec();
        if argv.len() > 0 {
            argv.remove(0);
            let path = Path::new(argv[0]);
            os::change_dir(&path);
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != ""
                {
                    Some(x.to_owned())
                }
                else {
                    None
                }).to_owned_vec();
        if argv.len() > 0 {
            self.parse_process(argv);
        }
    }

    fn parse_process(&mut self, mut argv : ~[~str]) {
        let program: ~str = argv.remove(0);
        if argv.len() > 0 {
            let last = argv.last().to_owned();
            if last == ~"&" {
                argv.pop();
                self.make_bg_process(program, argv);
            }
            else {
                self.make_fg_process(program, argv);
            }
        }
        else {
            self.make_fg_process(program, argv);
        }
    }

    fn make_fg_process(&mut self, program : ~str, argv : ~[~str]) {
        match CmdProcess::new(program, argv) {
            Some(mut process) => { process.run(); }
            None              => { }
        }
    }

    fn make_bg_process(&mut self, program : ~str, argv : ~[~str]) {
        match BackgroundProcess::new(program, argv) {
            Some(process) => {self.add_process(~process);}
            None          => { }
        }
    }

    fn add_process(&mut self, mut process : ~BackgroundProcess) {
        &process.run();
        self.processes.push(process);
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                Some(cmd_str) => {cmd_str.to_owned()},
                None          => {~""}
        };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<commit_msg>group similar code<commit_after>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::path::posix::Path;
use std::io::stdin;
use std::option::Option;
use std::io::process;
use std::io::{IoError, io_error};
use std::run::Process;
use std::io::process::ProcessExit;
use std::run::ProcessOptions;
use extra::getopts;

fn cmd_exists(command : &str) -> bool {
    let ret = run::process_output("which", [command.to_owned()]);
    return ret.expect("exit code error.").status.success();
}

fn is_dead(exit_port : &Option<Port<ProcessExit>>) -> bool {
    let mut dead = false;
    match *exit_port {
        Some(ref p) => {
            match p.try_recv() {
                Some (exitstatus) => {
                    if (exitstatus.success()) {
                        dead = true;
                    }
                },
                _ => {}
            }
        },
        _ => {},
    };
    dead
}

trait Command {
    fn run(&mut self);
}

struct CmdProcess {
    command     : ~str,
    args        : ~[~str],
    exit_status : Option<process::ProcessExit>,
}
impl CmdProcess {
    fn new(command: &str, args: ~[~str]) -> Option<CmdProcess> {
        if (cmd_exists(command)) {
            Some(CmdProcess {
                command: command.to_owned(),
                args: args.to_owned(),
                exit_status: None,
            })
        }
        else { None }
    }
}
impl Command for CmdProcess {
    fn run(&mut self) {
        self.exit_status = run::process_status(self.command, self.args);
    }
}

struct BackgroundProcess {
    command      : ~str,
    args         : ~[~str],
    exit_status  : Option<ProcessExit>,
    exit_port    : Option<Port<ProcessExit>>,
    kill_chan    : Option<Chan<int>>,
}
impl BackgroundProcess {
    fn new(command: &str, args: ~[~str]) -> Option<BackgroundProcess> {
        if (cmd_exists(command)) {
            Some(BackgroundProcess {
                command: command.to_owned(),
                args: args.to_owned(),
                exit_status: None,
                exit_port: None,
                kill_chan: None,
            })
        }
        else { None }
    }
}
impl Command for BackgroundProcess {
    fn run(&mut self) {
        let (port, chan) : (Port<ProcessExit>, Chan<ProcessExit>)
                = Chan::new();
        let (killport, killchan) : (Port<int>, Chan<int>) = Chan::new();
        let command = self.command.to_owned();
        let args = self.args.to_owned();
        spawn(proc() {
            let options = ProcessOptions {
                env    : None,
                dir    : None,
                in_fd  : None,
                out_fd : None,
                err_fd : None,
            };
            let maybe_process = Process::new(command, args, options);
            match maybe_process {
                Some(mut process) => {
                    let signal = killport.recv();
                    let mut error = None;
                    match signal {
                        9 => {
                            io_error::cond.trap(|e: IoError| {
                                error = Some(e);
                                }).inside(|| {
                                    process.force_destroy()
                                })
                        }
                        15 => {
                            io_error::cond.trap(|e: IoError| {
                                error = Some(e);
                                }).inside(|| {
                                    process.force_destroy()
                                })
                        }
                        _ => {}
                    }
                    chan.try_send_deferred(process.finish());
                }
                None => {
                }
            }
        });
        self.exit_port = Some(port);
        self.kill_chan = Some(killchan);
    }
}

struct Shell {
    cmd_prompt : ~str,
    history    : ~[~str],
    processes  : ~[~BackgroundProcess],
}
impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            history: ~[],
            processes: ~[],
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");
            self.kill_dead();
            match program {
                "" => {}
                _  => { self.push_hist(cmd_line) }
            }
            match program {
                ""        =>  { continue; }
                "exit"    =>  {
                    self.kill_all();
                    return;
                }
                "history" =>  { self.show_hist(); }
                "cd"      =>  { self.chdir(cmd_line); }
                _         =>  { self.run_cmdline(cmd_line); }
            }
        }
    }

    fn kill_dead(&mut self) {
        let mut dead : ~[uint];
        dead = ~[];
        let mut i = 0;
        for cmd in self.processes.iter() {
            if is_dead(&cmd.exit_port) {
                dead.push(i);
            }
            i += 1;
        }
        for &p in dead.iter() {
            self.processes.remove(p);
        }
    }

    fn kill_all(&mut self) {
        for p in self.processes.iter() {
            match p.kill_chan {
                Some(ref kill_channel) => {
                    kill_channel.try_send_deferred(15);
                }
                None => {}
            }

        }
    }

    fn push_hist(&mut self, cmd_line: &str) {
        &self.history.push(cmd_line.to_owned());
    }

    fn show_hist(&mut self) {
        println!("{:s}", self.get_hist());
    }

    fn get_hist(&mut self) -> ~str {
        let mut hist = ~"";
        for i in self.history.iter() {
            let s = i.to_owned();
            match hist {
                ~"" => { hist = s; }
                _   => { hist = hist + "\n" + s; }
            }
        }
        return hist
    }

    fn chdir(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != ""
                {
                    Some(x.to_owned())
                }
                else {
                    None
                }).to_owned_vec();
        if argv.len() > 0 {
            argv.remove(0);
            let path = Path::new(argv[0]);
            os::change_dir(&path);
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != ""
                {
                    Some(x.to_owned())
                }
                else {
                    None
                }).to_owned_vec();
        if argv.len() > 0 {
            self.parse_process(argv);
        }
    }

    fn parse_process(&mut self, mut argv : ~[~str]) {
        let program: ~str = argv.remove(0);
        if argv.len() > 0 {
            let last = argv.last().to_owned();
            if last == ~"&" {
                argv.pop();
                self.make_bg_process(program, argv);
            }
            else {
                self.make_fg_process(program, argv);
            }
        }
        else {
            self.make_fg_process(program, argv);
        }
    }

    fn make_fg_process(&mut self, program : ~str, argv : ~[~str]) {
        match CmdProcess::new(program, argv) {
            Some(mut process) => { process.run(); }
            None              => { }
        }
    }

    fn make_bg_process(&mut self, program : ~str, argv : ~[~str]) {
        match BackgroundProcess::new(program, argv) {
            Some(process) => {self.add_process(~process);}
            None          => { }
        }
    }

    fn add_process(&mut self, mut process : ~BackgroundProcess) {
        &process.run();
        self.processes.push(process);
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                Some(cmd_str) => {cmd_str.to_owned()},
                None          => {~""}
        };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A group of side offsets, which correspond to top/left/bottom/right for borders, padding,
//! and margins in CSS.

use std::num::Zero;

/// A group of side offsets, which correspond to top/left/bottom/right for borders, padding,
/// and margins in CSS.
#[deriving(Clone, Eq)]
pub struct SideOffsets2D<T> {
    top: T,
    right: T,
    bottom: T,
    left: T,
}

impl<T> SideOffsets2D<T> {
    pub fn new(top: T, right: T, bottom: T, left: T) -> SideOffsets2D<T> {
        SideOffsets2D {
            top: top,
            right: right,
            bottom: bottom,
            left: left,
        }
    }
}

impl<T:Clone> SideOffsets2D<T> {
    pub fn new_all_same(all: T) -> SideOffsets2D<T> {
        SideOffsets2D::new(all.clone(), all.clone(), all.clone(), all.clone())
    }
}

impl<T:Num> SideOffsets2D<T> {
    pub fn horizontal(&self) -> T {
        self.left + self.right
    }

    pub fn vertical(&self) -> T {
        self.top + self.bottom
    }
}

impl<T:Num> Add<SideOffsets2D<T>, SideOffsets2D<T>> for SideOffsets2D<T> {
    fn add(&self, other: &SideOffsets2D<T>) -> SideOffsets2D<T> {
        SideOffsets2D {
            top: self.top + other.top,
            right: self.right + other.right,
            bottom: self.bottom + other.bottom,
            left: self.left + other.left,
        }
    }
}

impl<T:Num> Zero for SideOffsets2D<T> {
    fn zero() -> SideOffsets2D<T> {
        SideOffsets2D {
            top: Zero::zero(),
            right: Zero::zero(),
            bottom: Zero::zero(),
            left: Zero::zero(),
        }
    }

    fn is_zero(&self) -> bool {
        self.top.is_zero() && self.right.is_zero() && self.bottom.is_zero() && self.left.is_zero()
    }
}
<commit_msg>Rust upgrade - fix privacy<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A group of side offsets, which correspond to top/left/bottom/right for borders, padding,
//! and margins in CSS.

use std::num::Zero;

/// A group of side offsets, which correspond to top/left/bottom/right for borders, padding,
/// and margins in CSS.
#[deriving(Clone, Eq)]
pub struct SideOffsets2D<T> {
    pub top: T,
    pub right: T,
    pub bottom: T,
    pub left: T,
}

impl<T> SideOffsets2D<T> {
    pub fn new(top: T, right: T, bottom: T, left: T) -> SideOffsets2D<T> {
        SideOffsets2D {
            top: top,
            right: right,
            bottom: bottom,
            left: left,
        }
    }
}

impl<T:Clone> SideOffsets2D<T> {
    pub fn new_all_same(all: T) -> SideOffsets2D<T> {
        SideOffsets2D::new(all.clone(), all.clone(), all.clone(), all.clone())
    }
}

impl<T:Num> SideOffsets2D<T> {
    pub fn horizontal(&self) -> T {
        self.left + self.right
    }

    pub fn vertical(&self) -> T {
        self.top + self.bottom
    }
}

impl<T:Num> Add<SideOffsets2D<T>, SideOffsets2D<T>> for SideOffsets2D<T> {
    fn add(&self, other: &SideOffsets2D<T>) -> SideOffsets2D<T> {
        SideOffsets2D {
            top: self.top + other.top,
            right: self.right + other.right,
            bottom: self.bottom + other.bottom,
            left: self.left + other.left,
        }
    }
}

impl<T:Num> Zero for SideOffsets2D<T> {
    fn zero() -> SideOffsets2D<T> {
        SideOffsets2D {
            top: Zero::zero(),
            right: Zero::zero(),
            bottom: Zero::zero(),
            left: Zero::zero(),
        }
    }

    fn is_zero(&self) -> bool {
        self.top.is_zero() && self.right.is_zero() && self.bottom.is_zero() && self.left.is_zero()
    }
}
<|endoftext|>


<commit_before>extern crate "parser-combinators" as parser_combinators;

use self::parser_combinators::{try, between, spaces, parser, many, many1, digit, optional, hex_digit, not_followed_by, satisfy, Parser, ParserExt, ParseResult};
use self::parser_combinators::primitives::{State, Stream};
use super::ast::*;
use super::ast::ExprNode::*;
use std::str::FromStr;
use std::num::FromStrRadix;

fn sint_const<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {
        optional(satisfy(|c| c == '-'))
            .and(
                (satisfy(|c| c == '0')
                    .and(satisfy(|c| c == 'x' || c == 'X')))
                    .with(many1::<Vec<_>, _>(hex_digit()))
                    .map(|x| {
                        isize::from_str_radix(
                            x.iter()
                             .fold(
                                String::new(),
                                |mut s: String, i| { s.push(*i); s })
                             .as_slice(),
                        16).unwrap()
                    })
                .or( many1::<Vec<_>, _>(digit()).map(|x|
                    isize::from_str(x.iter().fold(
                        String::new(), |mut s: String, i| { s.push(*i); s })
                        .as_slice()
                    ).unwrap()
                    )
                )
                )
            .map(|x| {
                if let Some(sign) = x.0 {
                    let mut s = String::new();
                    s.push(sign);
                    s.push('1');
                    x.1 * isize::from_str(s.as_slice()).unwrap()
                } else {
                    x.1
                }
                })
            .skip(not_followed_by(satisfy(|c| c == 'u' || c == 'U' || c == '.')))
            .map(|x: isize| NumNode::IntConst(IntNode{value: x}))
            .parse_state(input)
}

fn uint_const<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {
        (satisfy(|c| c == '0')
            .and(satisfy(|c| c == 'x' || c == 'X')))
            .with(many1::<Vec<_>, _>(hex_digit()))
            .map(|x| usize::from_str_radix(
                    x.iter()
                     .fold(
                        String::new(),
                        |mut s: String, i| { s.push(*i); s })
                     .as_slice(),
                16).unwrap()
            )
        .or( many1::<Vec<_>, _>(digit())
            .map(|x|usize::from_str(x.iter().fold(
                String::new(), |mut s: String, i| { s.push(*i); s })
                .as_slice()
            ).unwrap())
        )
        .skip(satisfy(|c| c == 'u' || c == 'U'))
        .map(|x: usize| NumNode::UIntConst(UIntNode{value: x}))
        .parse_state(input)
}

fn float_const<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {
        unimplemented!()
}

pub fn number<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {
        try(parser(sint_const))
            .or(try(parser(uint_const)))
            .or(try(parser(float_const)))
            .parse_state(input)
}

pub fn name<I>(input: State<I>) -> ParseResult<NameNode, I>
    where I: Stream<Item=char> {
         let initial = satisfy(|c|
            c.is_alphabetic()
                // R6RS 'special initial' characters
                || c == '!' || c == '$' || c == '%' || c == ':' || c == '^'
                || c == '<' || c == '>' || c == '_' || c == '~' || c == '\\'
                || c == '?');
        let subsequent = satisfy(|c|
            c.is_alphanumeric()
                // R6RS 'special initial' characters
                || c == '!' || c == '$' || c == '%' || c == ':' || c == '^'
                || c == '<' || c == '>' || c == '_' || c == '~' || c == '\\'
                || c == '?'
                // R6RS 'special subsequent' characters
                || c == '+' || c == '-' || c == '.' || c == '@');
        initial
            .and(many::<Vec<_>, _>(subsequent).map(|it|
                it.iter().fold(
                    String::new(),
                    |mut s: String, i| {
                        s.push(*i);
                        s
                    }
                    )
                ))
            .parse_state(input)
            .map(|x| {
                let mut s = String::new();
                s.push((x.0).0);
                s.push_str(&(x.0).1);
                (NameNode{ name: s}, x.1)
            })
}

pub fn expr<I>(input: State<I>) -> ParseResult<ExprNode, I>
    where I: Stream<Item=char> {
        let spaces = spaces();
        let sexpr = between(
            satisfy(|c| c == '('),
            satisfy(|c| c == ')'),
            parser(name)
                .and(many(parser(expr)))
                .map(|x| {
                    SExpr(SExprNode {
                        operator: x.0,
                        operands: x.1
                    })
                })
            );
        spaces.clone().with(
            sexpr
                .or(parser(name).map(Name))
            ).parse_state(input)
}

#[cfg(test)]
mod tests {
    use ::ast::*;
    use ::ast::ExprNode::*;
    use super::*;
    use super::parser_combinators::{Parser,parser};

    #[test]
    fn test_basic_ident() {
        assert_eq!(
            parser(expr).parse("ident").unwrap(),
            (Name(NameNode { name: "ident".to_string() }), "")
            );
    }

    #[test]
    fn test_basic_sexpr() {
        assert_eq!(
            parser(expr).parse("(ident arg1 arg2)").unwrap(),
            (SExpr(SExprNode {
                operator: NameNode { name: "ident".to_string() },
                operands: vec![
                    Name(NameNode { name: "arg1".to_string() }),
                    Name(NameNode { name: "arg2".to_string() })
                ]
            }), "")
            );
    }

    #[test]
    fn test_parse_sint_pos() {
        assert_eq!(
            parser(number).parse("1234"),
            Ok((NumNode::IntConst(IntNode { value: 1234isize }), ""))
            );
    }

    #[test]
    fn test_parse_sint_neg() {
        assert_eq!(
            parser(number).parse("-1234"),
            Ok((NumNode::IntConst(IntNode { value: -1234isize }), ""))
            );
    }

    #[test]
    fn test_parse_sint_hex() {
        assert_eq!(
            parser(number).parse("0x0ff"),
            Ok((NumNode::IntConst(IntNode { value: 0x0ffisize }), ""))
            );
        assert_eq!(
            parser(number).parse("0X0FF"),
            Ok((NumNode::IntConst(IntNode { value: 0x0ffisize }), ""))
            );
    }
    /*
    #[test]
    fn test_parse_sint_bin_upper() {
        assert_eq!(
            parser(number).parse("0B01"),
            Ok((NumNode::IntConst(IntNode { value: 0b01isize }), ""))
            );
        assert_eq!(
            parser(number).parse("0b01"),
            Ok((NumNode::IntConst(IntNode { value: 0b01isize }), ""))
            );
    }*/

    #[test]
    fn test_parse_uint() {
        assert_eq!(
            parser(number).parse("1234u"),
            Ok((NumNode::UIntConst(UIntNode { value: 1234usize }), ""))
            );
        assert_eq!(
            parser(number).parse("4321U"),
            Ok((NumNode::UIntConst(UIntNode { value: 4321usize }), ""))
            );
    }

    #[test]
    fn test_parse_float() {
        assert_eq!(
            parser(number).parse("1.0").unwrap(),
            (NumNode::FloatConst(FloatNode { value: 1.0f64 }), "")
            );
        assert_eq!(
            parser(number).parse("1f").unwrap(),
            (NumNode::FloatConst(FloatNode { value: 1.0f64 }), "")
            );
        assert_eq!(
            parser(number).parse("22.2222").unwrap(),
            (NumNode::FloatConst(FloatNode { value: 22.2222f64 }), "")
            );
        assert_eq!(
            parser(number).parse("22.2222f").unwrap(),
            (NumNode::FloatConst(FloatNode { value: 22.2222f64 }), "")
            );
    }

}
<commit_msg>Add tests for uint hex consts<commit_after>extern crate "parser-combinators" as parser_combinators;

use self::parser_combinators::{try, between, spaces, parser, many, many1, digit, optional, hex_digit, not_followed_by, satisfy, Parser, ParserExt, ParseResult};
use self::parser_combinators::primitives::{State, Stream};
use super::ast::*;
use super::ast::ExprNode::*;
use std::str::FromStr;
use std::num::FromStrRadix;

fn sint_const<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {
        optional(satisfy(|c| c == '-'))
            .and(
                (satisfy(|c| c == '0')
                    .and(satisfy(|c| c == 'x' || c == 'X')))
                    .with(many1::<Vec<_>, _>(hex_digit()))
                    .map(|x| {
                        isize::from_str_radix(
                            x.iter()
                             .fold(
                                String::new(),
                                |mut s: String, i| { s.push(*i); s })
                             .as_slice(),
                        16).unwrap()
                    })
                .or( many1::<Vec<_>, _>(digit()).map(|x|
                    isize::from_str(x.iter().fold(
                        String::new(), |mut s: String, i| { s.push(*i); s })
                        .as_slice()
                    ).unwrap()
                    )
                )
                )
            .map(|x| {
                if let Some(sign) = x.0 {
                    let mut s = String::new();
                    s.push(sign);
                    s.push('1');
                    x.1 * isize::from_str(s.as_slice()).unwrap()
                } else {
                    x.1
                }
                })
            .skip(not_followed_by(satisfy(|c| c == 'u' || c == 'U' || c == '.')))
            .map(|x: isize| NumNode::IntConst(IntNode{value: x}))
            .parse_state(input)
}

fn uint_const<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {
        (satisfy(|c| c == '0')
            .and(satisfy(|c| c == 'x' || c == 'X')))
            .with(many1::<Vec<_>, _>(hex_digit()))
            .map(|x| usize::from_str_radix(
                    x.iter()
                     .fold(
                        String::new(),
                        |mut s: String, i| { s.push(*i); s })
                     .as_slice(),
                16).unwrap()
            )
        .or( many1::<Vec<_>, _>(digit())
            .map(|x|usize::from_str(x.iter().fold(
                String::new(), |mut s: String, i| { s.push(*i); s })
                .as_slice()
            ).unwrap())
        )
        .skip(satisfy(|c| c == 'u' || c == 'U'))
        .map(|x: usize| NumNode::UIntConst(UIntNode{value: x}))
        .parse_state(input)
}

fn float_const<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {
        unimplemented!()
}

pub fn number<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {
        try(parser(sint_const))
            .or(try(parser(uint_const)))
            .or(try(parser(float_const)))
            .parse_state(input)
}

pub fn name<I>(input: State<I>) -> ParseResult<NameNode, I>
    where I: Stream<Item=char> {
         let initial = satisfy(|c|
            c.is_alphabetic()
                // R6RS 'special initial' characters
                || c == '!' || c == '$' || c == '%' || c == ':' || c == '^'
                || c == '<' || c == '>' || c == '_' || c == '~' || c == '\\'
                || c == '?');
        let subsequent = satisfy(|c|
            c.is_alphanumeric()
                // R6RS 'special initial' characters
                || c == '!' || c == '$' || c == '%' || c == ':' || c == '^'
                || c == '<' || c == '>' || c == '_' || c == '~' || c == '\\'
                || c == '?'
                // R6RS 'special subsequent' characters
                || c == '+' || c == '-' || c == '.' || c == '@');
        initial
            .and(many::<Vec<_>, _>(subsequent).map(|it|
                it.iter().fold(
                    String::new(),
                    |mut s: String, i| {
                        s.push(*i);
                        s
                    }
                    )
                ))
            .parse_state(input)
            .map(|x| {
                let mut s = String::new();
                s.push((x.0).0);
                s.push_str(&(x.0).1);
                (NameNode{ name: s}, x.1)
            })
}

pub fn expr<I>(input: State<I>) -> ParseResult<ExprNode, I>
    where I: Stream<Item=char> {
        let spaces = spaces();
        let sexpr = between(
            satisfy(|c| c == '('),
            satisfy(|c| c == ')'),
            parser(name)
                .and(many(parser(expr)))
                .map(|x| {
                    SExpr(SExprNode {
                        operator: x.0,
                        operands: x.1
                    })
                })
            );
        spaces.clone().with(
            sexpr
                .or(parser(name).map(Name))
            ).parse_state(input)
}

#[cfg(test)]
mod tests {
    use ::ast::*;
    use ::ast::ExprNode::*;
    use super::*;
    use super::parser_combinators::{Parser,parser};

    #[test]
    fn test_basic_ident() {
        assert_eq!(
            parser(expr).parse("ident").unwrap(),
            (Name(NameNode { name: "ident".to_string() }), "")
            );
    }

    #[test]
    fn test_basic_sexpr() {
        assert_eq!(
            parser(expr).parse("(ident arg1 arg2)").unwrap(),
            (SExpr(SExprNode {
                operator: NameNode { name: "ident".to_string() },
                operands: vec![
                    Name(NameNode { name: "arg1".to_string() }),
                    Name(NameNode { name: "arg2".to_string() })
                ]
            }), "")
            );
    }

    #[test]
    fn test_parse_sint_pos() {
        assert_eq!(
            parser(number).parse("1234"),
            Ok((NumNode::IntConst(IntNode { value: 1234isize }), ""))
            );
    }

    #[test]
    fn test_parse_sint_neg() {
        assert_eq!(
            parser(number).parse("-1234"),
            Ok((NumNode::IntConst(IntNode { value: -1234isize }), ""))
            );
    }

    #[test]
    fn test_parse_sint_hex() {
        assert_eq!(
            parser(number).parse("0x0ff"),
            Ok((NumNode::IntConst(IntNode { value: 0x0ffisize }), ""))
            );
        assert_eq!(
            parser(number).parse("0X0FF"),
            Ok((NumNode::IntConst(IntNode { value: 0x0ffisize }), ""))
            );
    }
    /*
    #[test]
    fn test_parse_sint_bin_upper() {
        assert_eq!(
            parser(number).parse("0B01"),
            Ok((NumNode::IntConst(IntNode { value: 0b01isize }), ""))
            );
        assert_eq!(
            parser(number).parse("0b01"),
            Ok((NumNode::IntConst(IntNode { value: 0b01isize }), ""))
            );
    }*/

    #[test]
    fn test_parse_uint() {
        assert_eq!(
            parser(number).parse("1234u"),
            Ok((NumNode::UIntConst(UIntNode { value: 1234usize }), ""))
            );
        assert_eq!(
            parser(number).parse("4321U"),
            Ok((NumNode::UIntConst(UIntNode { value: 4321usize }), ""))
            );
    }

    #[test]
    fn test_parse_uint_hex() {
        assert_eq!(
            parser(number).parse("0x0ffu"),
            Ok((NumNode::UIntConst(UIntNode { value: 0x0ffusize }), ""))
            );
        assert_eq!(
            parser(number).parse("0X0FFu"),
            Ok((NumNode::UIntConst(UIntNode { value: 0x0ffusize }), ""))
            );
    }

    #[test]
    fn test_parse_float() {
        assert_eq!(
            parser(number).parse("1.0").unwrap(),
            (NumNode::FloatConst(FloatNode { value: 1.0f64 }), "")
            );
        assert_eq!(
            parser(number).parse("1f").unwrap(),
            (NumNode::FloatConst(FloatNode { value: 1.0f64 }), "")
            );
        assert_eq!(
            parser(number).parse("22.2222").unwrap(),
            (NumNode::FloatConst(FloatNode { value: 22.2222f64 }), "")
            );
        assert_eq!(
            parser(number).parse("22.2222f").unwrap(),
            (NumNode::FloatConst(FloatNode { value: 22.2222f64 }), "")
            );
    }

}
<|endoftext|>


<commit_before>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

//! A module contains test cases of stale peers gc.

use std::time::Duration;
use std::thread;

use kvproto::eraftpb::MessageType;
use kvproto::raft_serverpb::{RegionLocalState, PeerState};
use tikv::raftstore::store::{keys, Peekable};

use super::cluster::{Cluster, Simulator};
use super::node::new_node_cluster;
use super::server::new_server_cluster;
use super::transport_simulate::*;
use super::util::*;

/// A helper function for testing the behaviour of the gc of stale peer
/// which is out of region.
/// If a peer detects the leader is missing for a specified long time,
/// it should consider itself as a stale peer which is removed from the region.
/// This test case covers the following scenario:
/// At first, there are three peer A, B, C in the cluster, and A is leader.
/// Peer B gets down. And then A adds D, E, F int the cluster.
/// Peer D becomes leader of the new cluster, and then removes peer A, B, C.
/// After all these peer in and out, now the cluster has peer D, E, F.
/// If peer B goes up at this moment, it still thinks it is one of the cluster
/// and has peers A, C. However, it could not reach A, C since they are removed from
/// the cluster or probably destroyed.
/// Meantime, D, E, F would not reach B, Since it's not in the cluster anymore.
/// In this case, Peer B would notice that the leader is missing for a long time,
/// and it would check with pd to confirm whether it's still a member of the cluster.
/// If not, it should destroy itself as a stale peer which is removed out already.
fn test_stale_peer_out_of_region<T: Simulator>(cluster: &mut Cluster<T>) {
    // Use a value of 3 seconds as max time here just for test.
    // In production environment, the value of max_leader_missing_duration
    // should be configured far beyond the election timeout.
    let max_leader_missing_duration = Duration::from_secs(3);
    cluster.cfg.raft_store.max_leader_missing_duration = max_leader_missing_duration;
    let pd_client = cluster.pd_client.clone();
    // Disable default max peer number check.
    pd_client.disable_default_rule();

    let r1 = cluster.run_conf_change();
    pd_client.must_add_peer(r1, new_peer(2, 2));
    pd_client.must_add_peer(r1, new_peer(3, 3));
    let (key, value) = (b"k1", b"v1");
    cluster.must_put(key, value);
    assert_eq!(cluster.get(key), Some(value.to_vec()));

    let engine_2 = cluster.get_engine(2);
    must_get_equal(&engine_2, key, value);

    // isolate peer 2 from other part of the cluster
    cluster.add_send_filter(IsolationFilterFactory::new(2));

    // add peer [(4, 4), (5, 5), (6, 6)]
    pd_client.must_add_peer(r1, new_peer(4, 4));
    pd_client.must_add_peer(r1, new_peer(5, 5));
    pd_client.must_add_peer(r1, new_peer(6, 6));

    // remove peer [(1, 1), (2, 2), (3, 3)]
    pd_client.must_remove_peer(r1, new_peer(1, 1));
    pd_client.must_remove_peer(r1, new_peer(2, 2));
    pd_client.must_remove_peer(r1, new_peer(3, 3));

    // recover peer 2 from isolation
    cluster.clear_send_filters();

    // wait for max_leader_missing_duration to timeout
    thread::sleep(max_leader_missing_duration);
    // sleep one more second to make sure there is enough time for the peer to be destroyed
    thread::sleep(Duration::from_secs(1));

    // check whether this region is still functional properly
    let (key2, value2) = (b"k2", b"v2");
    cluster.must_put(key2, value2);
    assert_eq!(cluster.get(key2), Some(value2.to_vec()));

    // check whether peer(2, 2) and its data are destroyed
    must_get_none(&engine_2, key);
    must_get_none(&engine_2, key2);
}

#[test]
fn test_node_stale_peer_out_of_region() {
    let count = 6;
    let mut cluster = new_node_cluster(0, count);
    test_stale_peer_out_of_region(&mut cluster);
}

#[test]
fn test_server_stale_peer_out_of_region() {
    let count = 6;
    let mut cluster = new_server_cluster(0, count);
    test_stale_peer_out_of_region(&mut cluster);
}

/// A help function for testing the behaviour of the gc of stale peer
/// which is out or region.
/// If a peer detects the leader is missing for a specified long time,
/// it should consider itself as a stale peer which is removed from the region.
/// This test case covers the following scenario:
/// A peer, B is initialized as a replicated peer without data after
/// receiving a single raft AE message. But then it goes through some process like
/// the case of `test_stale_peer_out_of_region`, it's removed out of the region
/// and wouldn't be contacted anymore.
/// In both cases, peer B would notice that the leader is missing for a long time,
/// and it's an initialized peer without any data. It would destroy itself as
/// as stale peer directly.
fn test_stale_peer_without_data<T: Simulator>(cluster: &mut Cluster<T>) {
    // Use a value of 3 seconds as max time here just for test.
    // In production environment, the value of max_leader_missing_duration
    // should be configured far beyond the election timeout.
    let max_leader_missing_duration = Duration::from_secs(3);
    cluster.cfg.raft_store.max_leader_missing_duration = max_leader_missing_duration;
    let pd_client = cluster.pd_client.clone();
    // Disable default max peer number check.
    pd_client.disable_default_rule();

    let r1 = cluster.run_conf_change();
    // block peer (2, 2) at receiving snapshot, but not the heartbeat
    cluster.add_send_filter(CloneFilterFactory(RegionPacketFilter::new(1, 2)
        .msg_type(MessageType::MsgSnapshot)));

    pd_client.must_add_peer(r1, new_peer(2, 2));

    // wait for the heartbeat broadcasted from peer (1, 1) to peer (2, 2)
    thread::sleep(Duration::from_millis(60));

    // and then isolate peer (2, 2) from peer (1, 1)
    cluster.add_send_filter(IsolationFilterFactory::new(2));

    // wait for max_leader_missing_duration to timeout
    thread::sleep(max_leader_missing_duration);
    // sleep one more second to make sure there is enough time for the peer to be destroyed
    thread::sleep(Duration::from_secs(1));

    // check whether peer(2, 2) is destroyed
    // if it's destroyed, it will write tomstone into the engine.
    let engine = cluster.get_engine(2);
    let state_key = keys::region_state_key(1);
    let state: RegionLocalState = engine.get_msg(&state_key).unwrap().unwrap();
    assert_eq!(state.get_state(), PeerState::Tombstone);
}

#[test]
fn test_node_stale_peer_without_data() {
    let count = 2;
    let mut cluster = new_node_cluster(0, count);
    test_stale_peer_without_data(&mut cluster);
}

#[test]
fn test_server_stale_peer_without_data() {
    let count = 2;
    let mut cluster = new_server_cluster(0, count);
    test_stale_peer_without_data(&mut cluster);
}
<commit_msg>test/raftstore: fix test case for stale peer gc (#1167)<commit_after>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

//! A module contains test cases of stale peers gc.

use std::time::Duration;
use std::thread;

use kvproto::eraftpb::MessageType;
use kvproto::raft_serverpb::{RegionLocalState, PeerState};
use tikv::raftstore::store::{keys, Peekable};

use super::cluster::{Cluster, Simulator};
use super::node::new_node_cluster;
use super::server::new_server_cluster;
use super::transport_simulate::*;
use super::util::*;

/// A helper function for testing the behaviour of the gc of stale peer
/// which is out of region.
/// If a peer detects the leader is missing for a specified long time,
/// it should consider itself as a stale peer which is removed from the region.
/// This test case covers the following scenario:
/// At first, there are three peer A, B, C in the cluster, and A is leader.
/// Peer B gets down. And then A adds D, E, F int the cluster.
/// Peer D becomes leader of the new cluster, and then removes peer A, B, C.
/// After all these peer in and out, now the cluster has peer D, E, F.
/// If peer B goes up at this moment, it still thinks it is one of the cluster
/// and has peers A, C. However, it could not reach A, C since they are removed from
/// the cluster or probably destroyed.
/// Meantime, D, E, F would not reach B, Since it's not in the cluster anymore.
/// In this case, Peer B would notice that the leader is missing for a long time,
/// and it would check with pd to confirm whether it's still a member of the cluster.
/// If not, it should destroy itself as a stale peer which is removed out already.
fn test_stale_peer_out_of_region<T: Simulator>(cluster: &mut Cluster<T>) {
    // Use a value of 3 seconds as max time here just for test.
    // In production environment, the value of max_leader_missing_duration
    // should be configured far beyond the election timeout.
    let max_leader_missing_duration = Duration::from_secs(3);
    cluster.cfg.raft_store.max_leader_missing_duration = max_leader_missing_duration;
    let pd_client = cluster.pd_client.clone();
    // Disable default max peer number check.
    pd_client.disable_default_rule();

    let r1 = cluster.run_conf_change();
    pd_client.must_add_peer(r1, new_peer(2, 2));
    pd_client.must_add_peer(r1, new_peer(3, 3));
    let (key, value) = (b"k1", b"v1");
    cluster.must_put(key, value);
    assert_eq!(cluster.get(key), Some(value.to_vec()));

    let engine_2 = cluster.get_engine(2);
    must_get_equal(&engine_2, key, value);

    // Isolate peer 2 from other part of the cluster.
    cluster.add_send_filter(IsolationFilterFactory::new(2));

    // Add peer [(4, 4), (5, 5), (6, 6)].
    pd_client.must_add_peer(r1, new_peer(4, 4));
    pd_client.must_add_peer(r1, new_peer(5, 5));
    pd_client.must_add_peer(r1, new_peer(6, 6));

    // Remove peer [(1, 1), (2, 2), (3, 3)].
    pd_client.must_remove_peer(r1, new_peer(1, 1));
    pd_client.must_remove_peer(r1, new_peer(2, 2));
    pd_client.must_remove_peer(r1, new_peer(3, 3));

    // Keep peer 2 isolated. Otherwise whether peer 3 is destroyed or not,
    // it will handle the stale raft message from peer 2 and cause peer 2 to
    // destroy itself earlier than this test case expects.

    // Wait for max_leader_missing_duration to time out.
    thread::sleep(max_leader_missing_duration);
    // Sleep one more second to make sure there is enough time for the peer to be destroyed.
    thread::sleep(Duration::from_secs(1));

    // Check whether this region is still functional properly.
    let (key2, value2) = (b"k2", b"v2");
    cluster.must_put(key2, value2);
    assert_eq!(cluster.get(key2), Some(value2.to_vec()));

    // Check whether peer(2, 2) and its data are destroyed.
    must_get_none(&engine_2, key);
    must_get_none(&engine_2, key2);
    let state_key = keys::region_state_key(1);
    let state: RegionLocalState = engine_2.get_msg(&state_key).unwrap().unwrap();
    assert_eq!(state.get_state(), PeerState::Tombstone);
}

#[test]
fn test_node_stale_peer_out_of_region() {
    let count = 6;
    let mut cluster = new_node_cluster(0, count);
    test_stale_peer_out_of_region(&mut cluster);
}

#[test]
fn test_server_stale_peer_out_of_region() {
    let count = 6;
    let mut cluster = new_server_cluster(0, count);
    test_stale_peer_out_of_region(&mut cluster);
}

/// A help function for testing the behaviour of the gc of stale peer
/// which is out or region.
/// If a peer detects the leader is missing for a specified long time,
/// it should consider itself as a stale peer which is removed from the region.
/// This test case covers the following scenario:
/// A peer, B is initialized as a replicated peer without data after
/// receiving a single raft AE message. But then it goes through some process like
/// the case of `test_stale_peer_out_of_region`, it's removed out of the region
/// and wouldn't be contacted anymore.
/// In both cases, peer B would notice that the leader is missing for a long time,
/// and it's an initialized peer without any data. It would destroy itself as
/// as stale peer directly.
fn test_stale_peer_without_data<T: Simulator>(cluster: &mut Cluster<T>) {
    // Use a value of 3 seconds as max time here just for test.
    // In production environment, the value of max_leader_missing_duration
    // should be configured far beyond the election timeout.
    let max_leader_missing_duration = Duration::from_secs(3);
    cluster.cfg.raft_store.max_leader_missing_duration = max_leader_missing_duration;
    let pd_client = cluster.pd_client.clone();
    // Disable default max peer number check.
    pd_client.disable_default_rule();

    let r1 = cluster.run_conf_change();
    // Block peer (2, 2) at receiving snapshot, but not the heartbeat.
    cluster.add_send_filter(CloneFilterFactory(RegionPacketFilter::new(1, 2)
        .msg_type(MessageType::MsgSnapshot)));

    pd_client.must_add_peer(r1, new_peer(2, 2));

    // Wait for the heartbeat broadcasted from peer (1, 1) to peer (2, 2).
    thread::sleep(Duration::from_millis(60));

    // And then isolate peer (2, 2) from peer (1, 1).
    cluster.add_send_filter(IsolationFilterFactory::new(2));

    // Wait for max_leader_missing_duration to time out.
    thread::sleep(max_leader_missing_duration);
    // Sleep one more second to make sure there is enough time for the peer to be destroyed.
    thread::sleep(Duration::from_secs(1));

    // Check whether peer(2, 2) is destroyed.
    // Before peer 2 is destroyed, a tombstone mark will be written into the engine.
    // So we could check the tombstone mark to make sure peer 2 is destroyed.
    let engine = cluster.get_engine(2);
    let state_key = keys::region_state_key(1);
    let state: RegionLocalState = engine.get_msg(&state_key).unwrap().unwrap();
    assert_eq!(state.get_state(), PeerState::Tombstone);
}

#[test]
fn test_node_stale_peer_without_data() {
    let count = 2;
    let mut cluster = new_node_cluster(0, count);
    test_stale_peer_without_data(&mut cluster);
}

#[test]
fn test_server_stale_peer_without_data() {
    let count = 2;
    let mut cluster = new_server_cluster(0, count);
    test_stale_peer_without_data(&mut cluster);
}
<|endoftext|>


<commit_before>// Copyright 2017 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::VecDeque;
use std::mem;
use std::error::Error;

use bcf;

/// A buffer for BCF records. This allows access regions in a sorted BCF file while iterating
/// over it in a single pass.
/// The buffer is implemented as a ringbuffer, such that extension or movement to the right has
/// linear complexity.
pub struct RecordBuffer {
    reader: bcf::Reader,
    ringbuffer: VecDeque<bcf::Record>,
    ringbuffer2: VecDeque<bcf::Record>,
    last_end: Option<u32>
}

impl RecordBuffer {
    /// Create new buffer.
    pub fn new(reader: bcf::Reader) -> Self {
        RecordBuffer {
            reader: reader,
            ringbuffer: VecDeque::new(),
            ringbuffer2: VecDeque::new(),
            last_end: None
        }
    }

    fn last_rid(&self) -> Option<u32> {
        self.ringbuffer.back().map(|rec| rec.rid().unwrap())
    }

    fn next_rid(&self) -> Option<u32> {
        self.ringbuffer2.back().map(|rec| rec.rid().unwrap())
    }

    fn swap_buffers(&mut self) {
        // swap with buffer for next rid
        mem::swap(&mut self.ringbuffer2, &mut self.ringbuffer);
        // clear second buffer
        self.ringbuffer2.clear();
    }

    fn drain_left(&mut self, rid: u32, window_start: u32) {
        // remove records too far left or from wrong rid
        // rec.rid() will always yield Some(), because otherwise we won't put the rec into the
        // buffer.
        let to_remove = self.ringbuffer.iter().take_while(
            |rec| rec.pos() < window_start || rec.rid().unwrap() != rid
        ).count();
        self.ringbuffer.drain(..to_remove);
    }

    /// Fill the buffer with variants in the given window. The start coordinate has to be left of
    /// the start coordinate of any previous `fill` operation.
    /// Coordinates are 0-based, and end is exclusive.
    pub fn fill(&mut self, chrom: &[u8], start: u32, end: u32) -> Result<(), Box<Error>> {
        let rid = try!(self.reader.header.name2rid(chrom));

        match (self.last_rid(), self.next_rid()) {
            (Some(last_rid), _) => {
                if last_rid != rid {
                    self.swap_buffers();
                } else {
                    self.drain_left(rid, start);
                }
            },
            (_, Some(_)) => {
                self.swap_buffers();
                self.drain_left(rid, start);
            },
            _ => ()
        }

        if !self.ringbuffer2.is_empty() {
            // We have already read beyond the current rid. Hence we can't extend to the right for
            // this rid.
            return Ok(())
        }

        // extend to the right
        loop {
            let mut rec = bcf::Record::new();
            if let Err(e) = self.reader.read(&mut rec) {
                if e.is_eof() {
                    break;
                }
                return Err(Box::new(e));
            }
            let pos = rec.pos();
            if let Some(rec_rid) = rec.rid() {
                if rec_rid == rid {
                    if pos >= end {
                        // Record is beyond our window. Store it anyways but stop.
                        self.ringbuffer.push_back(rec);
                        break;
                    } else if pos >= start {
                        // Record is within our window.
                        self.ringbuffer.push_back(rec);
                    } else {
                        // Record is upstream of our window, ignore it
                        continue
                    }
                } else if rec_rid > rid {
                    // record comes from next rid. Store it in second buffer but stop filling.
                    self.ringbuffer2.push_back(rec);
                    break;
                } else {
                    // Record comes from previous rid. Ignore it.
                    continue;
                }
            } else {
                // skip records without proper rid
                continue;
            }
        }

        self.last_end = Some(end);

        Ok(())
    }

    pub fn fetch(&self) -> Vec<&bcf::Record> {
        // if self.last_end is None, self.ringbuffer is empty
        self.ringbuffer.iter().filter(|rec| rec.pos() < self.last_end.unwrap()).collect()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use bcf;
    use bcf::record::Numeric;

    #[test]
    fn test_buffer() {
        let reader = bcf::Reader::from_path(&"test/test.bcf").unwrap();
        let mut buffer = RecordBuffer::new(reader);

        buffer.fill(b"1", 100, 10023).unwrap();
        let records = buffer.fetch();

        assert_eq!(records.len(), 2);
        assert_eq!(records[0].pos(), 10021);
        assert_eq!(records[1].pos(), 10022);
    }
}
<commit_msg>Improved buffer API.<commit_after>// Copyright 2017 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::{vec_deque, VecDeque};
use std::mem;
use std::error::Error;

use bcf;

/// A buffer for BCF records. This allows access regions in a sorted BCF file while iterating
/// over it in a single pass.
/// The buffer is implemented as a ringbuffer, such that extension or movement to the right has
/// linear complexity. The buffer does not use any indexed random access. Hence, for getting a
/// region at the very end of the BCF, you will have to wait until all records before have
/// been read.
pub struct RecordBuffer {
    reader: bcf::Reader,
    ringbuffer: VecDeque<bcf::Record>,
    ringbuffer2: VecDeque<bcf::Record>,
    overflow: Option<bcf::Record>
}

unsafe impl Sync for RecordBuffer {}
unsafe impl Send for RecordBuffer {}

impl RecordBuffer {
    /// Create new buffer.
    pub fn new(reader: bcf::Reader) -> Self {
        RecordBuffer {
            reader: reader,
            ringbuffer: VecDeque::new(),
            ringbuffer2: VecDeque::new(),
            overflow: None
        }
    }

    fn last_rid(&self) -> Option<u32> {
        self.ringbuffer.back().map(|rec| rec.rid().unwrap())
    }

    fn next_rid(&self) -> Option<u32> {
        self.ringbuffer2.back().map(|rec| rec.rid().unwrap())
    }

    fn swap_buffers(&mut self) {
        // swap with buffer for next rid
        mem::swap(&mut self.ringbuffer2, &mut self.ringbuffer);
        // clear second buffer
        self.ringbuffer2.clear();
    }

    fn drain_left(&mut self, rid: u32, window_start: u32) {
        // remove records too far left or from wrong rid
        // rec.rid() will always yield Some(), because otherwise we won't put the rec into the
        // buffer.
        let to_remove = self.ringbuffer.iter().take_while(
            |rec| rec.pos() < window_start || rec.rid().unwrap() != rid
        ).count();
        self.ringbuffer.drain(..to_remove);
    }

    /// Fill the buffer with variants in the given window. The start coordinate has to be left of
    /// the start coordinate of any previous `fill` operation.
    /// Coordinates are 0-based, and end is exclusive.
    pub fn fetch(&mut self, chrom: &[u8], start: u32, end: u32) -> Result<(), Box<Error>> {
        let rid = try!(self.reader.header.name2rid(chrom));

        // move overflow from last fill into ringbuffer
        if self.overflow.is_some() {
            self.ringbuffer.push_back(self.overflow.take().unwrap());
        }

        // shrink and swap
        match (self.last_rid(), self.next_rid()) {
            (Some(last_rid), _) => {
                if last_rid != rid {
                    self.swap_buffers();
                } else {
                    self.drain_left(rid, start);
                }
            },
            (_, Some(_)) => {
                self.swap_buffers();
                self.drain_left(rid, start);
            },
            _ => ()
        }

        if !self.ringbuffer2.is_empty() {
            // We have already read beyond the current rid. Hence we can't extend to the right for
            // this rid.
            return Ok(())
        }

        // extend to the right
        loop {
            let mut rec = bcf::Record::new();
            if let Err(e) = self.reader.read(&mut rec) {
                if e.is_eof() {
                    break;
                }
                return Err(Box::new(e));
            }
            let pos = rec.pos();
            if let Some(rec_rid) = rec.rid() {
                if rec_rid == rid {
                    if pos >= end {
                        // Record is beyond our window. Store it anyways but stop.
                        self.overflow = Some(rec);
                        break;
                    } else if pos >= start {
                        // Record is within our window.
                        self.ringbuffer.push_back(rec);
                    } else {
                        // Record is upstream of our window, ignore it
                        continue
                    }
                } else if rec_rid > rid {
                    // record comes from next rid. Store it in second buffer but stop filling.
                    self.ringbuffer2.push_back(rec);
                    break;
                } else {
                    // Record comes from previous rid. Ignore it.
                    continue;
                }
            } else {
                // skip records without proper rid
                continue;
            }
        }

        Ok(())
    }

    /// Iterate over records that have been fetched with `fetch`.
    pub fn iter(&self) -> vec_deque::Iter<bcf::Record> {
        self.ringbuffer.iter()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use bcf;
    use bcf::record::Numeric;
    use itertools::Itertools;

    #[test]
    fn test_buffer() {
        let reader = bcf::Reader::from_path(&"test/test.bcf").unwrap();
        let mut buffer = RecordBuffer::new(reader);

        buffer.fetch(b"1", 100, 10023).unwrap();
        {
            let records = buffer.iter().collect_vec();
            assert_eq!(records.len(), 2);
            assert_eq!(records[0].pos(), 10021);
            assert_eq!(records[1].pos(), 10022);
        }

        buffer.fetch(b"1", 10023, 10024);
        {
            let records = buffer.iter().collect_vec();
            assert_eq!(records.len(), 1);
            assert_eq!(records[0].pos(), 10023);
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::VecDeque;
use num::{ToPrimitive};

use failure::{Error, Fail};
use log::{warn, debug};

use super::arch::{Arch};
use super::loader::{LoadedModule, Section};
use super::flowmeta::FlowMeta;
use super::workspace::{Workspace};

#[derive(Debug, Fail)]
pub enum AnalysisError {
    #[fail(display = "foo")]
    Foo,
    #[fail(display = "foo")]
    InvalidInstruction
}

pub enum AnalysisCommand<A: Arch> {
    MakeInsn(A::RVA),
}

pub struct XrefAnalysis<A: Arch> {
    // dst rva -> src rva
    to: HashMap<A::RVA, A::RVA>,
    // src rva -> dst rva
    from: HashMap<A::RVA, A::RVA>,
}

pub struct FlowAnalysis<A: Arch> {
    // one entry for each section in the module.
    // if executable, then one FlowMeta for each address in the section.
    // that is, Vec<FlowMeta>.len() == Section.buf.len()
    meta: Vec<Vec<FlowMeta>>,
    xrefs: XrefAnalysis<A>,
}

pub struct Analysis<A: Arch> {
    queue: VecDeque<AnalysisCommand<A>>,

    flow: FlowAnalysis<A>,
    // datameta
    // symbols
    // functions
}

impl<A: Arch> Analysis<A> {
    pub fn new(module: &LoadedModule<A>) -> Analysis<A> {
        let flow_meta: Vec<Vec<FlowMeta>> = module.sections.iter()
            .map(|section| -> Vec<FlowMeta> {
                if section.is_executable() {
                    vec![FlowMeta::zero(); section.buf.len()]
                } else {
                    vec![]
                }
            })
            .collect();

        Analysis {
            queue: VecDeque::new(),
            flow: FlowAnalysis {
                meta: flow_meta,
                xrefs: XrefAnalysis {
                    to: HashMap::new(),
                    from: HashMap::new(),
                }
            }
        }
    }

}

// here we've logically split off the analysis portion of workspace.
// this should keep file sizes smaller, and hopefully easier to understand.
impl<A: Arch + 'static> Workspace<A> {
    pub fn make_insn(&mut self, rva: A::RVA) -> Result<(), Error> {
        self.analysis.queue.push_back(AnalysisCommand::MakeInsn(rva));
        Ok(())
    }

    fn get_meta(&self, rva: A::RVA) -> Option<FlowMeta> {
        self.module.sections
            .iter()
            .enumerate()
            .filter(|(_, section)| section.contains(rva))
            .nth(0)
            .and_then(|(i, section): (usize, &Section<A>)| -> Option<FlowMeta> {
                // rva is guaranteed to be within this section,
                // so we can do an unchecked subtract here.
                let offset = rva - section.addr;
                A::RVA::to_usize(&offset)
                    .and_then(|offset| {
                        Some(self.analysis.flow.meta[i][offset].clone())
                    })
            })
    }

    fn handle_make_insn(&mut self, rva: A::RVA) -> Result<Vec<AnalysisCommand<A>>, Error> {
        let mut ret = vec![];

        // TODO: 0. probe address

        // 1. ensure instruction doesn't already exist
        //
        // if we get a result here, then there's not yet an instruction at the rva.
        // otherwise, we will have returned early, and there's no work to be done.
        //
        // now, we might worry about lots of extra allocations for the Vec if the insn already exists.
        //  but, its not a problem: Vec only allocates when there's a non-zero element in it!
        // so, its mostly ok to spam `make_insn`.
        let mut meta = match self.get_meta(rva) {
            None => {
                // this might happen if:
                //   - the instruction is in a non-executable section
                //   - the memory is not mapped
                warn!("invalid instruction: no flow meta: {:x}", rva);
                return Ok(vec![]);
            },
            Some(meta) => {
                if meta.is_insn() {
                    debug!("duplicate instruction: {:x}", rva);
                    return Ok(vec![]);
                } else {
                    // this is the happy path:
                    //   - this is a valid place for an instruction
                    //   - and it doesn't yet exist
                    meta
                }
            }
        };

        let insn = match self.read_insn(rva) {
            Err(e) => {
                warn!("invalid instruction: {:}: {:x}", e, rva);
                return Ok(vec![]);
            },
            Ok(insn) => insn,
        };

        // 2. compute instruction len
        let length = insn.length;

        // 3. compute fallthrough
        // 4. compute flow ref
        // 5. update flowmeta
        Ok(ret)
    }

    pub fn analyze(&mut self) -> Result<(), Error> {
        while let Some(cmd) = self.analysis.queue.pop_front() {
            let cmds = match cmd {
                AnalysisCommand::MakeInsn(rva) => self.handle_make_insn(rva)?,
            };
            self.analysis.queue.extend(cmds);
        }

        Ok(())
    }
}
<commit_msg>analysis: detect instruction fallthrough<commit_after>use std::collections::HashMap;
use std::collections::VecDeque;
use num::{ToPrimitive};

use log::{warn, debug};
use failure::{Error, Fail};
use zydis::gen::*;

use super::arch::{Arch};
use super::loader::{LoadedModule, Section};
use super::flowmeta::FlowMeta;
use super::workspace::{Workspace};

#[derive(Debug, Fail)]
pub enum AnalysisError {
    #[fail(display = "foo")]
    Foo,
    #[fail(display = "foo")]
    InvalidInstruction
}

pub enum AnalysisCommand<A: Arch> {
    MakeInsn(A::RVA),
}

pub struct XrefAnalysis<A: Arch> {
    // TODO: use FNV because the keys are small.
    // TODO: use SmallVec(1) for `.from` values,
    // TODO: use SmallVec(X) for `.to` values,

    // dst rva -> src rva
    to: HashMap<A::RVA, A::RVA>,
    // src rva -> dst rva
    from: HashMap<A::RVA, A::RVA>,
}

pub struct FlowAnalysis<A: Arch> {
    // one entry for each section in the module.
    // if executable, then one FlowMeta for each address in the section.
    // that is, Vec<FlowMeta>.len() == Section.buf.len()
    // TODO: order these entries so that the most common sections are first (`.code`?)
    meta: Vec<Vec<FlowMeta>>,
    xrefs: XrefAnalysis<A>,
}

pub struct Analysis<A: Arch> {
    queue: VecDeque<AnalysisCommand<A>>,

    flow: FlowAnalysis<A>,
    // datameta
    // symbols
    // functions
}

impl<A: Arch> Analysis<A> {
    pub fn new(module: &LoadedModule<A>) -> Analysis<A> {
        let flow_meta: Vec<Vec<FlowMeta>> = module.sections.iter()
            .map(|section| -> Vec<FlowMeta> {
                if section.is_executable() {
                    vec![FlowMeta::zero(); section.buf.len()]
                } else {
                    vec![]
                }
            })
            .collect();

        Analysis {
            queue: VecDeque::new(),
            flow: FlowAnalysis {
                meta: flow_meta,
                xrefs: XrefAnalysis {
                    to: HashMap::new(),
                    from: HashMap::new(),
                }
            }
        }
    }

}

// here we've logically split off the analysis portion of workspace.
// this should keep file sizes smaller, and hopefully easier to understand.
impl<A: Arch + 'static> Workspace<A> {
    pub fn make_insn(&mut self, rva: A::RVA) -> Result<(), Error> {
        self.analysis.queue.push_back(AnalysisCommand::MakeInsn(rva));
        Ok(())
    }

    fn get_meta(&self, rva: A::RVA) -> Option<FlowMeta> {
        self.module.sections
            .iter()
            .enumerate()
            .filter(|(_, section)| section.contains(rva))
            .nth(0)
            .and_then(|(i, section): (usize, &Section<A>)| -> Option<FlowMeta> {
                // rva is guaranteed to be within this section,
                // so we can do an unchecked subtract here.
                let offset = rva - section.addr;
                A::RVA::to_usize(&offset)
                    .and_then(|offset| {
                        Some(self.analysis.flow.meta[i][offset].clone())
                    })
            })
    }

    /// ```
    /// use zydis::gen::*;
    ///
    /// use lancelot::test;
    ///
    /// // JMP $+0;
    /// let ws = test::get_shellcode32_workspace(b"\xEB\xFE");
    /// let insn = ws.read_insn(0x0).unwrap();
    /// assert_eq!(Workspace::<Arch32>::does_insn_fallthrough(&insn), false);
    ///
    /// // PUSH 0x11
    /// let ws = test::get_shellcode32_workspace(b"\x6A\x11");
    /// let insn = ws.read_insn(0x0).unwrap();
    /// assert_eq!(Workspace::<Arch32>::does_insn_fallthrough(&insn), true);
    /// ```
    pub fn does_insn_fallthrough(insn: &ZydisDecodedInstruction) -> bool {
        match insn.mnemonic as i32 {
            ZYDIS_MNEMONIC_JMP => false,
            ZYDIS_MNEMONIC_RET => false,
            ZYDIS_MNEMONIC_IRET => false,
            ZYDIS_MNEMONIC_IRETD => false,
            ZYDIS_MNEMONIC_IRETQ => false,
            // TODO: call may not fallthrough if function is noret.
            // will need another pass to clean this up.
            ZYDIS_MNEMONIC_CALL => true,
            _ => true,
        }
    }

    fn handle_make_insn(&mut self, rva: A::RVA) -> Result<Vec<AnalysisCommand<A>>, Error> {
        let mut ret = vec![];

        // TODO: 0. probe address

        // 1. ensure instruction doesn't already exist
        //
        // if we get a result here, then there's not yet an instruction at the rva.
        // otherwise, we will have returned early, and there's no work to be done.
        //
        // now, we might worry about lots of extra allocations for the Vec if the insn already exists.
        //  but, its not a problem: Vec only allocates when there's a non-zero element in it!
        // so, its mostly ok to spam `make_insn`.
        let mut meta = match self.get_meta(rva) {
            None => {
                // this might happen if:
                //   - the instruction is in a non-executable section
                //   - the memory is not mapped
                warn!("invalid instruction: no flow meta: {:x}", rva);
                return Ok(vec![]);
            },
            Some(meta) => {
                if meta.is_insn() {
                    debug!("duplicate instruction: {:x}", rva);
                    return Ok(vec![]);
                } else {
                    // this is the happy path:
                    //   - this is a valid place for an instruction
                    //   - and it doesn't yet exist
                    meta
                }
            }
        };

        let insn = match self.read_insn(rva) {
            Err(e) => {
                warn!("invalid instruction: {:}: {:x}", e, rva);
                return Ok(vec![]);
            },
            Ok(insn) => insn,
        };

        // 2. compute instruction len
        let length = insn.length;

        // 3. compute fallthrough
        let does_fallthrough = Workspace::<A>::does_insn_fallthrough(&insn);

        // 4. compute flow ref
        // 5. update flowmeta
        Ok(ret)
    }

    pub fn analyze(&mut self) -> Result<(), Error> {
        while let Some(cmd) = self.analysis.queue.pop_front() {
            let cmds = match cmd {
                AnalysisCommand::MakeInsn(rva) => self.handle_make_insn(rva)?,
            };
            self.analysis.queue.extend(cmds);
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Data structures and functions used by IA-32e but not Protected Mode.

macro_rules! bit {
    ( $x:expr ) => {
        1 << $x
    };
}

macro_rules! check_flag {
    ($doc:meta, $fun:ident, $flag:ident) => (
        #[$doc]
        pub fn $fun(&self) -> bool {
            self.contains($flag)
        }
    )
}

macro_rules! is_bit_set {
    ($field:expr, $bit:expr) => (
        $field & (1 << $bit) > 0
    )
}

macro_rules! check_bit_fn {
    ($doc:meta, $fun:ident, $field:ident, $bit:expr) => (
        #[$doc]
        pub fn $fun(&self) -> bool {
            is_bit_set!(self.$field, $bit)
        }
    )
}

pub mod time;
pub mod irq;
pub mod paging;
pub mod task;
pub mod syscall;
pub mod sgx;
<commit_msg>Remove unused macros causing compiler warnings.<commit_after>//! Data structures and functions used by IA-32e but not Protected Mode.

macro_rules! bit {
    ( $x:expr ) => {
        1 << $x
    };
}

macro_rules! check_flag {
    ($doc:meta, $fun:ident, $flag:ident) => (
        #[$doc]
        pub fn $fun(&self) -> bool {
            self.contains($flag)
        }
    )
}

pub mod time;
pub mod irq;
pub mod paging;
pub mod task;
pub mod syscall;
pub mod sgx;
<|endoftext|>


<commit_before>//! Create graphene and other substrates for use in molecular dynamics simulations.
#![allow(dead_code)]
#![allow(unused_imports)]
#![allow(unused_variables)]

extern crate ansi_term;
#[macro_use]
extern crate clap;
extern crate grafen;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

mod define;
mod error;
mod database;
mod output;

use database::{read_database, write_database, DataBase};
use error::{GrafenCliError, Result};
use define::SystemDefinition;

use grafen::substrate;
use grafen::system::{join_systems, Coord, Residue, System};
use std::cmp;
use std::error::Error;
use std::io;
use std::io::Write;
use std::process;
use std::result;
use std::path::PathBuf;

/// The program run configuration.
pub struct Config {
    /// Title of output system.
    pub title: String,
    /// Path to output file.
    pub output_filename: PathBuf,
    /// Database of residue and substrate definitions.
    pub database: DataBase,
}

impl Config {
    /// Parse the input command line arguments, ask the user to select
    /// a substrate and return the run configuration.
    ///
    /// # Errors
    /// Returns an error if any of the required arguments are missing or invalid,
    /// or if the user did not select a substrate. In the latter case the program
    /// should exit.
    pub fn from_matches(matches: clap::ArgMatches) -> Result<Config> {
        let output_filename = value_t!(matches, "output", String).map(|s| PathBuf::from(s))?;
        let title = value_t!(matches, "title", String)
            .unwrap_or("System created by grafen".to_string());

        let database = match value_t!(matches, "database", String) {
            Ok(path) => read_database(&path),
            _ => Ok(DataBase::new()),
        }?;

        Ok(Config { title, output_filename, database })
    }
}

fn main() {
    let matches = clap_app!(grafen_cli =>
        (version: crate_version!())
        (author: crate_authors!())
        (about: crate_description!())
        (@arg output: <PATH> "Output GROMOS file")
        (@arg title: -t --title [STR] +takes_value "Title of output system")
        (@arg database: -d --database [STR] +takes_value "Path to database")
    ).get_matches();

    if let Err(err) = Config::from_matches(matches).and_then(|mut conf| run(&mut conf)) {
        let mut stderr = io::stderr();
        writeln!(&mut stderr, "{}", err).expect("could not write to stderr");
        process::exit(1);
    }
}

/// Run the program with the set `Config`.
fn run(config: &mut Config) -> Result<()> {
    let system_defs = define::user_menu(&mut config.database)?;
    let system = construct_system(&system_defs)?;
    output::write_gromos(&system, &config.output_filename, &config.title)
}

/// After the systems have been defined we create them one by one and join them.
fn construct_system(system_defs: &Vec<SystemDefinition>) -> Result<System> {
    let systems = system_defs.iter().map(|def| {
        let (x, y) = def.size;
        substrate::create_substrate(&def.finalized)
            .map(|system| system.translate(&def.position))
            .map_err(|err| GrafenCliError::from(err))
    })
    .collect::<result::Result<Vec<System>, GrafenCliError>>()?;

    Ok(join_systems(systems))
}
<commit_msg>Add a default output filename<commit_after>//! Create graphene and other substrates for use in molecular dynamics simulations.
#![allow(dead_code)]
#![allow(unused_imports)]
#![allow(unused_variables)]

extern crate ansi_term;
#[macro_use]
extern crate clap;
extern crate grafen;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

mod define;
mod error;
mod database;
mod output;

use database::{read_database, write_database, DataBase};
use error::{GrafenCliError, Result};
use define::SystemDefinition;

use grafen::substrate;
use grafen::system::{join_systems, Coord, Residue, System};
use std::cmp;
use std::error::Error;
use std::io;
use std::io::Write;
use std::process;
use std::result;
use std::path::PathBuf;

/// The program run configuration.
pub struct Config {
    /// Title of output system.
    pub title: String,
    /// Path to output file.
    pub output_path: PathBuf,
    /// Database of residue and substrate definitions.
    pub database: DataBase,
}

impl Config {
    /// Parse the input command line arguments and read the `DataBase`.
    ///
    /// # Errors
    /// Returns an error if any of the arguments could not be properly parsed
    /// or the `DataBase` (if input) not opened.
    pub fn from_matches(matches: clap::ArgMatches) -> Result<Config> {
        let output_path = PathBuf::from(
            value_t!(matches, "output", String).unwrap_or("conf.gro".to_string())
        );
        let title = value_t!(matches, "title", String)
            .unwrap_or("System created by grafen".to_string()
        );

        let database = match value_t!(matches, "database", String) {
            Ok(path) => read_database(&path),
            Err(_) => Ok(DataBase::new()),
        }?;

        Ok(Config { title, output_path, database })
    }
}

fn main() {
    let matches = clap_app!(grafen_cli =>
        (version: crate_version!())
        (author: crate_authors!())
        (about: crate_description!())
        (@arg output: -o --output [PATH] +takes_value "Output GROMOS configuration file (conf.gro)")
        (@arg title: -t --title [STR] +takes_value "Title of output system")
        (@arg database: -d --database [PATH] +takes_value "Path to database")
    ).get_matches();

    if let Err(err) = Config::from_matches(matches).and_then(|mut conf| run(&mut conf)) {
        let mut stderr = io::stderr();
        writeln!(&mut stderr, "{}", err).expect("could not write to stderr");
        process::exit(1);
    }
}

/// Run the program with the set `Config`.
fn run(config: &mut Config) -> Result<()> {
    let system_defs = define::user_menu(&mut config.database)?;
    let system = construct_system(&system_defs)?;
    output::write_gromos(&system, &config.output_path, &config.title)
}

/// After the systems have been defined we create them one by one and join them.
fn construct_system(system_defs: &Vec<SystemDefinition>) -> Result<System> {
    let systems = system_defs.iter().map(|def| {
        let (x, y) = def.size;
        substrate::create_substrate(&def.finalized)
            .map(|system| system.translate(&def.position))
            .map_err(|err| GrafenCliError::from(err))
    })
    .collect::<result::Result<Vec<System>, GrafenCliError>>()?;

    Ok(join_systems(systems))
}
<|endoftext|>