<commit_before>//
// gash.rs
// by Nathan Typanski
//
// 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::{run, os};
use std::io::buffered::BufferedReader;
use std::io::{stdin, stdio, File, Truncate, Write};
use std::io::process::ProcessExit;
use std::io::signal::{Listener, Interrupt};
use std::path::posix::Path;
use std::option::Option;
use std::task::try;
use std::run::Process;
use std::run::ProcessOptions;
use std::comm::Port;

use extra::getopts;

use std::libc::types::os::arch::posix88::pid_t;
use std::libc::consts::os::posix88::{STDOUT_FILENO, STDIN_FILENO};
use std::libc;

extern {
  pub fn kill(pid: pid_t, sig: libc::c_int) -> libc::c_int;
}

// The basic unit for a command that could be run.
#[deriving(Clone)]
struct Cmd {
    program : ~str,
    argv : ~[~str],
}

impl Cmd {
    fn new(cmd_name: &str) -> Option<Cmd> {
        let mut argv: ~[~str] = split_words(cmd_name);
        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            let argv : ~[~str] = argv;
            Some(Cmd {
                program : program,
                argv : argv,
            })
        }
        else {
            None
        }
    }
}

struct FgProcess {
    command     : ~str,
    args        : ~[~str],
    stdin       : Option<i32>,
    stdout      : Option<i32>,
}
impl FgProcess {
    fn new(cmd : Cmd,
           stdin : Option<i32>,
           stdout : Option<i32>)
        -> Option<FgProcess>
    {
        if (cmd_exists(&cmd)) {
            Some(FgProcess {
                command     : cmd.program.to_owned(),
                args        : cmd.argv.to_owned(),
                stdin       : stdin,
                stdout      : stdout,
            })
        }
        else { None }
    }

    fn run(&mut self) -> Option<Process> {
        let command = self.command.to_owned();
        let args = self.args.to_owned();
        let options = ProcessOptions {
            env    : None,
            dir    : None,
            in_fd  : self.stdin,
            out_fd : self.stdout,
            err_fd : None,
        };
        Process::new(command, args, options)
    }
}

// Background processes are handled differently, but not *that* differently:
// we need to keep track of an ProcessExit port for determining whether a
// process has finished running, as well as a pid for the process (for killing
// it when the shell terminates).
struct BgProcess {
    command      : ~str,
    args         : ~[~str],
    exit_port    : Option<Port<ProcessExit>>,
    pid          : Option<i32>,
    stdin       : Option<i32>,
    stdout      : Option<i32>,
}
impl BgProcess {
    fn new(cmd : Cmd) -> Option<BgProcess> {
        if (cmd_exists(&cmd)) {
            Some(BgProcess {
                command: cmd.program.to_owned(),
                args: cmd.argv.to_owned(),
                exit_port: None,
                pid: None,
                stdin: None,
                stdout: None,
            })
        }
        else { None }
    }

    fn run(&mut self) -> Option<pid_t> {
        // Process exit ports; used for checking dead status.
        let (port, chan): (Port<ProcessExit>, Chan<ProcessExit>) = Chan::new();
        // Process ports; these don't leave this function and are used for
        // sending the PID out in the return value.
        let (pidport, pidchan): (Port<Option<pid_t>>, Chan<Option<pid_t>>)
                            = 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) => {
                    // Send the pid out for the return value
                    pidchan.try_send_deferred(Some(process.get_id()));
                    chan.try_send_deferred(process.finish());
                }
                None => {
                    pidchan.try_send_deferred(None);
                }
            }
        });
        self.exit_port = Some(port);
        self.pid = pidport.recv();
        self.pid
    }
}

struct Shell {
    cmd_prompt : ~str,
    history    : ~[~str],
    processes  : ~[~BgProcess],
    broken : bool,
}

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

    fn start(&mut self) {
        // Setup the interrupt handler. Has to happen here, or it won't
        // retain control over interrupts.
        let mut listener = Listener::new();
        listener.register(Interrupt);
        let port = listener.port;
        spawn(proc() {
            try(proc() {
                loop {
                    match port.recv_opt() {
                        Some(Interrupt) => {
                        }
                        None => {
                            break;
                        }
                        _ => {
                        }
                    }
                }
                return 0
            });
            return ();
        });

        self.display_prompt();
    }

    fn display_prompt(&mut self) {
        // Standard input reader
        let mut stdin = BufferedReader::new(stdin());
        // Show the prompt
        print(self.cmd_prompt);
        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.disown_dead();

        // Push commands onto the history
        match program {
            "" => {}
            _  => {
                self.push_hist(cmd_line)
            }
        }

        match program {
            "" =>  {
                self.display_prompt();
            }
            "exit" =>  {
                self.kill_all();
            }
            "history" => {
                self.show_hist();
                self.display_prompt();
            }
            "jobs" => {
                self.jobs();
                self.display_prompt();
            }
            "cd" =>  {
                self.chdir(cmd_line);
                self.display_prompt();
            }
            _ => {
                self.run_cmdline(cmd_line);
                self.display_prompt();
            }
        }
    }

    // Nice extra feature: list running jobs.
    fn jobs(&mut self) {
        for cmd in self.processes.iter() {
            print!("{:s}", cmd.command);
            match cmd.pid {
                Some(pid) => {
                    println!(" {:i}", pid);
                }
                None => {
                    println("");
                }
            }
        }
    }

    // Remove dead processes from the list of processes.
    fn disown_dead(&mut self) {
        let mut dead : ~[uint];
        dead = ~[];
        let mut i = 0;
        for cmd in self.processes.iter() {
            borrowed_maybe(&cmd.exit_port, |port| match port.try_recv() {
                Some(_) => {dead.push(i); Some(i)},
                _ => None,
            });
            i += 1;
        }
        for &p in dead.iter() {
            self.processes.remove(p);
        }
    }

    fn kill_all(&mut self) {
        for p in self.processes.iter() {
            match p.pid {
                Some(pid) => {
                    unsafe {
                        // Kill perhaps isn't the best way to do this, but
                        // without it we have no way of killing our background
                        // processes with only the PID - we'd need the process
                        // object itself, and that can't be moved out of the
                        // spawn() that it's trapped inside.
                        kill(pid, 15);
                    }
                }
                None => {
                }
            }
        }
    }

    // Push a new command onto history.
    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] = split_words(cmd_line);
        if argv.len() > 0 {
            argv.remove(0);
            let path = Path::new(argv[0]);
            os::change_dir(&path);
        }
    }

    // Determine the type of the current block, and send it to the right
    // parsing function.
    fn run_cmdline(&mut self, cmd_line: &str) {
        if cmd_line.contains_char('>') {
            parse_r_redirect(cmd_line);
        }
        else if cmd_line.contains_char('<') {
            parse_l_redirect(cmd_line);
        }
        else if cmd_line.contains_char('|') {
            self.parse_pipeline(cmd_line);
        }
        else {
            self.parse_process(cmd_line);
        }
    }

    // Parse a new lone process. Background/foreground it appropriately.
    fn parse_process(&mut self, cmd_line : &str) -> Option<Process>{
        maybe(Cmd::new(cmd_line), |cmd| {
            if (cmd.argv.len() > 0 && cmd.argv.last() == &~"&") {
                let mut argv = cmd.argv.to_owned();
                argv.pop();
                self.make_bg_process(Cmd{
                    program:cmd.program,
                    argv:argv});
                None
            }
            else {
                make_process(cmd, Some(STDIN_FILENO), Some(STDOUT_FILENO))
            }
        })
    }

    // Parse a process pipeline, and redirect stdin/stdout appropriately.
    fn parse_pipeline(&mut self, cmd_line : &str) {
        let pipes : ~[Cmd] = cmd_line.split('|')
            .filter_map(Cmd::new)
            .to_owned_vec();
        let mut i = 0;
        let mut stdout = stdio::stdout();
        let x = pipes[0].clone();
        let y = pipes[1].clone();
        match self.pipe_input(x, y) {
            Some(mut p) => {
                let output = p.finish_with_output();
                stdout.write(output.output);
            }
            None => {

            }
        }
    }

    // Redirect the stdout of Process two into the stdin of `cmd`, and return
    // the process created from `cmd`.
    fn pipe_input(&mut self, left : Cmd, right : Cmd) -> Option<Process> {
        match simple_process(left) {
            Some(mut left) => {
                match simple_process(right) {
                    Some(mut right) => {
                        let output = left.finish_with_output();
                        if output.status.success() {
                            right.input().write(output.output);
                            right.close_input();
                        }
                        Some(right)
                    }
                    None => {
                        None
                    }
                }
            }
            None => {
                None
            }
        }
    }

    // Make a new background process, and push it onto our stack of tracked
    // background processes.
    fn make_bg_process(&mut self, cmd : Cmd) {
        let name = cmd.program.to_owned();
        match BgProcess::new(cmd) {
            Some(mut process) => {
                match process.run() {
                    Some(pid) => {
                        println!("{:s} {:i}", name, pid);
                        self.processes.push(~process);
                    }
                    None => {
                    }
                }
            }
            None => {
            }
        }
    }
}

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;
    }
}

// Determine whether a command exists using "which".
fn cmd_exists(command : &Cmd) -> bool {
    let ret = run::process_output("which", [command.program.to_owned()]);
    return ret.expect("exit code error.").status.success();
}

fn split_words(word : &str) -> ~[~str] {
    word.split(' ').filter_map(
        |x| if x != "" { Some(x.to_owned()) } else { None }
        ).to_owned_vec()
}

fn simple_process(cmd : Cmd) -> Option<run::Process> {
    maybe(FgProcess::new(cmd, None, None),
          |mut cmdprocess| cmdprocess.run())
}

fn make_process(cmd : Cmd,
                stdin: Option<i32>,
                stdout: Option<i32>) -> Option<run::Process> {
    maybe(FgProcess::new(cmd, stdin, stdout),
          |mut cmdprocess| cmdprocess.run())
}

fn parse_l_redirect(cmd_line : &str) {
    let pair : ~[&str] = cmd_line.rsplit('<').collect();
    let filename = pair[0].trim();
    match maybe(Cmd::new(pair[1].trim()), |c|
                make_process(c, None, Some(STDOUT_FILENO))) {
        Some(mut process) => {
            match File::open_mode(&Path::new(filename),
                                    std::io::Append,
                                    std::io::ReadWrite) {
                Some(file) => {
                    let proc_input = process.input();
                    let mut file_buffer = BufferedReader::new(file);
                    proc_input.write(file_buffer.read_to_end());
                }
                None => {
                }
            }
        }
        None => {
        }
    }
}

fn write_output_to_file(output : std::run::ProcessOutput,
                        filename : &str) {
    if output.status.success() {
        match File::open_mode(&Path::new(filename),
                                std::io::Truncate,
                                std::io::Write)
        {
            Some(mut file) => {
                file.write(output.output);
            }
            None =>{
                println!("Opening {:s} failed!", filename);
            }
        }
    }
    else {
        println!("{:?}", output.error);
    }
}

fn parse_r_redirect(cmd_line : &str) {
    let pair : ~[&str] = cmd_line.rsplit('>').collect();
    let file = pair[0].trim();
    let cmd = Cmd::new(pair[1].trim());
    match maybe(cmd, |c| make_process(c, None, None)) {
        Some(mut process) => {
            write_output_to_file(
                process.finish_with_output(),
                file);
        }
        None => {
        }
    }
}

// Describes a computation that could fail.
// If v is Some(...), then f is called on v and the result is returned.
// Otherwise, None is returned.
fn maybe<A, B>(v : Option<A>, f : |A| -> Option<B>) -> Option<B> {
    match v {
        Some(v) => f(v),
        None    => None,
    }
}

// Same as maybe(v, f), but for &v.
fn borrowed_maybe<A, B>(v : &Option<A>, f : |&A| -> Option<B>) -> Option<B> {
    match *v {
        Some(ref v) => f(v),
        None    => None,
    }
}

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

    match opt_cmd_line {
        Some(cmd_line) => {
            let mut shell = Shell::new("");
            shell.run_cmdline(cmd_line);
        }
        None => {
            let mut shell = Shell::new("gash > ");
            shell.start();
        }
    }
}
<commit_msg>remove pipe code<commit_after>//
// gash.rs
// by Nathan Typanski
//
// 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::{run, os};
use std::io::buffered::BufferedReader;
use std::io::{stdin, stdio, File, Truncate, Write};
use std::io::process::ProcessExit;
use std::io::signal::{Listener, Interrupt};
use std::path::posix::Path;
use std::option::Option;
use std::task::try;
use std::run::Process;
use std::run::ProcessOptions;
use std::comm::Port;

use extra::getopts;

use std::libc::types::os::arch::posix88::pid_t;
use std::libc::consts::os::posix88::{STDOUT_FILENO, STDIN_FILENO};
use std::libc;

extern {
  pub fn kill(pid: pid_t, sig: libc::c_int) -> libc::c_int;
}

// The basic unit for a command that could be run.
#[deriving(Clone)]
struct Cmd {
    program : ~str,
    argv : ~[~str],
}

impl Cmd {
    fn new(cmd_name: &str) -> Option<Cmd> {
        let mut argv: ~[~str] = split_words(cmd_name);
        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            let argv : ~[~str] = argv;
            Some(Cmd {
                program : program,
                argv : argv,
            })
        }
        else {
            None
        }
    }
}

struct FgProcess {
    command     : ~str,
    args        : ~[~str],
    stdin       : Option<i32>,
    stdout      : Option<i32>,
}
impl FgProcess {
    fn new(cmd : Cmd,
           stdin : Option<i32>,
           stdout : Option<i32>)
        -> Option<FgProcess>
    {
        if (cmd_exists(&cmd)) {
            Some(FgProcess {
                command     : cmd.program.to_owned(),
                args        : cmd.argv.to_owned(),
                stdin       : stdin,
                stdout      : stdout,
            })
        }
        else { None }
    }

    fn run(&mut self) -> Option<Process> {
        let command = self.command.to_owned();
        let args = self.args.to_owned();
        let options = ProcessOptions {
            env    : None,
            dir    : None,
            in_fd  : self.stdin,
            out_fd : self.stdout,
            err_fd : None,
        };
        Process::new(command, args, options)
    }
}

// Background processes are handled differently, but not *that* differently:
// we need to keep track of an ProcessExit port for determining whether a
// process has finished running, as well as a pid for the process (for killing
// it when the shell terminates).
struct BgProcess {
    command      : ~str,
    args         : ~[~str],
    exit_port    : Option<Port<ProcessExit>>,
    pid          : Option<i32>,
    stdin       : Option<i32>,
    stdout      : Option<i32>,
}
impl BgProcess {
    fn new(cmd : Cmd) -> Option<BgProcess> {
        if (cmd_exists(&cmd)) {
            Some(BgProcess {
                command: cmd.program.to_owned(),
                args: cmd.argv.to_owned(),
                exit_port: None,
                pid: None,
                stdin: None,
                stdout: None,
            })
        }
        else { None }
    }

    fn run(&mut self) -> Option<pid_t> {
        // Process exit ports; used for checking dead status.
        let (port, chan): (Port<ProcessExit>, Chan<ProcessExit>) = Chan::new();
        // Process ports; these don't leave this function and are used for
        // sending the PID out in the return value.
        let (pidport, pidchan): (Port<Option<pid_t>>, Chan<Option<pid_t>>)
                            = 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) => {
                    // Send the pid out for the return value
                    pidchan.try_send_deferred(Some(process.get_id()));
                    chan.try_send_deferred(process.finish());
                }
                None => {
                    pidchan.try_send_deferred(None);
                }
            }
        });
        self.exit_port = Some(port);
        self.pid = pidport.recv();
        self.pid
    }
}

struct Shell {
    cmd_prompt : ~str,
    history    : ~[~str],
    processes  : ~[~BgProcess],
    broken : bool,
}

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

    fn start(&mut self) {
        // Setup the interrupt handler. Has to happen here, or it won't
        // retain control over interrupts.
        let mut listener = Listener::new();
        listener.register(Interrupt);
        let port = listener.port;
        spawn(proc() {
            try(proc() {
                loop {
                    match port.recv_opt() {
                        Some(Interrupt) => {
                        }
                        None => {
                            break;
                        }
                        _ => {
                        }
                    }
                }
                return 0
            });
            return ();
        });

        self.display_prompt();
    }

    fn display_prompt(&mut self) {
        // Standard input reader
        let mut stdin = BufferedReader::new(stdin());
        // Show the prompt
        print(self.cmd_prompt);
        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.disown_dead();

        // Push commands onto the history
        match program {
            "" => {}
            _  => {
                self.push_hist(cmd_line)
            }
        }

        match program {
            "" =>  {
                self.display_prompt();
            }
            "exit" =>  {
                self.kill_all();
            }
            "history" => {
                self.show_hist();
                self.display_prompt();
            }
            "jobs" => {
                self.jobs();
                self.display_prompt();
            }
            "cd" =>  {
                self.chdir(cmd_line);
                self.display_prompt();
            }
            _ => {
                self.run_cmdline(cmd_line);
                self.display_prompt();
            }
        }
    }

    // Nice extra feature: list running jobs.
    fn jobs(&mut self) {
        for cmd in self.processes.iter() {
            print!("{:s}", cmd.command);
            match cmd.pid {
                Some(pid) => {
                    println!(" {:i}", pid);
                }
                None => {
                    println("");
                }
            }
        }
    }

    // Remove dead processes from the list of processes.
    fn disown_dead(&mut self) {
        let mut dead : ~[uint];
        dead = ~[];
        let mut i = 0;
        for cmd in self.processes.iter() {
            borrowed_maybe(&cmd.exit_port, |port| match port.try_recv() {
                Some(_) => {dead.push(i); Some(i)},
                _ => None,
            });
            i += 1;
        }
        for &p in dead.iter() {
            self.processes.remove(p);
        }
    }

    fn kill_all(&mut self) {
        for p in self.processes.iter() {
            match p.pid {
                Some(pid) => {
                    unsafe {
                        // Kill perhaps isn't the best way to do this, but
                        // without it we have no way of killing our background
                        // processes with only the PID - we'd need the process
                        // object itself, and that can't be moved out of the
                        // spawn() that it's trapped inside.
                        kill(pid, 15);
                    }
                }
                None => {
                }
            }
        }
    }

    // Push a new command onto history.
    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] = split_words(cmd_line);
        if argv.len() > 0 {
            argv.remove(0);
            let path = Path::new(argv[0]);
            os::change_dir(&path);
        }
    }

    // Determine the type of the current block, and send it to the right
    // parsing function.
    fn run_cmdline(&mut self, cmd_line: &str) {
        if cmd_line.contains_char('>') {
            parse_r_redirect(cmd_line);
        }
        else if cmd_line.contains_char('<') {
            parse_l_redirect(cmd_line);
        }
        else {
            self.parse_process(cmd_line);
        }
    }

    // Parse a new lone process. Background/foreground it appropriately.
    fn parse_process(&mut self, cmd_line : &str) -> Option<Process>{
        maybe(Cmd::new(cmd_line), |cmd| {
            if (cmd.argv.len() > 0 && cmd.argv.last() == &~"&") {
                let mut argv = cmd.argv.to_owned();
                argv.pop();
                self.make_bg_process(Cmd{
                    program:cmd.program,
                    argv:argv});
                None
            }
            else {
                make_process(cmd, Some(STDIN_FILENO), Some(STDOUT_FILENO))
            }
        })
    }

    // background processes.
    fn make_bg_process(&mut self, cmd : Cmd) {
        let name = cmd.program.to_owned();
        match BgProcess::new(cmd) {
            Some(mut process) => {
                match process.run() {
                    Some(pid) => {
                        println!("{:s} {:i}", name, pid);
                        self.processes.push(~process);
                    }
                    None => {
                    }
                }
            }
            None => {
            }
        }
    }
}

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;
    }
}

// Determine whether a command exists using "which".
fn cmd_exists(command : &Cmd) -> bool {
    let ret = run::process_output("which", [command.program.to_owned()]);
    return ret.expect("exit code error.").status.success();
}

fn split_words(word : &str) -> ~[~str] {
    word.split(' ').filter_map(
        |x| if x != "" { Some(x.to_owned()) } else { None }
        ).to_owned_vec()
}

fn make_process(cmd : Cmd,
                stdin: Option<i32>,
                stdout: Option<i32>) -> Option<run::Process> {
    maybe(FgProcess::new(cmd, stdin, stdout),
          |mut cmdprocess| cmdprocess.run())
}

fn parse_l_redirect(cmd_line : &str) {
    let pair : ~[&str] = cmd_line.rsplit('<').collect();
    let filename = pair[0].trim();
    match maybe(Cmd::new(pair[1].trim()), |c|
                make_process(c, None, Some(STDOUT_FILENO))) {
        Some(mut process) => {
            match File::open_mode(&Path::new(filename),
                                    std::io::Append,
                                    std::io::ReadWrite) {
                Some(file) => {
                    let proc_input = process.input();
                    let mut file_buffer = BufferedReader::new(file);
                    proc_input.write(file_buffer.read_to_end());
                }
                None => {
                }
            }
        }
        None => {
        }
    }
}

fn write_output_to_file(output : std::run::ProcessOutput,
                        filename : &str) {
    if output.status.success() {
        match File::open_mode(&Path::new(filename),
                                std::io::Truncate,
                                std::io::Write)
        {
            Some(mut file) => {
                file.write(output.output);
            }
            None =>{
                println!("Opening {:s} failed!", filename);
            }
        }
    }
    else {
        println!("{:?}", output.error);
    }
}

fn parse_r_redirect(cmd_line : &str) {
    let pair : ~[&str] = cmd_line.rsplit('>').collect();
    let file = pair[0].trim();
    let cmd = Cmd::new(pair[1].trim());
    match maybe(cmd, |c| make_process(c, None, None)) {
        Some(mut process) => {
            write_output_to_file(
                process.finish_with_output(),
                file);
        }
        None => {
        }
    }
}

// Describes a computation that could fail.
// If v is Some(...), then f is called on v and the result is returned.
// Otherwise, None is returned.
fn maybe<A, B>(v : Option<A>, f : |A| -> Option<B>) -> Option<B> {
    match v {
        Some(v) => f(v),
        None    => None,
    }
}

// Same as maybe(v, f), but for &v.
fn borrowed_maybe<A, B>(v : &Option<A>, f : |&A| -> Option<B>) -> Option<B> {
    match *v {
        Some(ref v) => f(v),
        None    => None,
    }
}

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

    match opt_cmd_line {
        Some(cmd_line) => {
            let mut shell = Shell::new("");
            shell.run_cmdline(cmd_line);
        }
        None => {
            let mut shell = Shell::new("gash > ");
            shell.start();
        }
    }
}
<|endoftext|>


<commit_before>extern mod xlib;
use std::ptr;
use std::option::Option;
use xlib::xlib;
use xlib::{Display, XSelectInput, XOpenDisplay, Window, XDefaultRootWindow};
use xlib::{XNextEvent, Union__XEvent};

mod x;

fn getDisplay() -> Option<*mut Display> {
    unsafe {
        let null = ptr::null();
        let display = XOpenDisplay(null);

        if (ptr::is_null(display)) {
            return None
        } else {
            return Some(display);
        }

    }
}

fn getRootWindow(display: *mut Display) -> Window {
    unsafe {
        return XDefaultRootWindow(display);
    }
}

fn setSelectInput(display: *mut Display, window: Window) {
    unsafe {
        let XSelectInputMask = x::SubstructureNotifyMask|x::SubstructureRedirectMask;
        XSelectInput(display, window, XSelectInputMask);
    }
}

fn main() {
    let maybeDisplay = getDisplay();

    match maybeDisplay {
        Some(display) => {
            println!("Got display {}", display);
            let root = getRootWindow(display);
            println!("Got root window {}", root);

            setSelectInput(display, root);
            println!("select input set!");

            unsafe {
                let mut wa = xlib::XSetWindowAttributes {
                    background_pixmap: 0,
                    background_pixel: 0,
                    border_pixmap: 0,
                    border_pixel: 0,
                    bit_gravity: 0,
                    win_gravity: 0,
                    backing_store: 0,
                    backing_planes: 0,
                    backing_pixel: 0,
                    save_under: 0,
                    event_mask: 0,
                    do_not_propagate_mask: 0,
                    override_redirect: 0,
                    colormap: 0,
                    cursor: 0,
                };
                wa.cursor = xlib::XCreateFontCursor(display, 68 /*XC_left_ptr*/);
                xlib::XChangeWindowAttributes(display, root,
                    x::CWCursor, &mut wa);
                xlib::XGrabKey(display, 53, x::Mod4Mask, root, 1, x::GrabModeAsync,
                    x::GrabModeAsync);
                xlib::XGrabKey(display, 45, x::Mod4Mask, root, 1, x::GrabModeAsync,
                    x::GrabModeAsync);

                let mut xevent = Union__XEvent{ data: [0, ..24] };
                loop {
                    XNextEvent(display, ptr::to_mut_unsafe_ptr(&mut xevent));
                    let eventType = *xevent._type();

                    match eventType {
                        x::MapRequest => {
                            let event = *xevent.xmaprequest();
                            xlib::XMapWindow(display, event.window);
                            xlib::XSetInputFocus(display, event.window,
                                x::RevertToPointerRoot, x::CurrentTime);
                            xlib::XMoveResizeWindow(display, event.window, 0, 0,
                                1920, 1080);
                        }
                        x::KeyRelease => {
                            let event = *xevent.xkey();
                            println!("Key {}", event.keycode);
                            if (event.keycode == 45) {
                                    let mut focus: Window = 0;
                                    let mut revert: i32 = 0;
                                    xlib::XGetInputFocus(display, &mut focus,
                                        &mut revert);
                                    xlib::XDestroyWindow(display, focus);
                            }
                        }
                        _ => {
                            println!("Unknown Event Type {}", eventType);
                        }
                    }
                }
            }
        }
        None => println!("Error getting display")
    }
}
<commit_msg>map new windows to the size of the display<commit_after>extern mod xlib;
use std::ptr;
use std::option::Option;
use xlib::xlib;
use xlib::{Display, XSelectInput, XOpenDisplay, Window, XDefaultRootWindow};
use xlib::{XNextEvent, Union__XEvent};

mod x;

fn getDisplay() -> Option<*mut Display> {
    unsafe {
        let null = ptr::null();
        let display = XOpenDisplay(null);

        if (ptr::is_null(display)) {
            return None
        } else {
            return Some(display);
        }

    }
}

fn getRootWindow(display: *mut Display) -> Window {
    unsafe {
        return XDefaultRootWindow(display);
    }
}

fn setSelectInput(display: *mut Display, window: Window) {
    unsafe {
        let XSelectInputMask = x::SubstructureNotifyMask|x::SubstructureRedirectMask;
        XSelectInput(display, window, XSelectInputMask);
    }
}

fn main() {
    let maybeDisplay = getDisplay();

    match maybeDisplay {
        Some(display) => {
            println!("Got display {}", display);
            let root = getRootWindow(display);
            println!("Got root window {}", root);

            setSelectInput(display, root);
            println!("select input set!");

            unsafe {
                let mut wa = xlib::XSetWindowAttributes {
                    background_pixmap: 0,
                    background_pixel: 0,
                    border_pixmap: 0,
                    border_pixel: 0,
                    bit_gravity: 0,
                    win_gravity: 0,
                    backing_store: 0,
                    backing_planes: 0,
                    backing_pixel: 0,
                    save_under: 0,
                    event_mask: 0,
                    do_not_propagate_mask: 0,
                    override_redirect: 0,
                    colormap: 0,
                    cursor: 0,
                };
                wa.cursor = xlib::XCreateFontCursor(display, 68 /*XC_left_ptr*/);
                xlib::XChangeWindowAttributes(display, root,
                    x::CWCursor, &mut wa);
                xlib::XGrabKey(display, 53, x::Mod4Mask, root, 1, x::GrabModeAsync,
                    x::GrabModeAsync);
                xlib::XGrabKey(display, 45, x::Mod4Mask, root, 1, x::GrabModeAsync,
                    x::GrabModeAsync);

                let mut xevent = Union__XEvent{ data: [0, ..24] };
                loop {
                    XNextEvent(display, ptr::to_mut_unsafe_ptr(&mut xevent));
                    let eventType = *xevent._type();

                    match eventType {
                        x::MapRequest => {
                            let screen = xlib::XDefaultScreen(display);
                            let width = xlib::XDisplayWidth(display, screen);
                            let height = xlib::XDisplayHeight(display, screen);

                            println!("Map request screen {} width {} height {}",
                                screen, width, height);

                            let event = *xevent.xmaprequest();
                            xlib::XMapWindow(display, event.window);
                            xlib::XSetInputFocus(display, event.window,
                                x::RevertToPointerRoot, x::CurrentTime);
                            xlib::XMoveResizeWindow(display, event.window, 0, 0,
                                width as u32, height as u32);
                        }
                        x::KeyRelease => {
                            let event = *xevent.xkey();
                            println!("Key {}", event.keycode);
                            if (event.keycode == 45) {
                                    let mut focus: Window = 0;
                                    let mut revert: i32 = 0;
                                    xlib::XGetInputFocus(display, &mut focus,
                                        &mut revert);
                                    xlib::XDestroyWindow(display, focus);
                            }
                        }
                        _ => {
                            println!("Unknown Event Type {}", eventType);
                        }
                    }
                }
            }
        }
        None => println!("Error getting display")
    }
}
<|endoftext|>


<commit_before>use clippy_dev::clippy_project_root;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::prelude::*;
use std::io::ErrorKind;
use std::path::Path;

pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str>) -> Result<(), io::Error> {
    let pass = pass.expect("`pass` argument is validated by clap");
    let lint_name = lint_name.expect("`name` argument is validated by clap");
    let category = category.expect("`category` argument is validated by clap");

    match open_files(lint_name) {
        Ok((mut test_file, mut lint_file)) => {
            let (pass_type, pass_lifetimes, pass_import, context_import) = match pass {
                "early" => ("EarlyLintPass", "", "use syntax::ast::*;", "EarlyContext"),
                "late" => ("LateLintPass", "<'_, '_>", "use rustc_hir::*;", "LateContext"),
                _ => {
                    unreachable!("`pass_type` should only ever be `early` or `late`!");
                },
            };

            let camel_case_name = to_camel_case(lint_name);

            if let Err(e) = test_file.write_all(get_test_file_contents(lint_name).as_bytes()) {
                return Err(io::Error::new(
                    ErrorKind::Other,
                    format!("Could not write to test file: {}", e),
                ));
            };

            if let Err(e) = lint_file.write_all(
                get_lint_file_contents(
                    pass_type,
                    pass_lifetimes,
                    lint_name,
                    &camel_case_name,
                    category,
                    pass_import,
                    context_import,
                )
                .as_bytes(),
            ) {
                return Err(io::Error::new(
                    ErrorKind::Other,
                    format!("Could not write to lint file: {}", e),
                ));
            }
            Ok(())
        },
        Err(e) => Err(io::Error::new(
            ErrorKind::Other,
            format!("Unable to create lint: {}", e),
        )),
    }
}

fn open_files(lint_name: &str) -> Result<(File, File), io::Error> {
    let project_root = clippy_project_root();

    let test_file_path = project_root.join("tests").join("ui").join(format!("{}.rs", lint_name));
    let lint_file_path = project_root
        .join("clippy_lints")
        .join("src")
        .join(format!("{}.rs", lint_name));

    if Path::new(&test_file_path).exists() {
        return Err(io::Error::new(
            ErrorKind::AlreadyExists,
            format!("test file {:?} already exists", test_file_path),
        ));
    }
    if Path::new(&lint_file_path).exists() {
        return Err(io::Error::new(
            ErrorKind::AlreadyExists,
            format!("lint file {:?} already exists", lint_file_path),
        ));
    }

    let test_file = OpenOptions::new().write(true).create_new(true).open(test_file_path)?;
    let lint_file = OpenOptions::new().write(true).create_new(true).open(lint_file_path)?;

    Ok((test_file, lint_file))
}

fn to_camel_case(name: &str) -> String {
    name.split('_')
        .map(|s| {
            if s.is_empty() {
                String::from("")
            } else {
                [&s[0..1].to_uppercase(), &s[1..]].concat()
            }
        })
        .collect()
}

fn get_test_file_contents(lint_name: &str) -> String {
    format!(
        "#![warn(clippy::{})]

fn main() {{
    // test code goes here
}}
",
        lint_name
    )
}

fn get_lint_file_contents(
    pass_type: &str,
    pass_lifetimes: &str,
    lint_name: &str,
    camel_case_name: &str,
    category: &str,
    pass_import: &str,
    context_import: &str,
) -> String {
    format!(
        "use rustc_lint::{{LintArray, LintPass, {type}, {context_import}}};
use rustc_session::{{declare_lint_pass, declare_tool_lint}};
{pass_import}

declare_clippy_lint! {{
    /// **What it does:**
    ///
    /// **Why is this bad?**
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// // example code
    /// ```
    pub {name_upper},
    {category},
    \"default lint description\"
}}

declare_lint_pass!({name_camel} => [{name_upper}]);

impl {type}{lifetimes} for {name_camel} {{}}
",
        type=pass_type,
        lifetimes=pass_lifetimes,
        name_upper=lint_name.to_uppercase(),
        name_camel=camel_case_name,
        category=category,
        pass_import=pass_import,
        context_import=context_import
    )
}

#[test]
fn test_camel_case() {
    let s = "a_lint";
    let s2 = to_camel_case(s);
    assert_eq!(s2, "ALint");

    let name = "a_really_long_new_lint";
    let name2 = to_camel_case(name);
    assert_eq!(name2, "AReallyLongNewLint");

    let name3 = "lint__name";
    let name4 = to_camel_case(name3);
    assert_eq!(name4, "LintName");
}
<commit_msg>Remove unnecessary imports from `new_lint` tool<commit_after>use clippy_dev::clippy_project_root;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::prelude::*;
use std::io::ErrorKind;
use std::path::Path;

pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str>) -> Result<(), io::Error> {
    let pass = pass.expect("`pass` argument is validated by clap");
    let lint_name = lint_name.expect("`name` argument is validated by clap");
    let category = category.expect("`category` argument is validated by clap");

    match open_files(lint_name) {
        Ok((mut test_file, mut lint_file)) => {
            let (pass_type, pass_lifetimes, pass_import, context_import) = match pass {
                "early" => ("EarlyLintPass", "", "use syntax::ast::*;", "EarlyContext"),
                "late" => ("LateLintPass", "<'_, '_>", "use rustc_hir::*;", "LateContext"),
                _ => {
                    unreachable!("`pass_type` should only ever be `early` or `late`!");
                },
            };

            let camel_case_name = to_camel_case(lint_name);

            if let Err(e) = test_file.write_all(get_test_file_contents(lint_name).as_bytes()) {
                return Err(io::Error::new(
                    ErrorKind::Other,
                    format!("Could not write to test file: {}", e),
                ));
            };

            if let Err(e) = lint_file.write_all(
                get_lint_file_contents(
                    pass_type,
                    pass_lifetimes,
                    lint_name,
                    &camel_case_name,
                    category,
                    pass_import,
                    context_import,
                )
                .as_bytes(),
            ) {
                return Err(io::Error::new(
                    ErrorKind::Other,
                    format!("Could not write to lint file: {}", e),
                ));
            }
            Ok(())
        },
        Err(e) => Err(io::Error::new(
            ErrorKind::Other,
            format!("Unable to create lint: {}", e),
        )),
    }
}

fn open_files(lint_name: &str) -> Result<(File, File), io::Error> {
    let project_root = clippy_project_root();

    let test_file_path = project_root.join("tests").join("ui").join(format!("{}.rs", lint_name));
    let lint_file_path = project_root
        .join("clippy_lints")
        .join("src")
        .join(format!("{}.rs", lint_name));

    if Path::new(&test_file_path).exists() {
        return Err(io::Error::new(
            ErrorKind::AlreadyExists,
            format!("test file {:?} already exists", test_file_path),
        ));
    }
    if Path::new(&lint_file_path).exists() {
        return Err(io::Error::new(
            ErrorKind::AlreadyExists,
            format!("lint file {:?} already exists", lint_file_path),
        ));
    }

    let test_file = OpenOptions::new().write(true).create_new(true).open(test_file_path)?;
    let lint_file = OpenOptions::new().write(true).create_new(true).open(lint_file_path)?;

    Ok((test_file, lint_file))
}

fn to_camel_case(name: &str) -> String {
    name.split('_')
        .map(|s| {
            if s.is_empty() {
                String::from("")
            } else {
                [&s[0..1].to_uppercase(), &s[1..]].concat()
            }
        })
        .collect()
}

fn get_test_file_contents(lint_name: &str) -> String {
    format!(
        "#![warn(clippy::{})]

fn main() {{
    // test code goes here
}}
",
        lint_name
    )
}

fn get_lint_file_contents(
    pass_type: &str,
    pass_lifetimes: &str,
    lint_name: &str,
    camel_case_name: &str,
    category: &str,
    pass_import: &str,
    context_import: &str,
) -> String {
    format!(
        "use rustc_lint::{{{type}, {context_import}}};
use rustc_session::{{declare_lint_pass, declare_tool_lint}};
{pass_import}

declare_clippy_lint! {{
    /// **What it does:**
    ///
    /// **Why is this bad?**
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// // example code
    /// ```
    pub {name_upper},
    {category},
    \"default lint description\"
}}

declare_lint_pass!({name_camel} => [{name_upper}]);

impl {type}{lifetimes} for {name_camel} {{}}
",
        type=pass_type,
        lifetimes=pass_lifetimes,
        name_upper=lint_name.to_uppercase(),
        name_camel=camel_case_name,
        category=category,
        pass_import=pass_import,
        context_import=context_import
    )
}

#[test]
fn test_camel_case() {
    let s = "a_lint";
    let s2 = to_camel_case(s);
    assert_eq!(s2, "ALint");

    let name = "a_really_long_new_lint";
    let name2 = to_camel_case(name);
    assert_eq!(name2, "AReallyLongNewLint");

    let name3 = "lint__name";
    let name4 = to_camel_case(name3);
    assert_eq!(name4, "LintName");
}
<|endoftext|>


<commit_before>//! Handling of `preserveAspectRatio` values
//!
//! This module handles `preserveAspectRatio` values [per the SVG specification][spec].
//! We have an [`AspectRatio`] struct which encapsulates such a value.
//!
//! ```ignore
//! assert_eq!(
//!     AspectRatio::parse("xMidYMid", ()),
//!     Ok(AspectRatio {
//!         defer: false,
//!         align: Some(Align {
//!             x: Align1D::Mid,
//!             y: Align1D::Mid,
//!             fit: FitMode::Meet,
//!         }),
//!     })
//! );
//! ```
//!
//! [`AspectRatio`]: struct.AspectRatio.html
//! [spec]: https://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute

use cssparser::{Parser, ParserInput};
use error::*;
use parsers::Parse;
use parsers::ParseError;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct AspectRatio {
    defer: bool,
    align: Option<Align>,
}

impl Default for AspectRatio {
    fn default() -> AspectRatio {
        AspectRatio {
            defer: false,
            align: Some(Align::default()),
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum FitMode {
    Meet,
    Slice,
}

impl Default for FitMode {
    fn default() -> FitMode {
        FitMode::Meet
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct Align {
    x: Align1D,
    y: Align1D,
    fit: FitMode,
}

impl Default for Align {
    fn default() -> Align {
        Align {
            x: Align1D::Mid,
            y: Align1D::Mid,
            fit: FitMode::default(),
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum Align1D {
    Min,
    Mid,
    Max,
}

impl Align1D {
    fn compute(self, dest_pos: f64, dest_size: f64, obj_size: f64) -> f64 {
        match self {
            Align1D::Min => dest_pos,
            Align1D::Mid => dest_pos + (dest_size - obj_size) / 2.0,
            Align1D::Max => dest_pos + dest_size - obj_size,
        }
    }
}

impl AspectRatio {
    pub fn is_slice(&self) -> bool {
        match self.align {
            Some(Align {
                fit: FitMode::Slice,
                ..
            }) => true,

            _ => false,
        }
    }

    pub fn compute(
        &self,
        object_width: f64,
        object_height: f64,
        dest_x: f64,
        dest_y: f64,
        dest_width: f64,
        dest_height: f64,
    ) -> (f64, f64, f64, f64) {
        match self.align {
            None => (dest_x, dest_y, dest_width, dest_height),

            Some(Align { x, y, fit }) => {
                let w_factor = dest_width / object_width;
                let h_factor = dest_height / object_height;
                let factor = match fit {
                    FitMode::Meet => w_factor.min(h_factor),
                    FitMode::Slice => w_factor.max(h_factor),
                };

                let w = object_width * factor;
                let h = object_height * factor;

                let xpos = x.compute(dest_x, dest_width, w);
                let ypos = y.compute(dest_y, dest_height, h);

                (xpos, ypos, w, h)
            }
        }
    }

    fn parse_input<'i, 't>(p: &mut Parser<'i, 't>) -> Result<AspectRatio, ()> {
        let defer = p.try(|p| p.expect_ident_matching("defer")).is_ok();

        let align_xy = p.try(|p| {
            p.expect_ident()
                .map_err(|_| ())
                .and_then(|ident| Align::parse_xy(ident))
        })?;

        let fit = p.try(|p| {
            p.expect_ident()
                .map_err(|_| ())
                .and_then(|ident| FitMode::parse(ident))
        }).unwrap_or(FitMode::default());

        p.expect_exhausted().map_err(|_| ())?;

        let align = align_xy.map(|(x, y)| Align { x, y, fit });

        Ok(AspectRatio { defer, align })
    }
}

impl Align {
    fn parse_xy(s: &str) -> Result<Option<(Align1D, Align1D)>, ()> {
        use self::Align1D::*;

        match s {
            "none" => Ok(None),

            "xMinYMin" => Ok(Some((Min, Min))),
            "xMidYMin" => Ok(Some((Mid, Min))),
            "xMaxYMin" => Ok(Some((Max, Min))),

            "xMinYMid" => Ok(Some((Min, Mid))),
            "xMidYMid" => Ok(Some((Mid, Mid))),
            "xMaxYMid" => Ok(Some((Max, Mid))),

            "xMinYMax" => Ok(Some((Min, Max))),
            "xMidYMax" => Ok(Some((Mid, Max))),
            "xMaxYMax" => Ok(Some((Max, Max))),

            _ => Err(()),
        }
    }
}

impl FitMode {
    fn parse(s: &str) -> Result<FitMode, ()> {
        match s {
            "meet" => Ok(FitMode::Meet),
            "slice" => Ok(FitMode::Slice),
            _ => Err(()),
        }
    }
}

impl Parse for AspectRatio {
    type Data = ();
    type Err = AttributeError;

    fn parse(s: &str, _: ()) -> Result<AspectRatio, AttributeError> {
        let mut input = ParserInput::new(s);
        AspectRatio::parse_input(&mut Parser::new(&mut input)).map_err(|_| {
            AttributeError::Parse(ParseError::new(
                "expected \"[defer] <align> [meet | slice]\"",
            ))
        })
    }
}

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

    #[test]
    fn parsing_invalid_strings_yields_error() {
        assert!(AspectRatio::parse("", ()).is_err());

        assert!(AspectRatio::parse("defer", ()).is_err());

        assert!(AspectRatio::parse("defer foo", ()).is_err());

        assert!(AspectRatio::parse("defer xmidymid", ()).is_err());

        assert!(AspectRatio::parse("defer xMidYMid foo", ()).is_err());

        assert!(AspectRatio::parse("xmidymid", ()).is_err());

        assert!(AspectRatio::parse("xMidYMid foo", ()).is_err());

        assert!(AspectRatio::parse("defer xMidYMid meet foo", ()).is_err());
    }

    #[test]
    fn parses_valid_strings() {
        assert_eq!(
            AspectRatio::parse("defer none", ()),
            Ok(AspectRatio {
                defer: true,
                align: None,
            },)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMid", ()),
            Ok(AspectRatio {
                defer: false,
                align: Some(Align {
                    x: Align1D::Mid,
                    y: Align1D::Mid,
                    fit: FitMode::Meet,
                },),
            },)
        );

        assert_eq!(
            AspectRatio::parse("defer xMidYMid", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: Align1D::Mid,
                    y: Align1D::Mid,
                    fit: FitMode::Meet,
                },),
            },)
        );

        assert_eq!(
            AspectRatio::parse("defer xMinYMax", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: Align1D::Min,
                    y: Align1D::Max,
                    fit: FitMode::Meet,
                },),
            },)
        );

        assert_eq!(
            AspectRatio::parse("defer xMaxYMid meet", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: Align1D::Max,
                    y: Align1D::Mid,
                    fit: FitMode::Meet,
                },),
            },)
        );

        assert_eq!(
            AspectRatio::parse("defer xMinYMax slice", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: Align1D::Min,
                    y: Align1D::Max,
                    fit: FitMode::Slice,
                },),
            },)
        );
    }

    #[test]
    fn aligns() {
        assert_eq!(
            AspectRatio::parse("xMinYMin meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMinYMin slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMinYMid meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMinYMid slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -49.5, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMinYMax meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMinYMax slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -99.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMin meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (4.95, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMidYMin slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMid meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (4.95, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMidYMid slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -49.5, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMax meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (4.95, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMidYMax slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -99.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMaxYMin meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (9.9, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMaxYMin slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, 0.0, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMaxYMid meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (9.9, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMaxYMid slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -49.5, 10.0, 100.0)
        );

        assert_eq!(
            AspectRatio::parse("xMaxYMax meet", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (9.9, 0.0, 0.1, 1.0)
        );
        assert_eq!(
            AspectRatio::parse("xMaxYMax slice", ()).unwrap().compute(
                1.0,
                10.0,
                0.0,
                0.0,
                10.0,
                1.0,
            ),
            (0.0, -99.0, 10.0, 100.0)
        );
    }
}
<commit_msg>aspect_ratio: make tests more compact.<commit_after>//! Handling of `preserveAspectRatio` values
//!
//! This module handles `preserveAspectRatio` values [per the SVG specification][spec].
//! We have an [`AspectRatio`] struct which encapsulates such a value.
//!
//! ```ignore
//! assert_eq!(
//!     AspectRatio::parse("xMidYMid", ()),
//!     Ok(AspectRatio {
//!         defer: false,
//!         align: Some(Align {
//!             x: Align1D::Mid,
//!             y: Align1D::Mid,
//!             fit: FitMode::Meet,
//!         }),
//!     })
//! );
//! ```
//!
//! [`AspectRatio`]: struct.AspectRatio.html
//! [spec]: https://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute

use cssparser::{Parser, ParserInput};
use error::*;
use parsers::Parse;
use parsers::ParseError;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct AspectRatio {
    defer: bool,
    align: Option<Align>,
}

impl Default for AspectRatio {
    fn default() -> AspectRatio {
        AspectRatio {
            defer: false,
            align: Some(Align::default()),
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum FitMode {
    Meet,
    Slice,
}

impl Default for FitMode {
    fn default() -> FitMode {
        FitMode::Meet
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct Align {
    x: Align1D,
    y: Align1D,
    fit: FitMode,
}

impl Default for Align {
    fn default() -> Align {
        Align {
            x: Align1D::Mid,
            y: Align1D::Mid,
            fit: FitMode::default(),
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum Align1D {
    Min,
    Mid,
    Max,
}

impl Align1D {
    fn compute(self, dest_pos: f64, dest_size: f64, obj_size: f64) -> f64 {
        match self {
            Align1D::Min => dest_pos,
            Align1D::Mid => dest_pos + (dest_size - obj_size) / 2.0,
            Align1D::Max => dest_pos + dest_size - obj_size,
        }
    }
}

impl AspectRatio {
    pub fn is_slice(&self) -> bool {
        match self.align {
            Some(Align {
                fit: FitMode::Slice,
                ..
            }) => true,

            _ => false,
        }
    }

    pub fn compute(
        &self,
        object_width: f64,
        object_height: f64,
        dest_x: f64,
        dest_y: f64,
        dest_width: f64,
        dest_height: f64,
    ) -> (f64, f64, f64, f64) {
        match self.align {
            None => (dest_x, dest_y, dest_width, dest_height),

            Some(Align { x, y, fit }) => {
                let w_factor = dest_width / object_width;
                let h_factor = dest_height / object_height;
                let factor = match fit {
                    FitMode::Meet => w_factor.min(h_factor),
                    FitMode::Slice => w_factor.max(h_factor),
                };

                let w = object_width * factor;
                let h = object_height * factor;

                let xpos = x.compute(dest_x, dest_width, w);
                let ypos = y.compute(dest_y, dest_height, h);

                (xpos, ypos, w, h)
            }
        }
    }

    fn parse_input<'i, 't>(p: &mut Parser<'i, 't>) -> Result<AspectRatio, ()> {
        let defer = p.try(|p| p.expect_ident_matching("defer")).is_ok();

        let align_xy = p.try(|p| {
            p.expect_ident()
                .map_err(|_| ())
                .and_then(|ident| Align::parse_xy(ident))
        })?;

        let fit = p.try(|p| {
            p.expect_ident()
                .map_err(|_| ())
                .and_then(|ident| FitMode::parse(ident))
        }).unwrap_or(FitMode::default());

        p.expect_exhausted().map_err(|_| ())?;

        let align = align_xy.map(|(x, y)| Align { x, y, fit });

        Ok(AspectRatio { defer, align })
    }
}

impl Align {
    fn parse_xy(s: &str) -> Result<Option<(Align1D, Align1D)>, ()> {
        use self::Align1D::*;

        match s {
            "none" => Ok(None),

            "xMinYMin" => Ok(Some((Min, Min))),
            "xMidYMin" => Ok(Some((Mid, Min))),
            "xMaxYMin" => Ok(Some((Max, Min))),

            "xMinYMid" => Ok(Some((Min, Mid))),
            "xMidYMid" => Ok(Some((Mid, Mid))),
            "xMaxYMid" => Ok(Some((Max, Mid))),

            "xMinYMax" => Ok(Some((Min, Max))),
            "xMidYMax" => Ok(Some((Mid, Max))),
            "xMaxYMax" => Ok(Some((Max, Max))),

            _ => Err(()),
        }
    }
}

impl FitMode {
    fn parse(s: &str) -> Result<FitMode, ()> {
        match s {
            "meet" => Ok(FitMode::Meet),
            "slice" => Ok(FitMode::Slice),
            _ => Err(()),
        }
    }
}

impl Parse for AspectRatio {
    type Data = ();
    type Err = AttributeError;

    fn parse(s: &str, _: ()) -> Result<AspectRatio, AttributeError> {
        let mut input = ParserInput::new(s);
        AspectRatio::parse_input(&mut Parser::new(&mut input)).map_err(|_| {
            AttributeError::Parse(ParseError::new(
                "expected \"[defer] <align> [meet | slice]\"",
            ))
        })
    }
}

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

    #[test]
    fn parsing_invalid_strings_yields_error() {
        assert!(AspectRatio::parse("", ()).is_err());
        assert!(AspectRatio::parse("defer", ()).is_err());
        assert!(AspectRatio::parse("defer foo", ()).is_err());
        assert!(AspectRatio::parse("defer xmidymid", ()).is_err());
        assert!(AspectRatio::parse("defer xMidYMid foo", ()).is_err());
        assert!(AspectRatio::parse("xmidymid", ()).is_err());
        assert!(AspectRatio::parse("xMidYMid foo", ()).is_err());
        assert!(AspectRatio::parse("defer xMidYMid meet foo", ()).is_err());
    }

    #[test]
    fn parses_valid_strings() {
        assert_eq!(
            AspectRatio::parse("defer none", ()),
            Ok(AspectRatio {
                defer: true,
                align: None,
            },)
        );

        assert_eq!(
            AspectRatio::parse("xMidYMid", ()),
            Ok(AspectRatio {
                defer: false,
                align: Some(Align {
                    x: Align1D::Mid,
                    y: Align1D::Mid,
                    fit: FitMode::Meet,
                },),
            },)
        );

        assert_eq!(
            AspectRatio::parse("defer xMidYMid", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: Align1D::Mid,
                    y: Align1D::Mid,
                    fit: FitMode::Meet,
                },),
            },)
        );

        assert_eq!(
            AspectRatio::parse("defer xMinYMax", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: Align1D::Min,
                    y: Align1D::Max,
                    fit: FitMode::Meet,
                },),
            },)
        );

        assert_eq!(
            AspectRatio::parse("defer xMaxYMid meet", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: Align1D::Max,
                    y: Align1D::Mid,
                    fit: FitMode::Meet,
                },),
            },)
        );

        assert_eq!(
            AspectRatio::parse("defer xMinYMax slice", ()),
            Ok(AspectRatio {
                defer: true,
                align: Some(Align {
                    x: Align1D::Min,
                    y: Align1D::Max,
                    fit: FitMode::Slice,
                },),
            },)
        );
    }

    #[test]
    fn aligns() {
        let foo = AspectRatio::parse("xMinYMin meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse("xMinYMin slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, 0.0, 10.0, 100.0));

        let foo = AspectRatio::parse("xMinYMid meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse("xMinYMid slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);

        assert_eq!(foo, (0.0, -49.5, 10.0, 100.0));

        let foo = AspectRatio::parse("xMinYMax meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse("xMinYMax slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, -99.0, 10.0, 100.0));

        let foo = AspectRatio::parse("xMidYMin meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (4.95, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse("xMidYMin slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, 0.0, 10.0, 100.0));

        let foo = AspectRatio::parse("xMidYMid meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (4.95, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse("xMidYMid slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, -49.5, 10.0, 100.0));

        let foo = AspectRatio::parse("xMidYMax meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (4.95, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse("xMidYMax slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, -99.0, 10.0, 100.0));

        let foo = AspectRatio::parse("xMaxYMin meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (9.9, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse("xMaxYMin slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, 0.0, 10.0, 100.0));

        let foo = AspectRatio::parse("xMaxYMid meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (9.9, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse("xMaxYMid slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, -49.5, 10.0, 100.0));

        let foo = AspectRatio::parse("xMaxYMax meet", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (9.9, 0.0, 0.1, 1.0));

        let foo = AspectRatio::parse("xMaxYMax slice", ()).unwrap();
        let foo = foo.compute(1.0, 10.0, 0.0, 0.0, 10.0, 1.0);
        assert_eq!(foo, (0.0, -99.0, 10.0, 100.0));
    }
}
<|endoftext|>


<commit_before>extern crate clap;

use clap::{App, Arg};

fn main() {

    // Positional arguments are those values after the program name which are not preceded by any
    // identifier (such as "myapp some_file"). Positionals support many of the same options as
    // flags, as well as a few additional ones.
    let matches = App::new("MyApp")
                        // Regular App configuration goes here...

                        // We'll add two positional arguments, a input file, and a config file.
                        //
                        // I'll explain each possible setting that "positionals" accept. Keep in
                        // mind that you DO NOT need to set each of these for every flag, only the
                        // ones that apply to your individual case.
                        .arg(Arg::with_name("input")
                                    .help("the input file to use") // Displayed when showing help info
                                    .index(1)                      // Set the order in which the user must
                                                                   // specify this argument (Starts at 1)
                                    .requires("config")            // Says, "If the user uses "input", they MUST
                                                                   // also use this other 'config' arg too"
                                                                   // Can also specify a list using
                                                                   // requires_all(Vec<&str>)
                                    .conflicts_with("output")      // Opposite of requires(), says "if the
                                                                   // user uses -a, they CANNOT use 'output'"
                                                                   // also has a mutually_excludes_all(Vec<&str>)
                                    .required(true)                // By default this argument MUST be present
                                                                   // NOTE: mutual exclusions take precedence over
                                                                   // required arguments
                        )
                        .arg(Arg::with_name("config")
                                    .help("the config file to use")
                                    .index(2))                     // Note, we do not need to specify required(true)
                                                                   // if we don't want to, because "input" already
                                                                   // requires "config"
                                                                   // Note, we also do not need to specify requires("input")
                                                                   // because requires lists are automatically two-way

                        // NOTE: In order to compile this example, comment out mutually_excludes()
                        // because we have not defined an "output" argument.
                        .get_matches();

    // We can find out whether or not "input" or "config" were used
    if matches.is_present("input") {
        println!("An input file was specified");
    }

    // We can also get the values for those arguments
    if let Some(in_file) = matches.value_of("input") {
        // It's safe to call unwrap() because of the required options we set above
        println!("Doing work with {} and {}", in_file, matches.value_of("config").unwrap());
    }
    // Continued program logic goes here...
}
<commit_msg>Update 06_positional_args.rs<commit_after>extern crate clap;

use clap::{App, Arg};

fn main() {

    // Positional arguments are those values after the program name which are not preceded by any
    // identifier (such as "myapp some_file"). Positionals support many of the same options as
    // flags, as well as a few additional ones.
    let matches = App::new("MyApp")
                        // Regular App configuration goes here...

                        // We'll add two positional arguments, a input file, and a config file.
                        //
                        // I'll explain each possible setting that "positionals" accept. Keep in
                        // mind that you DO NOT need to set each of these for every flag, only the
                        // ones that apply to your individual case.
                        .arg(Arg::with_name("input")
                                    .help("the input file to use") // Displayed when showing help info
                                    .index(1)                      // Set the order in which the user must
                                                                   // specify this argument (Starts at 1)
                                    .requires("config")            // Says, "If the user uses "input", they MUST
                                                                   // also use this other 'config' arg too"
                                                                   // Can also specify a list using
                                                                   // requires_all(Vec<&str>)
                                    .conflicts_with("output")      // Opposite of requires(), says "if the
                                                                   // user uses -a, they CANNOT use 'output'"
                                                                   // also has a conflicts_with_all(Vec<&str>)
                                    .required(true)                // By default this argument MUST be present
                                                                   // NOTE: mutual exclusions take precedence over
                                                                   // required arguments
                        )
                        .arg(Arg::with_name("config")
                                    .help("the config file to use")
                                    .index(2))                     // Note, we do not need to specify required(true)
                                                                   // if we don't want to, because "input" already
                                                                   // requires "config"
                                                                   // Note, we also do not need to specify requires("input")
                                                                   // because requires lists are automatically two-way

                        // NOTE: In order to compile this example, comment out conflicts_with()
                        // because we have not defined an "output" argument.
                        .get_matches();

    // We can find out whether or not "input" or "config" were used
    if matches.is_present("input") {
        println!("An input file was specified");
    }

    // We can also get the values for those arguments
    if let Some(in_file) = matches.value_of("input") {
        // It's safe to call unwrap() because of the required options we set above
        println!("Doing work with {} and {}", in_file, matches.value_of("config").unwrap());
    }
    // Continued program logic goes here...
}
<|endoftext|>