<commit_before>use regex::Regex;
use std::sync::mpsc::channel;

use adapter::ChatAdapter;
use handler::MessageHandler;

/// The Chatbot is the central data structure of the chatbot platform. It contains a `run` method
/// which listens for messages from adapters and routes them to handlers. Any program which uses
/// chatbot will need to minimally create a Chatbot, add an adapter, add a handler, and call Chatbot
/// [`run`](chatbot/struct.Chatbot.html#method.run).
pub struct Chatbot {
    name: String,
    adapters: Vec<Box<ChatAdapter>>,
    handlers: Vec<Box<MessageHandler>>,
    addressed_handlers: Vec<Box<MessageHandler>>,
    addresser: Regex
}

impl Chatbot {
    /// Create a new chatbot instance.
    ///
    /// The name provided here will be used for message filtering and in handlers for whatever they
    /// want. You'll want to make your binding mutable so you can call `add_adapter` and
    /// `add_handler`.
    pub fn new(name: &str) -> Chatbot {
        let addresser_str = format!(r"^\s*@?{}[:,\s]\s*", name);
        let addresser = Regex::new(addresser_str.as_ref());

        Chatbot {
            name: name.to_owned(),
            adapters: Vec::new(),
            handlers: Vec::new(),
            addressed_handlers: Vec::new(),
            addresser: addresser.unwrap()
        }
    }

    /// Return the name provided in initialization
    pub fn get_name(&self) -> &str {
        self.name.as_ref()
    }

    /// Return the regular expression of what the bot will be addressed by
    pub fn get_addresser(&self) -> &Regex {
        &self.addresser
    }

    /// Add a ChatAdapter to the bot
    ///
    /// Add as many adapters as you like. The IncomingMessages sent by adapters are made available
    /// to all handlers regardless of how many adapters exist. The IncomingMessage.reply method
    /// makes sure the response is sent back to the adapter from whence the message came.
    pub fn add_adapter<T>(&mut self, adapter: T)
        where T: ChatAdapter + 'static
    {
        println!("Adding adapter {}", adapter.get_name());
        self.adapters.push(Box::new(adapter))
    }

    /// Add a MessageHandler to the bot
    ///
    /// The more handlers you have the more useful your bot becomes (for potentially loose
    /// definitions of useful :P). Check out the handler! macro for making simple handlers and also
    /// see the `MessageHandler` implementors section for a list of built in handlers.
    pub fn add_handler<T>(&mut self, handler: T)
        where T: MessageHandler + 'static
    {
        println!("Adding handler {}", handler.name());
        self.handlers.push(Box::new(handler))
    }

    pub fn add_addressed_handler<T>(&mut self, handler: T)
        where T: MessageHandler + 'static
    {
        println!("Adding handler {}", handler.name());
        self.addressed_handlers.push(Box::new(handler))
    }

    /// Start processing messages
    ///
    /// Call process_events on all of the adapters and `recv` on the `IncomingMessage` channel.
    /// Distribute IncomingMessages to list of handlers.
    pub fn run(&self) {

        assert!(self.adapters.len() > 0);
        assert!(self.handlers.len() > 0);

        println!("Chatbot: {} adapters", self.adapters.len());
        println!("Chatbot: {} handlers", self.handlers.len());

        let (incoming_tx, incoming_rx) = channel();

        for adapter in &self.adapters {
            adapter.process_events(self, incoming_tx.clone());
        }

        loop {
            // Get message from adapter
            let msg = match incoming_rx.recv() {
                Ok(msg) => msg,
                Err(_) => break
            };

            // Distribute to handlers
            for handler in &self.handlers {
                let msg_str = msg.get_contents();

                if handler.can_handle(msg_str) {
                    // When addresser is present, ignore handlers that don't directly call the
                    // bot's name
                    if let Some(ref addresser) = self.addresser {
                        if !addresser.is_match(msg_str) {
                            continue;
                        }
                    }

                    match handler.handle(&msg) {
                        Err(e) => {
                            println!("Error in handler `{}`", handler.name());
                            println!("{:?}", e);
                            println!("The incoming message was {}", msg_str);

                            // TODO remove handler?
                        },
                        _ => ()
                    }
                }
            }
        }

        println!("chatbot shutting down");
    }
}

#[cfg(test)]
mod tests {
    use chatbot::Chatbot;
    use adapter::CliAdapter;

    #[test]
    fn test_create_chatbot() {
        let name = "testbot";
        let bot = Chatbot::new("testbot");
        assert_eq!(bot.get_name(), name);
    }

    #[test]
    fn test_chatbot_add_adapter() {
        let mut bot = Chatbot::new("testbot");
        let cli = CliAdapter::new();
        bot.add_adapter(cli);
    }

    #[test]
    fn test_chatbot_add_handler() {
        let mut bot = Chatbot::new("testbot");
        let echo = handler!("EchoHandler", r"echo .+", |_, msg| {
            Some(msg.to_owned())
        });
        bot.add_handler(echo);
    }

    #[test]
    fn test_chatbot_address_by_name() {
        let mut bot = Chatbot::new("testbot");
        bot.address_by_name();
    }

    #[test]
    fn test_chatbot_address_matches() {
        let mut bot = Chatbot::new("testbot");
        bot.address_by_name();
        let addresser = bot.get_addresser().unwrap();

        assert!(!addresser.is_match("testbotping"),
                "Shouldn't match bot name without a break (space, colon, comma)");
        assert!(!addresser.is_match("@testbotping"),
                "Shouldn't match bot name with '@' sign minus a break (space, colon, comma)");

        // Space separation
        assert!(addresser.is_match("testbot ping"), "Should match bot name with space");
        assert!(addresser.is_match("@testbot ping"),
                "Should match bot name with '@' sign plus '@' space");

        // Colon separation
        assert!(addresser.is_match("testbot:ping"), "Should match bot name with colon");
        assert!(addresser.is_match("testbot: ping"), "Should match bot name with colon and space");
        assert!(addresser.is_match("@testbot:ping"),
                "Should match bot name with '@' sign plus colon");
        assert!(addresser.is_match("@testbot: ping"),
                "Should match bot name with '@' sign plus colon and space");

        // Comma separation
        assert!(addresser.is_match("testbot,ping"), "Should match bot name with comma");
        assert!(addresser.is_match("testbot, ping"), "Should match bot name with comma and space");
        assert!(addresser.is_match("@testbot,ping"),
                "Should match bot name with '@' sign plus comma");
        assert!(addresser.is_match("@testbot, ping"),
                "Should match bot name with '@' sign plus comma and space");
    }
}
<commit_msg>Handle the two different handler lists separately<commit_after>use regex::Regex;
use std::sync::mpsc::channel;

use adapter::ChatAdapter;
use handler::MessageHandler;

/// The Chatbot is the central data structure of the chatbot platform. It contains a `run` method
/// which listens for messages from adapters and routes them to handlers. Any program which uses
/// chatbot will need to minimally create a Chatbot, add an adapter, add a handler, and call Chatbot
/// [`run`](chatbot/struct.Chatbot.html#method.run).
pub struct Chatbot {
    name: String,
    adapters: Vec<Box<ChatAdapter>>,
    handlers: Vec<Box<MessageHandler>>,
    addressed_handlers: Vec<Box<MessageHandler>>,
    addresser: Regex
}

impl Chatbot {
    /// Create a new chatbot instance.
    ///
    /// The name provided here will be used for message filtering and in handlers for whatever they
    /// want. You'll want to make your binding mutable so you can call `add_adapter` and
    /// `add_handler`.
    pub fn new(name: &str) -> Chatbot {
        let addresser_str = format!(r"^\s*@?{}[:,\s]\s*", name);
        let addresser = Regex::new(addresser_str.as_ref());

        Chatbot {
            name: name.to_owned(),
            adapters: Vec::new(),
            handlers: Vec::new(),
            addressed_handlers: Vec::new(),
            addresser: addresser.unwrap()
        }
    }

    /// Return the name provided in initialization
    pub fn get_name(&self) -> &str {
        self.name.as_ref()
    }

    /// Return the regular expression of what the bot will be addressed by
    pub fn get_addresser(&self) -> &Regex {
        &self.addresser
    }

    /// Add a ChatAdapter to the bot
    ///
    /// Add as many adapters as you like. The IncomingMessages sent by adapters are made available
    /// to all handlers regardless of how many adapters exist. The IncomingMessage.reply method
    /// makes sure the response is sent back to the adapter from whence the message came.
    pub fn add_adapter<T>(&mut self, adapter: T)
        where T: ChatAdapter + 'static
    {
        println!("Adding adapter {}", adapter.get_name());
        self.adapters.push(Box::new(adapter))
    }

    /// Add a MessageHandler to the bot
    ///
    /// The more handlers you have the more useful your bot becomes (for potentially loose
    /// definitions of useful :P). Check out the handler! macro for making simple handlers and also
    /// see the `MessageHandler` implementors section for a list of built in handlers.
    pub fn add_handler<T>(&mut self, handler: T)
        where T: MessageHandler + 'static
    {
        println!("Adding handler {}", handler.name());
        self.handlers.push(Box::new(handler))
    }

    pub fn add_addressed_handler<T>(&mut self, handler: T)
        where T: MessageHandler + 'static
    {
        println!("Adding handler {}", handler.name());
        self.addressed_handlers.push(Box::new(handler))
    }

    /// Start processing messages
    ///
    /// Call process_events on all of the adapters and `recv` on the `IncomingMessage` channel.
    /// Distribute IncomingMessages to list of handlers.
    pub fn run(&self) {

        assert!(self.adapters.len() > 0);
        assert!(self.handlers.len() > 0);

        println!("Chatbot: {} adapters", self.adapters.len());
        println!("Chatbot: {} handlers", self.handlers.len());

        let (incoming_tx, incoming_rx) = channel();

        for adapter in &self.adapters {
            adapter.process_events(self, incoming_tx.clone());
        }

        loop {
            // Get message from adapter
            let msg = match incoming_rx.recv() {
                Ok(msg) => msg,
                Err(_) => break
            };
            let msg_str = msg.get_contents();

            let handlers = if self.addresser.is_match(msg_str) {
                &self.addressed_handlers
            } else {
                &self.handlers
            };

            // Distribute to handlers
            for handler in handlers {
                if handler.can_handle(msg_str) {
                    match handler.handle(&msg) {
                        Err(e) => {
                            println!("Error in handler `{}`", handler.name());
                            println!("{:?}", e);
                            println!("The incoming message was {}", msg_str);

                            // TODO remove handler?
                        },
                        _ => ()
                    }
                }
            }
        }

        println!("chatbot shutting down");
    }
}

#[cfg(test)]
mod tests {
    use chatbot::Chatbot;
    use adapter::CliAdapter;

    #[test]
    fn test_create_chatbot() {
        let name = "testbot";
        let bot = Chatbot::new("testbot");
        assert_eq!(bot.get_name(), name);
    }

    #[test]
    fn test_chatbot_add_adapter() {
        let mut bot = Chatbot::new("testbot");
        let cli = CliAdapter::new();
        bot.add_adapter(cli);
    }

    #[test]
    fn test_chatbot_add_handler() {
        let mut bot = Chatbot::new("testbot");
        let echo = handler!("EchoHandler", r"echo .+", |_, msg| {
            Some(msg.to_owned())
        });
        bot.add_handler(echo);
    }

    #[test]
    fn test_chatbot_address_by_name() {
        let mut bot = Chatbot::new("testbot");
        bot.address_by_name();
    }

    #[test]
    fn test_chatbot_address_matches() {
        let mut bot = Chatbot::new("testbot");
        bot.address_by_name();
        let addresser = bot.get_addresser().unwrap();

        assert!(!addresser.is_match("testbotping"),
                "Shouldn't match bot name without a break (space, colon, comma)");
        assert!(!addresser.is_match("@testbotping"),
                "Shouldn't match bot name with '@' sign minus a break (space, colon, comma)");

        // Space separation
        assert!(addresser.is_match("testbot ping"), "Should match bot name with space");
        assert!(addresser.is_match("@testbot ping"),
                "Should match bot name with '@' sign plus '@' space");

        // Colon separation
        assert!(addresser.is_match("testbot:ping"), "Should match bot name with colon");
        assert!(addresser.is_match("testbot: ping"), "Should match bot name with colon and space");
        assert!(addresser.is_match("@testbot:ping"),
                "Should match bot name with '@' sign plus colon");
        assert!(addresser.is_match("@testbot: ping"),
                "Should match bot name with '@' sign plus colon and space");

        // Comma separation
        assert!(addresser.is_match("testbot,ping"), "Should match bot name with comma");
        assert!(addresser.is_match("testbot, ping"), "Should match bot name with comma and space");
        assert!(addresser.is_match("@testbot,ping"),
                "Should match bot name with '@' sign plus comma");
        assert!(addresser.is_match("@testbot, ping"),
                "Should match bot name with '@' sign plus comma and space");
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate env_logger;

use std::io;
use std::io::prelude::*;
use std::process;

use super::client::Client;

pub fn main(_args: &clap::ArgMatches) {
    env_logger::init().unwrap();

    let client = Client::new("couchbase://localhost/default");

    let process_command = |cmd: &str| {
        match cmd {
            "exit" | "quit" => {
                process::exit(0);
            },
            "get" => {
            },
            "info" => {
                println!("{:?}", client);
            },
            _ => {
                println!("Unknown command \"{}\"", cmd);
            }
        }
    };

    let process_line = || {
        print!("gauc> ");
        let _ = io::stdout().flush();
        let mut input = String::new();
        match io::stdin().read_line(&mut input) {
            Ok(_) => {
                process_command(&input.trim());
            }
            _ => {}
        }
        return true;
    };

    while process_line() {}
}
<commit_msg>Handle empty command<commit_after>extern crate clap;
extern crate env_logger;

use std::io;
use std::io::prelude::*;
use std::process;

use super::client::Client;

pub fn main(_args: &clap::ArgMatches) {
    env_logger::init().unwrap();

    let client = Client::new("couchbase://localhost/default");

    let process_command = |cmd: &str| {
        match cmd {
            "exit" | "quit" => {
                process::exit(0);
            },
            "get" => {
            },
            "info" => {
                println!("{:?}", client);
            },
            "" => {
            },
            _ => {
                println!("Unknown command \"{}\"", cmd);
            }
        }
    };

    let process_line = || {
        print!("gauc> ");
        let _ = io::stdout().flush();
        let mut input = String::new();
        match io::stdin().read_line(&mut input) {
            Ok(_) => {
                process_command(&input.trim());
            }
            _ => {}
        }
        return true;
    };

    while process_line() {}
}
<|endoftext|>


<commit_before>use std::thread::{JoinHandle, spawn};
use std::sync::mpsc::{Receiver, channel};
use std::io::{self, BufRead};
extern crate itertools;
use self::itertools::Itertools;
use std::sync::mpsc::TryRecvError;

extern crate either;

pub enum Decision {
    None,
    ImportLines(String),
    ShowCategories,
    ResetCursor,
    Respond,
    Tell(String),
    ConnectServer,
    ConnectIrc(String),
    ConnectDiscord(String),
}

pub fn new() -> Iter {
    let (sender, receiver) = channel();
    Iter{
        _thread: spawn(move || {
            let stdin = io::stdin();
            for line in stdin.lock().lines() {
                match line {
                    Ok(s) => {
                        if sender.send(s).is_err() {
                            break;
                        }
                    },
                    Err(_) => {
                        break;
                    }
                }
            }
        }),
        receiver: receiver,
    }
}

pub struct Iter {
    _thread: JoinHandle<()>,
    receiver: Receiver<String>,
}

impl Iterator for Iter {
    type Item = Decision;

    fn next(&mut self) -> Option<Decision> {
        match self.receiver.try_recv() {
            Ok(s) => {
                let params = s.split('`')
                    .enumerate()
                    .flat_map(|(iter, s)| {
                        // If we are not in a quotation
                        if iter % 2 == 0 {
                            either::Left(s.split(' '))
                        } else {
                            use std::iter::once;
                            either::Right(once(s))
                        }
                    })
                    .filter(|s| !s.is_empty()).collect_vec();

                let help = || {
                    println!("Available commands: import, connect, list, respond, tell");
                    Some(Decision::ResetCursor)
                };

                match params.len() {
                    0 => {
                        help()
                    },
                    _ => {
                        match params[0] {
                            "help" => {
                                help()
                            },
                            "import" => {
                                if params.len() < 2 {
                                    println!("Usage: import <import type>");
                                    println!("Available import types: lines");
                                    Some(Decision::ResetCursor)
                                } else {
                                    match params[1] {
                                        "lines" => {
                                            if params.len() != 3 {
                                                println!("Usage: import lines <filname>");
                                                Some(Decision::ResetCursor)
                                            } else {
                                                println!("Importing lines from `{}`...", params[2]);
                                                Some(Decision::ImportLines(params[2].to_string()))
                                            }
                                        },
                                        _ => {
                                            println!("Ignored: Unrecognized import type");
                                            Some(Decision::ResetCursor)
                                        },
                                    }
                                }
                            },
                            "connect" => {
                                if params.len() < 2 {
                                    println!("Ignored: connect takes at least a connect type");
                                    println!("Connect types: server, irc, discord");
                                    Some(Decision::ResetCursor)
                                } else {
                                    match params[1] {
                                        "server" => {
                                            if params.len() != 2 {
                                                println!("Ignored: no extra parameters needed");
                                                Some(Decision::ResetCursor)
                                            } else {
                                                Some(Decision::ConnectServer)
                                            }
                                        },
                                        "irc" => {
                                            if params.len() != 3 {
                                                println!("Ignored: connect irc requires a config path");
                                                Some(Decision::ResetCursor)
                                            } else {
                                                Some(Decision::ConnectIrc(params[2].to_string()))
                                            }
                                        },
                                        "discord" => {
                                            if params.len() != 3 {
                                                println!("Ignored: connect discord requires a config path");
                                                Some(Decision::ResetCursor)
                                            } else {
                                                Some(Decision::ConnectDiscord(params[2].to_string()))
                                            }
                                        },
                                        _ => {
                                            println!("Ignored: Unrecognized connect type");
                                            Some(Decision::ResetCursor)
                                        },
                                    }
                                }
                            },
                            "list" => {
                                if params.len() != 2 {
                                    println!("Ignored: list takes 1 param");
                                    Some(Decision::ResetCursor)
                                } else {
                                    match params[1] {
                                        "categories" => {
                                            Some(Decision::ShowCategories)
                                        },
                                        _ => {
                                            println!("Ignored: Unrecognized list type");
                                            Some(Decision::ResetCursor)
                                        },
                                    }
                                }
                            },
                            "respond" => {
                                if params.len() != 1 {
                                    println!("Ignored: respond takes no params");
                                    Some(Decision::ResetCursor)
                                } else {
                                    Some(Decision::Respond)
                                }
                            },
                            "tell" => {
                                if params.len() != 2 {
                                    println!("Ignored: respond takes 1 param");
                                    Some(Decision::ResetCursor)
                                } else {
                                    Some(Decision::Tell(params[1].to_string()))
                                }
                            },
                            _ => {
                                println!("Ignored: Unrecognized command");
                                Some(Decision::ResetCursor)
                            },
                        }
                    }
                }
            },
            Err(TryRecvError::Empty) => {
                Some(Decision::None)
            },
            Err(TryRecvError::Disconnected) => {
                None
            },
        }
    }
}
<commit_msg>improve help more<commit_after>use std::thread::{JoinHandle, spawn};
use std::sync::mpsc::{Receiver, channel};
use std::io::{self, BufRead};
extern crate itertools;
use self::itertools::Itertools;
use std::sync::mpsc::TryRecvError;

extern crate either;

pub enum Decision {
    None,
    ImportLines(String),
    ShowCategories,
    ResetCursor,
    Respond,
    Tell(String),
    ConnectServer,
    ConnectIrc(String),
    ConnectDiscord(String),
}

pub fn new() -> Iter {
    let (sender, receiver) = channel();
    Iter{
        _thread: spawn(move || {
            let stdin = io::stdin();
            for line in stdin.lock().lines() {
                match line {
                    Ok(s) => {
                        if sender.send(s).is_err() {
                            break;
                        }
                    },
                    Err(_) => {
                        break;
                    }
                }
            }
        }),
        receiver: receiver,
    }
}

pub struct Iter {
    _thread: JoinHandle<()>,
    receiver: Receiver<String>,
}

impl Iterator for Iter {
    type Item = Decision;

    fn next(&mut self) -> Option<Decision> {
        match self.receiver.try_recv() {
            Ok(s) => {
                let params = s.split('`')
                    .enumerate()
                    .flat_map(|(iter, s)| {
                        // If we are not in a quotation
                        if iter % 2 == 0 {
                            either::Left(s.split(' '))
                        } else {
                            use std::iter::once;
                            either::Right(once(s))
                        }
                    })
                    .filter(|s| !s.is_empty()).collect_vec();

                let help = || {
                    println!("Available commands: import, connect, list, respond, tell");
                    Some(Decision::ResetCursor)
                };

                match params.len() {
                    0 => {
                        help()
                    },
                    _ => {
                        match params[0] {
                            "help" => {
                                help()
                            },
                            "import" => {
                                if params.len() < 2 {
                                    println!("Usage: import <import type>");
                                    println!("Available import types: lines");
                                    Some(Decision::ResetCursor)
                                } else {
                                    match params[1] {
                                        "lines" => {
                                            if params.len() != 3 {
                                                println!("Usage: import lines <filname>");
                                                Some(Decision::ResetCursor)
                                            } else {
                                                println!("Importing lines from `{}`...", params[2]);
                                                Some(Decision::ImportLines(params[2].to_string()))
                                            }
                                        },
                                        _ => {
                                            println!("Ignored: Unrecognized import type");
                                            Some(Decision::ResetCursor)
                                        },
                                    }
                                }
                            },
                            "connect" => {
                                if params.len() < 2 {
                                    println!("Ignored: connect takes at least a connect type");
                                    println!("Connect types: server, irc, discord");
                                    Some(Decision::ResetCursor)
                                } else {
                                    match params[1] {
                                        "server" => {
                                            if params.len() != 2 {
                                                println!("Ignored: no extra parameters needed");
                                                Some(Decision::ResetCursor)
                                            } else {
                                                Some(Decision::ConnectServer)
                                            }
                                        },
                                        "irc" => {
                                            if params.len() != 3 {
                                                println!("Usage: connect irc <config>");
                                                Some(Decision::ResetCursor)
                                            } else {
                                                Some(Decision::ConnectIrc(params[2].to_string()))
                                            }
                                        },
                                        "discord" => {
                                            if params.len() != 3 {
                                                println!("Usage: connect discord <config>");
                                                Some(Decision::ResetCursor)
                                            } else {
                                                Some(Decision::ConnectDiscord(params[2].to_string()))
                                            }
                                        },
                                        _ => {
                                            println!("Ignored: Unrecognized connect type");
                                            Some(Decision::ResetCursor)
                                        },
                                    }
                                }
                            },
                            "list" => {
                                if params.len() != 2 {
                                    println!("Usage: list <list type>");
                                    println!("Available list types: categories");
                                    Some(Decision::ResetCursor)
                                } else {
                                    match params[1] {
                                        "categories" => {
                                            Some(Decision::ShowCategories)
                                        },
                                        _ => {
                                            println!("Ignored: Unrecognized list type");
                                            Some(Decision::ResetCursor)
                                        },
                                    }
                                }
                            },
                            "respond" => {
                                if params.len() != 1 {
                                    println!("Usage: respond");
                                    Some(Decision::ResetCursor)
                                } else {
                                    Some(Decision::Respond)
                                }
                            },
                            "tell" => {
                                if params.len() != 2 {
                                    println!("Usage: tell <message>");
                                    Some(Decision::ResetCursor)
                                } else {
                                    Some(Decision::Tell(params[1].to_string()))
                                }
                            },
                            _ => {
                                println!("Ignored: Unrecognized command");
                                Some(Decision::ResetCursor)
                            },
                        }
                    }
                }
            },
            Err(TryRecvError::Empty) => {
                Some(Decision::None)
            },
            Err(TryRecvError::Disconnected) => {
                None
            },
        }
    }
}
<|endoftext|>


<commit_before>use std::ascii::AsciiExt;

#[cfg(not(target_os = "emscripten"))]
use std::io::{self, Write};

use direction::Direction;

#[cfg(target_os = "emscripten")]
use emscripten::{emscripten};

#[derive(Debug)]
pub enum PrimaryCommand {
  Go(Direction),
  Look,
  Quit,
}

type HelpInfo = &'static [(char, &'static str)];

pub trait CommandProcessor<T> {
  fn from_char(c: char) -> Option<T>;

  fn get_help() -> HelpInfo;

  fn prompt() -> &'static [u8] { b"> " }

  #[cfg(target_os = "emscripten")]
  fn show_prompt() {}

  #[cfg(not(target_os = "emscripten"))]
  fn show_prompt() {
    io::stdout().write(Self::prompt()).unwrap();
    io::stdout().flush().unwrap();
  }

  #[cfg(target_os = "emscripten")]
  fn read_input() -> Option<String> {
    if emscripten::run_script_int("has_input()") == 0 {
      None
    } else {
      Some(emscripten::run_script_string("get_input()"))
    }
  }

  #[cfg(not(target_os = "emscripten"))]
  fn read_input() -> Option<String> {
    let mut input = String::new();

    match io::stdin().read_line(&mut input) {
      Ok(_) => { return Some(input); },
      Err(error) => {
        println!("Error reading input: {}", error);
        return None;
      },
    }
  }

  fn get() -> Option<T> {
    Self::show_prompt();

    match Self::read_input() {
      Some(input) => {
        match input.chars().next() {
          Some(k) => {
            let k = k.to_ascii_lowercase();
            if k == 'h' || k == '?' {
              println!("Available commands:");

              for &(ch, desc) in Self::get_help().iter() {
                println!("{} - {}", ch, desc);
              }
              return None;
            } else if let Some(cmd) = Self::from_char(k) {
              return Some(cmd);
            }
          },
          None => {}
        }
        println!("I have no idea what you're talking about.");
        return None;
      },
      None => {
        return None;
      }
    }
  }
}

static PRIMARY_COMMAND_HELP: HelpInfo = &[
  ('n', "go north"),
  ('s', "go south"),
  ('e', "go east"),
  ('w', "go west"),
  ('l', "look around"),
  ('q', "quit"),
];

impl CommandProcessor<PrimaryCommand> for PrimaryCommand {
  fn get_help() -> HelpInfo { PRIMARY_COMMAND_HELP }

  fn from_char(c: char) -> Option<PrimaryCommand> {
    match c {
      'n' => { return Some(PrimaryCommand::Go(Direction::North)); },
      's' => { return Some(PrimaryCommand::Go(Direction::South)); },
      'e' => { return Some(PrimaryCommand::Go(Direction::East)); },
      'w' => { return Some(PrimaryCommand::Go(Direction::West)); },
      'l' => { return Some(PrimaryCommand::Look); },
      'q' => { return Some(PrimaryCommand::Quit); },
      _ => { return None; },
    }
  }
}
<commit_msg>Use str for prompt instead of [u8].<commit_after>use std::ascii::AsciiExt;

#[cfg(not(target_os = "emscripten"))]
use std::io::{self, Write};

use direction::Direction;

#[cfg(target_os = "emscripten")]
use emscripten::{emscripten};

#[derive(Debug)]
pub enum PrimaryCommand {
  Go(Direction),
  Look,
  Quit,
}

type HelpInfo = &'static [(char, &'static str)];

pub trait CommandProcessor<T> {
  fn from_char(c: char) -> Option<T>;

  fn get_help() -> HelpInfo;

  fn prompt() -> &'static str { "> " }

  #[cfg(target_os = "emscripten")]
  fn show_prompt() {}

  #[cfg(not(target_os = "emscripten"))]
  fn show_prompt() {
    io::stdout().write(Self::prompt().as_bytes()).unwrap();
    io::stdout().flush().unwrap();
  }

  #[cfg(target_os = "emscripten")]
  fn read_input() -> Option<String> {
    if emscripten::run_script_int("has_input()") == 0 {
      None
    } else {
      Some(emscripten::run_script_string("get_input()"))
    }
  }

  #[cfg(not(target_os = "emscripten"))]
  fn read_input() -> Option<String> {
    let mut input = String::new();

    match io::stdin().read_line(&mut input) {
      Ok(_) => { return Some(input); },
      Err(error) => {
        println!("Error reading input: {}", error);
        return None;
      },
    }
  }

  fn get() -> Option<T> {
    Self::show_prompt();

    match Self::read_input() {
      Some(input) => {
        match input.chars().next() {
          Some(k) => {
            let k = k.to_ascii_lowercase();
            if k == 'h' || k == '?' {
              println!("Available commands:");

              for &(ch, desc) in Self::get_help().iter() {
                println!("{} - {}", ch, desc);
              }
              return None;
            } else if let Some(cmd) = Self::from_char(k) {
              return Some(cmd);
            }
          },
          None => {}
        }
        println!("I have no idea what you're talking about.");
        return None;
      },
      None => {
        return None;
      }
    }
  }
}

static PRIMARY_COMMAND_HELP: HelpInfo = &[
  ('n', "go north"),
  ('s', "go south"),
  ('e', "go east"),
  ('w', "go west"),
  ('l', "look around"),
  ('q', "quit"),
];

impl CommandProcessor<PrimaryCommand> for PrimaryCommand {
  fn get_help() -> HelpInfo { PRIMARY_COMMAND_HELP }

  fn from_char(c: char) -> Option<PrimaryCommand> {
    match c {
      'n' => { return Some(PrimaryCommand::Go(Direction::North)); },
      's' => { return Some(PrimaryCommand::Go(Direction::South)); },
      'e' => { return Some(PrimaryCommand::Go(Direction::East)); },
      'w' => { return Some(PrimaryCommand::Go(Direction::West)); },
      'l' => { return Some(PrimaryCommand::Look); },
      'q' => { return Some(PrimaryCommand::Quit); },
      _ => { return None; },
    }
  }
}
<|endoftext|>


<commit_before>use std::ffi::OsStr;
use std::io;
use std::process::{self, Command};

use crate::errors::*;
use crate::utils::utils::ExitCode;

pub fn run_command_for_dir<S: AsRef<OsStr>>(
    mut cmd: Command,
    arg0: &str,
    args: &[S],
) -> Result<ExitCode> {
    cmd.args(args);

    // FIXME rust-lang/rust#32254. It's not clear to me
    // when and why this is needed.
    cmd.stdin(process::Stdio::inherit());

    return exec(&mut cmd).chain_err(|| crate::ErrorKind::RunningCommand {
        name: OsStr::new(arg0).to_owned(),
    });

    #[cfg(unix)]
    fn exec(cmd: &mut Command) -> io::Result<ExitCode> {
        use std::os::unix::prelude::*;
        Err(cmd.exec())
    }

    #[cfg(windows)]
    fn exec(cmd: &mut Command) -> io::Result<ExitCode> {
        let status = cmd.status()?;
        Ok(ExitCode(status.code().unwrap()))
    }
}
<commit_msg>command: Pass Ctrl+C on in Windows<commit_after>use std::ffi::OsStr;
use std::io;
use std::process::{self, Command};

use crate::errors::*;
use crate::utils::utils::ExitCode;

pub fn run_command_for_dir<S: AsRef<OsStr>>(
    mut cmd: Command,
    arg0: &str,
    args: &[S],
) -> Result<ExitCode> {
    cmd.args(args);

    // FIXME rust-lang/rust#32254. It's not clear to me
    // when and why this is needed.
    cmd.stdin(process::Stdio::inherit());

    return exec(&mut cmd).chain_err(|| crate::ErrorKind::RunningCommand {
        name: OsStr::new(arg0).to_owned(),
    });

    #[cfg(unix)]
    fn exec(cmd: &mut Command) -> io::Result<ExitCode> {
        use std::os::unix::prelude::*;
        Err(cmd.exec())
    }

    #[cfg(windows)]
    fn exec(cmd: &mut Command) -> io::Result<ExitCode> {
        use winapi::shared::minwindef::{BOOL, DWORD, FALSE, TRUE};
        use winapi::um::consoleapi::SetConsoleCtrlHandler;

        unsafe extern "system" fn ctrlc_handler(_: DWORD) -> BOOL {
            // Do nothing. Let the child process handle it.
            TRUE
        }
        unsafe {
            if SetConsoleCtrlHandler(Some(ctrlc_handler), TRUE) == FALSE {
                return Err(io::Error::new(
                    io::ErrorKind::Other,
                    "Unable to set console handler",
                ));
            }
        }
        let status = cmd.status()?;
        Ok(ExitCode(status.code().unwrap()))
    }
}
<|endoftext|>


<commit_before>extern crate semver;

use std::collections::HashMap;
use std::io::net::ip::IpAddr;
use std::hash::Hash;
use std::any::Any;

#[deriving(PartialEq, Show, Clone)]
pub enum Scheme {
    Http,
    Https
}

#[deriving(PartialEq, Show, Clone)]
pub enum Host<'a> {
    HostName(&'a str),
    HostIp(IpAddr)
}

#[deriving(PartialEq, Hash, Eq, Show, Clone)]
pub enum Method<'a> {
    Get,
    Post,
    Put,
    Delete,
    Head,
    Connect,
    Options,
    Trace,

    // RFC-5789
    Patch,
    Purge,

    // WebDAV, Subversion, UPNP
    Other(&'a str)
}

/// A Dictionary for extensions provided by the server or middleware
pub type Extensions = HashMap<&'static str, Box<Any>>;

pub trait Request {
    /// The version of HTTP being used
    fn http_version(&self) -> semver::Version;

    /// The version of the conduit spec being used
    fn conduit_version(&self) -> semver::Version;

    /// The request method, such as GET, POST, PUT, DELETE or PATCH
    fn method<'a>(&'a self) -> Method<'a>;

    /// The scheme part of the request URL
    fn scheme(&self) -> Scheme;

    /// The host part of the requested URL
    fn host<'a>(&'a self) -> Host<'a>;

    /// The initial part of the request URL's path that corresponds
    /// to a virtual root. This allows an application to have a
    /// virtual location that consumes part of the path.
    fn virtual_root<'a>(&'a self) -> Option<&'a str>;

    /// The remainder of the path.
    fn path<'a>(&'a self) -> &'a str;

    /// The portion of the request URL that follows the "?"
    fn query_string<'a>(&'a self) -> Option<&'a str>;

    /// The remote IP address of the client or the last proxy that
    /// sent the request.
    fn remote_ip(&self) -> IpAddr;

    /// The byte-size of the body, if any
    fn content_length(&self) -> Option<uint>;

    /// The request's headers, as conduit::Headers.
    fn headers<'a>(&'a self) -> &'a Headers;

    /// A Reader for the body of the request
    fn body<'a>(&'a mut self) -> &'a mut Reader;

    /// A readable map of extensions
    fn extensions<'a>(&'a self) -> &'a Extensions;

    /// A mutable map of extensions
    fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions;
}

pub type HeaderEntries<'a> = Box<Iterator<(&'a str, Vec<&'a str>)>>;

pub trait Headers {
    /// Find the value of a given header. Multi-line headers are represented
    /// as an array.
    fn find<'a>(&'a self, key: &str) -> Option<Vec<&'a str>>;

    /// Returns true if a particular header exists
    fn has(&self, key: &str) -> bool;

    /// Iterate over all of the available headers.
    fn iter<'a>(&'a self) -> HeaderEntries<'a>;
}

pub struct Response {
    /// The status code as a tuple of the return code and status string
    pub status: (uint, &'static str),

    /// A Map of the headers
    pub headers: HashMap<String, Vec<String>>,

    /// A Writer for body of the response
    pub body: Box<Reader + Send>
}

/// A Handler takes a request and returns a response or an error.
/// By default, a bare function implements `Handler`.
pub trait Handler<E> {
    fn call(&self, request: &mut Request) -> Result<Response, E>;
}

impl<E> Handler<E> for fn(&mut Request) -> Result<Response, E> {
    fn call(&self, request: &mut Request) -> Result<Response, E> {
        (*self)(request)
    }
}
<commit_msg>Method should not be borrowed<commit_after>extern crate semver;

use std::collections::HashMap;
use std::io::net::ip::IpAddr;
use std::hash::Hash;
use std::any::Any;

#[deriving(PartialEq, Show, Clone)]
pub enum Scheme {
    Http,
    Https
}

#[deriving(PartialEq, Show, Clone)]
pub enum Host<'a> {
    HostName(&'a str),
    HostIp(IpAddr)
}

#[deriving(PartialEq, Hash, Eq, Show, Clone)]
pub enum Method {
    Get,
    Post,
    Put,
    Delete,
    Head,
    Connect,
    Options,
    Trace,

    // RFC-5789
    Patch,
    Purge,

    // WebDAV, Subversion, UPNP
    Other(&'static str)
}

/// A Dictionary for extensions provided by the server or middleware
pub type Extensions = HashMap<&'static str, Box<Any>>;

pub trait Request {
    /// The version of HTTP being used
    fn http_version(&self) -> semver::Version;

    /// The version of the conduit spec being used
    fn conduit_version(&self) -> semver::Version;

    /// The request method, such as GET, POST, PUT, DELETE or PATCH
    fn method(&self) -> Method;

    /// The scheme part of the request URL
    fn scheme(&self) -> Scheme;

    /// The host part of the requested URL
    fn host<'a>(&'a self) -> Host<'a>;

    /// The initial part of the request URL's path that corresponds
    /// to a virtual root. This allows an application to have a
    /// virtual location that consumes part of the path.
    fn virtual_root<'a>(&'a self) -> Option<&'a str>;

    /// The remainder of the path.
    fn path<'a>(&'a self) -> &'a str;

    /// The portion of the request URL that follows the "?"
    fn query_string<'a>(&'a self) -> Option<&'a str>;

    /// The remote IP address of the client or the last proxy that
    /// sent the request.
    fn remote_ip(&self) -> IpAddr;

    /// The byte-size of the body, if any
    fn content_length(&self) -> Option<uint>;

    /// The request's headers, as conduit::Headers.
    fn headers<'a>(&'a self) -> &'a Headers;

    /// A Reader for the body of the request
    fn body<'a>(&'a mut self) -> &'a mut Reader;

    /// A readable map of extensions
    fn extensions<'a>(&'a self) -> &'a Extensions;

    /// A mutable map of extensions
    fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions;
}

pub type HeaderEntries<'a> = Box<Iterator<(&'a str, Vec<&'a str>)>>;

pub trait Headers {
    /// Find the value of a given header. Multi-line headers are represented
    /// as an array.
    fn find<'a>(&'a self, key: &str) -> Option<Vec<&'a str>>;

    /// Returns true if a particular header exists
    fn has(&self, key: &str) -> bool;

    /// Iterate over all of the available headers.
    fn iter<'a>(&'a self) -> HeaderEntries<'a>;
}

pub struct Response {
    /// The status code as a tuple of the return code and status string
    pub status: (uint, &'static str),

    /// A Map of the headers
    pub headers: HashMap<String, Vec<String>>,

    /// A Writer for body of the response
    pub body: Box<Reader + Send>
}

/// A Handler takes a request and returns a response or an error.
/// By default, a bare function implements `Handler`.
pub trait Handler<E> {
    fn call(&self, request: &mut Request) -> Result<Response, E>;
}

impl<E> Handler<E> for fn(&mut Request) -> Result<Response, E> {
    fn call(&self, request: &mut Request) -> Result<Response, E> {
        (*self)(request)
    }
}
<|endoftext|>


<commit_before>use byteorder::ReadBytesExt;
use net2::TcpStreamExt;
use std::io;
use std::io::prelude::*;
use std::fmt;
use std::net::TcpStream;
use std::time::Duration;
use bufstream::BufStream;
#[cfg(feature = "unix_socket")]
use unix_socket::UnixStream;
#[cfg(unix)]
use std::os::unix::io::{AsRawFd, RawFd};
#[cfg(windows)]
use std::os::windows::io::{AsRawSocket, RawSocket};

use {SslMode, ConnectParams, ConnectTarget};
use error::ConnectError;
use io::{NegotiateSsl, StreamWrapper};
use message::{self, WriteMessage};
use message::FrontendMessage::SslRequest;

const DEFAULT_PORT: u16 = 5432;

#[doc(hidden)]
pub trait ReadTimeout {
    fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()>;
}

impl ReadTimeout for BufStream<Box<StreamWrapper>> {
    fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
        match self.get_ref().get_ref().0 {
            InternalStream::Tcp(ref s) => {
                <TcpStream as TcpStreamExt>::set_read_timeout(s, timeout)
            }
            #[cfg(feature = "unix_socket")]
            InternalStream::Unix(ref s) => s.set_read_timeout(timeout),
        }
    }
}

/// A connection to the Postgres server.
///
/// It implements `Read`, `Write` and `StreamWrapper`, as well as `AsRawFd` on
/// Unix platforms and `AsRawSocket` on Windows platforms.
pub struct Stream(InternalStream);

impl fmt::Debug for Stream {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self.0 {
            InternalStream::Tcp(ref s) => fmt::Debug::fmt(s, fmt),
            #[cfg(feature = "unix_socket")]
            InternalStream::Unix(ref s) => fmt::Debug::fmt(s, fmt),
        }
    }
}

impl Read for Stream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl Write for Stream {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

impl StreamWrapper for Stream {
    fn get_ref(&self) -> &Stream {
        self
    }

    fn get_mut(&mut self) -> &mut Stream {
        self
    }
}

#[cfg(unix)]
impl AsRawFd for Stream {
    fn as_raw_fd(&self) -> RawFd {
        match self.0 {
            InternalStream::Tcp(ref s) => s.as_raw_fd(),
            #[cfg(feature = "unix_socket")]
            InternalStream::Unix(ref s) => s.as_raw_fd(),
        }
    }
}

#[cfg(windows)]
impl AsRawSocket for Stream {
    fn as_raw_socket(&self) -> RawSocket {
        // Unix sockets aren't supported on windows, so no need to match
        match self.0 {
            InternalStream::Tcp(ref s) => s.as_raw_socket(),
        }
    }
}

enum InternalStream {
    Tcp(TcpStream),
    #[cfg(feature = "unix_socket")]
    Unix(UnixStream),
}

impl Read for InternalStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match *self {
            InternalStream::Tcp(ref mut s) => s.read(buf),
            #[cfg(feature = "unix_socket")]
            InternalStream::Unix(ref mut s) => s.read(buf),
        }
    }
}

impl Write for InternalStream {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        match *self {
            InternalStream::Tcp(ref mut s) => s.write(buf),
            #[cfg(feature = "unix_socket")]
            InternalStream::Unix(ref mut s) => s.write(buf),
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        match *self {
            InternalStream::Tcp(ref mut s) => s.flush(),
            #[cfg(feature = "unix_socket")]
            InternalStream::Unix(ref mut s) => s.flush(),
        }
    }
}

fn open_socket(params: &ConnectParams) -> Result<InternalStream, ConnectError> {
    let port = params.port.unwrap_or(DEFAULT_PORT);
    match params.target {
        ConnectTarget::Tcp(ref host) => {
            Ok(try!(TcpStream::connect(&(&**host, port)).map(InternalStream::Tcp)))
        }
        #[cfg(feature = "unix_socket")]
        ConnectTarget::Unix(ref path) => {
            let path = path.join(&format!(".s.PGSQL.{}", port));
            Ok(try!(UnixStream::connect(&path).map(InternalStream::Unix)))
        }
    }
}

pub fn initialize_stream(params: &ConnectParams,
                         ssl: SslMode)
                         -> Result<Box<StreamWrapper>, ConnectError> {
    let mut socket = Stream(try!(open_socket(params)));

    let (ssl_required, negotiator) = match ssl {
        SslMode::None => return Ok(Box::new(socket)),
        SslMode::Prefer(negotiator) => (false, negotiator),
        SslMode::Require(negotiator) => (true, negotiator),
    };

    try!(socket.write_message(&SslRequest { code: message::SSL_CODE }));
    try!(socket.flush());

    if try!(socket.read_u8()) == 'N' as u8 {
        if ssl_required {
            return Err(ConnectError::NoSslSupport);
        } else {
            return Ok(Box::new(socket));
        }
    }

    // Postgres doesn't support SSL over unix sockets
    let host = match params.target {
        ConnectTarget::Tcp(ref host) => host,
        #[cfg(feature = "unix_socket")]
        ConnectTarget::Unix(_) => return Err(ConnectError::IoError(::bad_response())),
    };

    match negotiator.negotiate_ssl(host, socket) {
        Ok(stream) => Ok(stream),
        Err(err) => Err(ConnectError::Ssl(err)),
    }
}
<commit_msg>Fix features<commit_after>use byteorder::ReadBytesExt;
use net2::TcpStreamExt;
use std::io;
use std::io::prelude::*;
use std::fmt;
use std::net::TcpStream;
use std::time::Duration;
use bufstream::BufStream;
#[cfg(feature = "unix_socket")]
use unix_socket::UnixStream;
#[cfg(unix)]
use std::os::unix::io::{AsRawFd, RawFd};
#[cfg(windows)]
use std::os::windows::io::{AsRawSocket, RawSocket};

use {SslMode, ConnectParams, ConnectTarget};
use error::ConnectError;
use io::{NegotiateSsl, StreamWrapper};
use message::{self, WriteMessage};
use message::FrontendMessage::SslRequest;

const DEFAULT_PORT: u16 = 5432;

#[doc(hidden)]
pub trait ReadTimeout {
    fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()>;
}

impl ReadTimeout for BufStream<Box<StreamWrapper>> {
    fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
        match self.get_ref().get_ref().0 {
            InternalStream::Tcp(ref s) => {
                <TcpStream as TcpStreamExt>::set_read_timeout(s, timeout)
            }
            #[cfg(feature = "unix_socket")]
            InternalStream::Unix(ref s) => s.set_read_timeout(timeout),
        }
    }
}

/// A connection to the Postgres server.
///
/// It implements `Read`, `Write` and `StreamWrapper`, as well as `AsRawFd` on
/// Unix platforms and `AsRawSocket` on Windows platforms.
pub struct Stream(InternalStream);

impl fmt::Debug for Stream {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self.0 {
            InternalStream::Tcp(ref s) => fmt::Debug::fmt(s, fmt),
            #[cfg(feature = "unix_socket")]
            InternalStream::Unix(ref s) => fmt::Debug::fmt(s, fmt),
        }
    }
}

impl Read for Stream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl Write for Stream {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

impl StreamWrapper for Stream {
    fn get_ref(&self) -> &Stream {
        self
    }

    fn get_mut(&mut self) -> &mut Stream {
        self
    }
}

#[cfg(unix)]
impl AsRawFd for Stream {
    fn as_raw_fd(&self) -> RawFd {
        match self.0 {
            InternalStream::Tcp(ref s) => s.as_raw_fd(),
            #[cfg(feature = "unix_socket")]
            InternalStream::Unix(ref s) => s.as_raw_fd(),
        }
    }
}

#[cfg(windows)]
impl AsRawSocket for Stream {
    fn as_raw_socket(&self) -> RawSocket {
        // Unix sockets aren't supported on windows, so no need to match
        match self.0 {
            InternalStream::Tcp(ref s) => s.as_raw_socket(),
        }
    }
}

enum InternalStream {
    Tcp(TcpStream),
    #[cfg(feature = "unix_socket")]
    Unix(UnixStream),
}

impl Read for InternalStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match *self {
            InternalStream::Tcp(ref mut s) => s.read(buf),
            #[cfg(feature = "unix_socket")]
            InternalStream::Unix(ref mut s) => s.read(buf),
        }
    }
}

impl Write for InternalStream {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        match *self {
            InternalStream::Tcp(ref mut s) => s.write(buf),
            #[cfg(feature = "unix_socket")]
            InternalStream::Unix(ref mut s) => s.write(buf),
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        match *self {
            InternalStream::Tcp(ref mut s) => s.flush(),
            #[cfg(feature = "unix_socket")]
            InternalStream::Unix(ref mut s) => s.flush(),
        }
    }
}

fn open_socket(params: &ConnectParams) -> Result<InternalStream, ConnectError> {
    let port = params.port.unwrap_or(DEFAULT_PORT);
    match params.target {
        ConnectTarget::Tcp(ref host) => {
            Ok(try!(TcpStream::connect(&(&**host, port)).map(InternalStream::Tcp)))
        }
        #[cfg(feature = "unix_socket")]
        ConnectTarget::Unix(ref path) => {
            let path = path.join(&format!(".s.PGSQL.{}", port));
            Ok(try!(UnixStream::connect(&path).map(InternalStream::Unix)))
        }
    }
}

pub fn initialize_stream(params: &ConnectParams,
                         ssl: SslMode)
                         -> Result<Box<StreamWrapper>, ConnectError> {
    let mut socket = Stream(try!(open_socket(params)));

    let (ssl_required, negotiator) = match ssl {
        SslMode::None => return Ok(Box::new(socket)),
        SslMode::Prefer(negotiator) => (false, negotiator),
        SslMode::Require(negotiator) => (true, negotiator),
    };

    try!(socket.write_message(&SslRequest { code: message::SSL_CODE }));
    try!(socket.flush());

    if try!(socket.read_u8()) == 'N' as u8 {
        if ssl_required {
            return Err(ConnectError::NoSslSupport);
        } else {
            return Ok(Box::new(socket));
        }
    }

    // Postgres doesn't support SSL over unix sockets
    let host = match params.target {
        ConnectTarget::Tcp(ref host) => host,
        #[cfg(feature = "unix_socket")]
        ConnectTarget::Unix(_) => return Err(ConnectError::Io(::bad_response())),
    };

    match negotiator.negotiate_ssl(host, socket) {
        Ok(stream) => Ok(stream),
        Err(err) => Err(ConnectError::Ssl(err)),
    }
}
<|endoftext|>


<commit_before>use command::Command;
use vm::VM;

pub struct Program {
    instructions : Vec<Command>,
    instruction_pointer: Option<usize>,
    is_seeking: bool,
    current_depth: u64,
    goal_depth: Option<u64>,
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            is_seeking: false,
            current_depth: 0,
            goal_depth: None,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() { self.instruction_pointer = Some(0); }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match self.instruction_pointer {
            None => {},
            Some(mut index) => {
                while index < self.instructions.len() {
                    let command = self.instructions[index];
                    if command == Command::JumpForward { self.current_depth = self.current_depth + 1}
                    if command == Command::JumpBackward { self.current_depth = self.current_depth - 1}
                    vm.apply(command);
                    index = index + 1;
                }
                self.instruction_pointer = Some(index);
            }
        }
    }

    fn handle_jump_forward(&mut self, vm: &VM, mut index: usize) -> usize {
        if vm.cells[vm.data_pointer] == 0 {
            self.goal_depth = Some(self.current_depth);
            while self.current_depth != self.goal_depth.unwrap() && index < self.instructions.len() {
                match self.instructions[index] {
                    Command::JumpForward => self.current_depth = self.current_depth + 1,
                    Command::JumpBackward => self.current_depth = self.current_depth - 1,
                    _ => {},
                }
                index = index + 1;
            }
            return index;
        } else {
            self.current_depth = self.current_depth + 1;
            return index;
        }
    }
}
<commit_msg>Add seek_forward fn<commit_after>use command::Command;
use vm::VM;

pub struct Program {
    instructions : Vec<Command>,
    instruction_pointer: Option<usize>,
    is_seeking: bool,
    current_depth: u64,
    goal_depth: Option<u64>,
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            is_seeking: false,
            current_depth: 0,
            goal_depth: None,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() { self.instruction_pointer = Some(0); }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match self.instruction_pointer {
            None => {},
            Some(mut index) => {
                while index < self.instructions.len() {
                    let command = self.instructions[index];
                    if command == Command::JumpForward { self.current_depth = self.current_depth + 1}
                    if command == Command::JumpBackward { self.current_depth = self.current_depth - 1}
                    vm.apply(command);
                    index = index + 1;
                }
                self.instruction_pointer = Some(index);
            }
        }
    }

    fn seek_forward(&mut self, mut index: usize) -> usize {
        while self.current_depth != self.goal_depth.unwrap() && index < self.instructions.len() {
            match self.instructions[index] {
                Command::JumpForward => self.current_depth = self.current_depth + 1,
                Command::JumpBackward => self.current_depth = self.current_depth - 1,
                _ => {},
            }
            index = index + 1;
        }
        return index;
    }

    fn handle_jump_forward(&mut self, vm: &VM, mut index: usize) -> usize {
        if vm.cells[vm.data_pointer] == 0 {
            self.goal_depth = Some(self.current_depth);
            while self.current_depth != self.goal_depth.unwrap() && index < self.instructions.len() {
                match self.instructions[index] {
                    Command::JumpForward => self.current_depth = self.current_depth + 1,
                    Command::JumpBackward => self.current_depth = self.current_depth - 1,
                    _ => {},
                }
                index = index + 1;
            }
            return index;
        } else {
            self.current_depth = self.current_depth + 1;
            return index;
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// This tests that we can't modify Box<&mut T> contents while they
// are borrowed.

#![feature(box_syntax)]

struct A { a: isize }
struct B<'a> { a: Box<&'a mut isize> }

fn borrow_in_var_from_var() {
    let mut x: isize = 1;
    let y: Box<_> = box &mut x;
    let p = &y;
    let q = &***p;
    **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
    drop(p);
    drop(q);
}

fn borrow_in_var_from_field() {
    let mut x = A { a: 1 };
    let y: Box<_> = box &mut x.a;
    let p = &y;
    let q = &***p;
    **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
    drop(p);
    drop(q);
}

fn borrow_in_field_from_var() {
    let mut x: isize = 1;
    let y = B { a: box &mut x };
    let p = &y.a;
    let q = &***p;
    **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
    drop(p);
    drop(q);
}

fn borrow_in_field_from_field() {
    let mut x = A { a: 1 };
    let y = B { a: box &mut x.a };
    let p = &y.a;
    let q = &***p;
    **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
    drop(p);
    drop(q);
}

fn main() {
    borrow_in_var_from_var();
    borrow_in_var_from_field();
    borrow_in_field_from_var();
    borrow_in_field_from_field();
}
<commit_msg>Fallout to test.<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// This tests that we can't modify Box<&mut T> contents while they
// are borrowed (#14498).
//
// Also includes tests of the errors reported when the Box in question
// is immutable (#14270).

#![feature(box_syntax)]

struct A { a: isize }
struct B<'a> { a: Box<&'a mut isize> }

fn indirect_write_to_imm_box() {
    let mut x: isize = 1;
    let y: Box<_> = box &mut x;
    let p = &y;
    ***p = 2; //~ ERROR cannot assign to data in an immutable container
    drop(p);
}

fn borrow_in_var_from_var() {
    let mut x: isize = 1;
    let mut y: Box<_> = box &mut x;
    let p = &y;
    let q = &***p;
    **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
    drop(p);
    drop(q);
}

fn borrow_in_var_from_var_via_imm_box() {
    let mut x: isize = 1;
    let y: Box<_> = box &mut x;
    let p = &y;
    let q = &***p;
    **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
    //~^         ERROR cannot assign to data in an immutable container
    drop(p);
    drop(q);
}

fn borrow_in_var_from_field() {
    let mut x = A { a: 1 };
    let mut y: Box<_> = box &mut x.a;
    let p = &y;
    let q = &***p;
    **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
    drop(p);
    drop(q);
}

fn borrow_in_var_from_field_via_imm_box() {
    let mut x = A { a: 1 };
    let y: Box<_> = box &mut x.a;
    let p = &y;
    let q = &***p;
    **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
    //~^         ERROR cannot assign to data in an immutable container
    drop(p);
    drop(q);
}

fn borrow_in_field_from_var() {
    let mut x: isize = 1;
    let mut y = B { a: box &mut x };
    let p = &y.a;
    let q = &***p;
    **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
    drop(p);
    drop(q);
}

fn borrow_in_field_from_var_via_imm_box() {
    let mut x: isize = 1;
    let y = B { a: box &mut x };
    let p = &y.a;
    let q = &***p;
    **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
    //~^           ERROR cannot assign to data in an immutable container
    drop(p);
    drop(q);
}

fn borrow_in_field_from_field() {
    let mut x = A { a: 1 };
    let mut y = B { a: box &mut x.a };
    let p = &y.a;
    let q = &***p;
    **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
    drop(p);
    drop(q);
}

fn borrow_in_field_from_field_via_imm_box() {
    let mut x = A { a: 1 };
    let y = B { a: box &mut x.a };
    let p = &y.a;
    let q = &***p;
    **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
    //~^           ERROR cannot assign to data in an immutable container
    drop(p);
    drop(q);
}

fn main() {
    indirect_write_to_imm_box();
    borrow_in_var_from_var();
    borrow_in_var_from_var_via_imm_box();
    borrow_in_var_from_field();
    borrow_in_var_from_field_via_imm_box();
    borrow_in_field_from_var();
    borrow_in_field_from_var_via_imm_box();
    borrow_in_field_from_field();
    borrow_in_field_from_field_via_imm_box();
}
<|endoftext|>


<commit_before>pub mod builtins;
pub mod utils;
pub mod read_line;
// pub mod exec;

use std::env;
use std::path::{Path, PathBuf};
use std::io;
use std::io::Write;
use std::collections::HashMap;
use std::collections::hash_map::Entry;

#[derive(Debug, Clone)]
pub struct State {
    cwd: PathBuf,
    variables: HashMap<String, String>,
    aliases: HashMap<String, String>,
    argv: Vec<String>,
    argc: usize,
    exit_status: i32,
}

impl State {
    pub fn new(cwd: String) -> State {
        State {
            cwd: utils::make_absolute(PathBuf::from(cwd)).unwrap(),
            variables: HashMap::new(),
            aliases: HashMap::new(),
            argv: Vec::new(),
            argc: 0,
            exit_status: 0,
        }
    }

    pub fn default() -> State {
        match env::current_dir() {
            Ok(cwd) => {
                State {
                    cwd: cwd,
                    variables: HashMap::new(),
                    aliases: HashMap::new(),
                    argv: Vec::new(),
                    argc: 0,
                    exit_status: 0,
                }
            }
            Err(e) => panic!(e),
        }
    }

    pub fn exec_paths(&self) -> Vec<PathBuf> {
        let path = if let Some(s) = self.variables.get("PATH") {
            s.clone()
        } else {
            "".to_string()
        };

        path.split(";")
            .map(|x| Path::new(x).to_path_buf())
            .collect()
    }

    pub fn env<'a>(&'a mut self, key: String, value: String) -> &'a mut State {
        self.variables.insert(key, value);
        self
    }

    pub fn alias<'a>(&'a mut self, alias: String, value: String) -> &'a mut State {
        self.aliases.insert(alias, value);
        self
    }
}

pub fn run(initial_state: State) {
    let mut builtins = builtins::load();
    let mut s = initial_state.clone();
    let i = read_line::Input::from(&s);

    println!("Welcome to rsh! {:?}", s);

    loop {

        let input = i.prompt(format!("{} -> ", s.cwd.display()));

        s.argv = parse_args(&input);
        s.argc = s.argv.len();

        print!("\n");
        println!("Input: {}\nState: {:?}", input, s);

        let first_arg = s.argv.get(0).unwrap().clone();
        if let Entry::Occupied(f) = builtins.entry(String::from(first_arg)) {
            let bn = f.get();
            s.exit_status = bn(&mut s);
            // prompt for input again.
            continue;
        }
    }
}

#[derive(PartialEq)]
enum BuildType {
    None,
    Single,
    Double,
}

struct ParseResult {
    result: Vec<String>,
    completed: bool,
    build_string: String,
    build_type: BuildType,
}

fn parse_args(args: &String) -> Vec<String> {
    if args.len() == 0 {
        return Vec::new();
    }

    let mut parse_result: ParseResult = ParseResult {
        result: Vec::new(),
        completed: false,
        build_string: String::from(""),
        build_type: BuildType::None,
    };

    let mut argstr = args.clone();

    parse_string_into_vec(&argstr, &mut parse_result);

    while !parse_result.completed {
        // prompt for the rest of input
        print!(">");
        io::stdout().flush();
        argstr = String::from("");
        io::stdin().read_line(&mut argstr).unwrap();

        parse_string_into_vec(&argstr, &mut parse_result);
    }

    let result: Vec<String> = parse_result.result
        .into_iter()
        .filter(|s| s.len() > 0)
        .collect();

    result
}

fn parse_string_into_vec(string: &String, parse_result: &mut ParseResult) {
    let &mut ParseResult { ref mut build_string,
                           ref mut build_type,
                           ref mut completed,
                           ref mut result } = parse_result;
    let mut iter = string.chars().peekable();

    while let Some(c) = iter.next() {
        match c {
            '\'' => {
                match *build_type {
                    BuildType::Single => {
                        *build_type = BuildType::None;
                        if iter.peek() == Some(&' ') {
                            result.push(build_string.clone());
                            *build_string = String::from("");
                        }
                    }

                    BuildType::None => {
                        *build_type = BuildType::Single;
                    }

                    _ => {
                        build_string.push(c);
                    }
                }
            }

            '\"' => {
                match *build_type {
                    BuildType::Double => {
                        *build_type = BuildType::None;
                        if iter.peek() == Some(&' ') {
                            result.push(build_string.clone());
                            *build_string = String::from("");
                        }
                    }

                    BuildType::None => {
                        *build_type = BuildType::Double;
                    }

                    _ => {
                        build_string.push(c);
                    }
                }
            }

            ' ' => {
                match *build_type {
                    BuildType::None => {
                        result.push(build_string.clone());
                        *build_string = String::from("");
                    }

                    _ => {
                        build_string.push(c);
                    }
                }
            }

            '\n' => {
                match *build_type {
                    BuildType::None => {
                        match iter.peek() {
                            Some(_) => {
                                build_string.push(c);
                            }
                            None => {}
                        }
                    }
                    _ => {
                        build_string.push(c);
                    }
                }
            }

            _ => {
                build_string.push(c);
            }
        }
    }

    if *build_type == BuildType::None {
        *completed = true;
        if build_string.len() > 0 {
            result.push(build_string.clone());
        }
    }
}

#[test]
fn parse_args_test() {
    // parse empty string
    {
        let expected: Vec<String> = Vec::new();
        let result = parse_args(&String::from(""));
        assert_eq!(result, expected);
    }

    // parse single-word string
    {
        let expected: Vec<String> = vec!["echo".to_string()];
        let result = parse_args(&String::from("echo"));
        assert_eq!(result, expected);
    }

    // parse single-word string inside quotes
    {
        let expected = vec!["echo".to_string()];
        let result = parse_args(&String::from("\"echo\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with closed quotes section
    {
        let expected = vec!["echo".to_string(), "-n".into(), "Hello Dear World".into()];
        let result = parse_args(&String::from("echo -n \"Hello Dear World\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with multiple closed quotes sections
    {
        let expected = vec!["echo".to_string(), "Hello".into(), "Dear World".into()];
        let result = parse_args(&String::from("echo \"Hello\" \"Dear World\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with no spaces around single quotes
    {
        let expected = vec!["echo".to_string(), "helloworld".into()];
        let result = parse_args(&String::from("echo 'hello'world"));
        assert_eq!(result, expected);
    }

    // parse multi-word string with no spaces around double quotes
    {
        let expected = vec!["echo".to_string(), "helloworld".into()];
        let result = parse_args(&String::from("echo \"hello\"world"));
        assert_eq!(result, expected);
    }

    // allow double quotes inside single quotes
    {
        let expected = vec!["\"".to_string()];
        let result = parse_args(&String::from("'\"'"));
        assert_eq!(result, expected);
    }

    // allow single quotes inside double quotes
    {
        let expected = vec!["\'".to_string()];
        let result = parse_args(&String::from("\"\'\""));
        assert_eq!(result, expected);
    }

    // handle multiple quote sections in succession
    {
        let expected = vec!["echo".to_string(), "hello world how are you".into()];
        let result = parse_args(&String::from("echo \"hello world\"\' how are you\'"));
        assert_eq!(result, expected);
    }

    // preserve newlines
    {
        let expected = vec!["echo".to_string(), "hello\nworld".into()];
        let result = parse_args(&String::from("echo \"hello\nworld\""));
        assert_eq!(result, expected);
    }

    // remove final newline
    {
        let expected = vec!["echo".to_string()];
        let result = parse_args(&String::from("echo\n"));
        assert_eq!(result, expected);
    }
}
<commit_msg>manually implement debug for state<commit_after>pub mod builtins;
pub mod utils;
pub mod read_line;
// pub mod exec;

use std::env;
use std::path::{Path, PathBuf};
use std::fmt;
use std::io;
use std::io::Write;
use std::collections::HashMap;
use std::collections::hash_map::Entry;

#[derive(Clone)]
pub struct State {
    cwd: PathBuf,
    variables: HashMap<String, String>,
    aliases: HashMap<String, String>,
    argv: Vec<String>,
    argc: usize,
    exit_status: i32,
}

impl fmt::Debug for State {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "\nState {{
\tcwd: {},
\tvariables: {:?},
\taliases: {:?},
\targv: {:?}
\targc: {}
\texit_status: {}
}}
",
               self.cwd.display(),
               self.variables,
               self.aliases,
               self.argv,
               self.argc,
               self.exit_status)
    }
}

impl State {
    pub fn new(cwd: String) -> State {
        State {
            cwd: utils::make_absolute(PathBuf::from(cwd)).unwrap(),
            variables: HashMap::new(),
            aliases: HashMap::new(),
            argv: Vec::new(),
            argc: 0,
            exit_status: 0,
        }
    }

    pub fn default() -> State {
        match env::current_dir() {
            Ok(cwd) => {
                State {
                    cwd: cwd,
                    variables: HashMap::new(),
                    aliases: HashMap::new(),
                    argv: Vec::new(),
                    argc: 0,
                    exit_status: 0,
                }
            }
            Err(e) => panic!(e),
        }
    }

    pub fn exec_paths(&self) -> Vec<PathBuf> {
        let path = if let Some(s) = self.variables.get("PATH") {
            s.clone()
        } else {
            "".to_string()
        };

        path.split(";")
            .map(|x| Path::new(x).to_path_buf())
            .collect()
    }

    pub fn env<'a>(&'a mut self, key: String, value: String) -> &'a mut State {
        self.variables.insert(key, value);
        self
    }

    pub fn alias<'a>(&'a mut self, alias: String, value: String) -> &'a mut State {
        self.aliases.insert(alias, value);
        self
    }
}

pub fn run(initial_state: State) {
    let mut s = initial_state.clone();
    let mut builtins = builtins::load();
    let i = read_line::Input::from(&s);

    println!("Welcome to rsh! {:?}", s);

    loop {

        let input = i.prompt(format!("{} -> ", s.cwd.display()));

        s.argv = parse_args(&input);
        s.argc = s.argv.len();

        print!("\n");
        println!("Input: {}\nState: {:?}", input, s);

        let first_arg = s.argv.get(0).unwrap().clone();
        if let Entry::Occupied(f) = builtins.entry(String::from(first_arg)) {
            let bn = f.get();
            s.exit_status = bn(&mut s);
            // prompt for input again.
            continue;
        }
    }
}

#[derive(PartialEq)]
enum BuildType {
    None,
    Single,
    Double,
}

struct ParseResult {
    result: Vec<String>,
    completed: bool,
    build_string: String,
    build_type: BuildType,
}

fn parse_args(args: &String) -> Vec<String> {
    if args.len() == 0 {
        return Vec::new();
    }

    let mut parse_result: ParseResult = ParseResult {
        result: Vec::new(),
        completed: false,
        build_string: String::from(""),
        build_type: BuildType::None,
    };

    let mut argstr = args.clone();

    parse_string_into_vec(&argstr, &mut parse_result);

    while !parse_result.completed {
        // prompt for the rest of input
        print!(">");
        io::stdout().flush();
        argstr = String::from("");
        io::stdin().read_line(&mut argstr).unwrap();

        parse_string_into_vec(&argstr, &mut parse_result);
    }

    let result: Vec<String> = parse_result.result
        .into_iter()
        .filter(|s| s.len() > 0)
        .collect();

    result
}

fn parse_string_into_vec(string: &String, parse_result: &mut ParseResult) {
    let &mut ParseResult { ref mut build_string,
                           ref mut build_type,
                           ref mut completed,
                           ref mut result } = parse_result;
    let mut iter = string.chars().peekable();

    while let Some(c) = iter.next() {
        match c {
            '\'' => {
                match *build_type {
                    BuildType::Single => {
                        *build_type = BuildType::None;
                        if iter.peek() == Some(&' ') {
                            result.push(build_string.clone());
                            *build_string = String::from("");
                        }
                    }

                    BuildType::None => {
                        *build_type = BuildType::Single;
                    }

                    _ => {
                        build_string.push(c);
                    }
                }
            }

            '\"' => {
                match *build_type {
                    BuildType::Double => {
                        *build_type = BuildType::None;
                        if iter.peek() == Some(&' ') {
                            result.push(build_string.clone());
                            *build_string = String::from("");
                        }
                    }

                    BuildType::None => {
                        *build_type = BuildType::Double;
                    }

                    _ => {
                        build_string.push(c);
                    }
                }
            }

            ' ' => {
                match *build_type {
                    BuildType::None => {
                        result.push(build_string.clone());
                        *build_string = String::from("");
                    }

                    _ => {
                        build_string.push(c);
                    }
                }
            }

            '\n' => {
                match *build_type {
                    BuildType::None => {
                        match iter.peek() {
                            Some(_) => {
                                build_string.push(c);
                            }
                            None => {}
                        }
                    }
                    _ => {
                        build_string.push(c);
                    }
                }
            }

            _ => {
                build_string.push(c);
            }
        }
    }

    if *build_type == BuildType::None {
        *completed = true;
        if build_string.len() > 0 {
            result.push(build_string.clone());
        }
    }
}

#[test]
fn parse_args_test() {
    // parse empty string
    {
        let expected: Vec<String> = Vec::new();
        let result = parse_args(&String::from(""));
        assert_eq!(result, expected);
    }

    // parse single-word string
    {
        let expected: Vec<String> = vec!["echo".to_string()];
        let result = parse_args(&String::from("echo"));
        assert_eq!(result, expected);
    }

    // parse single-word string inside quotes
    {
        let expected = vec!["echo".to_string()];
        let result = parse_args(&String::from("\"echo\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with closed quotes section
    {
        let expected = vec!["echo".to_string(), "-n".into(), "Hello Dear World".into()];
        let result = parse_args(&String::from("echo -n \"Hello Dear World\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with multiple closed quotes sections
    {
        let expected = vec!["echo".to_string(), "Hello".into(), "Dear World".into()];
        let result = parse_args(&String::from("echo \"Hello\" \"Dear World\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with no spaces around single quotes
    {
        let expected = vec!["echo".to_string(), "helloworld".into()];
        let result = parse_args(&String::from("echo 'hello'world"));
        assert_eq!(result, expected);
    }

    // parse multi-word string with no spaces around double quotes
    {
        let expected = vec!["echo".to_string(), "helloworld".into()];
        let result = parse_args(&String::from("echo \"hello\"world"));
        assert_eq!(result, expected);
    }

    // allow double quotes inside single quotes
    {
        let expected = vec!["\"".to_string()];
        let result = parse_args(&String::from("'\"'"));
        assert_eq!(result, expected);
    }

    // allow single quotes inside double quotes
    {
        let expected = vec!["\'".to_string()];
        let result = parse_args(&String::from("\"\'\""));
        assert_eq!(result, expected);
    }

    // handle multiple quote sections in succession
    {
        let expected = vec!["echo".to_string(), "hello world how are you".into()];
        let result = parse_args(&String::from("echo \"hello world\"\' how are you\'"));
        assert_eq!(result, expected);
    }

    // preserve newlines
    {
        let expected = vec!["echo".to_string(), "hello\nworld".into()];
        let result = parse_args(&String::from("echo \"hello\nworld\""));
        assert_eq!(result, expected);
    }

    // remove final newline
    {
        let expected = vec!["echo".to_string()];
        let result = parse_args(&String::from("echo\n"));
        assert_eq!(result, expected);
    }
}
<|endoftext|>


<commit_before>extern crate syntax;

pub use syntax::ast;
pub use syntax::ptr::P;
pub use syntax::codemap::DUMMY_SP;
pub use syntax::ext::base::ExtCtxt;
pub use syntax::ast::{Mod, Item, Expr, ViewItem};
pub use syntax::parse::token::str_to_ident;
pub use syntax::ext::build::AstBuilder;
pub use syntax::print::pprust::{expr_to_string, item_to_string, view_item_to_string};

pub fn module(view_items: Vec<ViewItem>, items: Vec<P<Item>>) -> P<Mod> {
	P(Mod{
		inner: DUMMY_SP,
		view_items: view_items,
		items: items,
	})
}

pub fn parse_path(e: &str) -> ast::Path {
	let ps = syntax::parse::new_parse_sess();
	let mut p = syntax::parse::new_parser_from_source_str(&ps, Vec::new(), "file".to_string(), e.to_string());
	let r = p.parse_path(syntax::parse::parser::NoTypesAllowed);
	p.abort_if_errors();
	r.path
}

pub fn parse_path_vec(s: &str) -> Vec<ast::Ident> {
	s.split_str("::").map(|i| str_to_ident(i)).collect()
}

pub fn parse_block(e: &str) -> P<ast::Block> {
	let ps = syntax::parse::new_parse_sess();
	let mut p = syntax::parse::new_parser_from_source_str(&ps, Vec::new(), "file".to_string(), e.to_string());
	let r = p.parse_block();
	p.abort_if_errors();
	r
}

pub fn parse_type(e: &str) -> P<ast::Ty> {
	let ps = syntax::parse::new_parse_sess();
	let mut p = syntax::parse::new_parser_from_source_str(&ps, Vec::new(), "file".to_string(), e.to_string());
	let r = p.parse_ty(false);
	p.abort_if_errors();
	r
}
<commit_msg>Fix compilation against updated rustc APIs<commit_after>extern crate syntax;

pub use syntax::ast;
pub use syntax::ptr::P;
pub use syntax::codemap::DUMMY_SP;
pub use syntax::ext::base::ExtCtxt;
pub use syntax::ast::{Mod, Item, Expr, ViewItem};
pub use syntax::parse::token::str_to_ident;
pub use syntax::ext::build::AstBuilder;
pub use syntax::print::pprust::{expr_to_string, item_to_string, view_item_to_string};

pub fn module(view_items: Vec<ViewItem>, items: Vec<P<Item>>) -> P<Mod> {
	P(Mod{
		inner: DUMMY_SP,
		view_items: view_items,
		items: items,
	})
}

pub fn parse_path(e: &str) -> ast::Path {
	let ps = syntax::parse::new_parse_sess();
	let mut p = syntax::parse::new_parser_from_source_str(&ps, Vec::new(), "file".to_string(), e.to_string());
	let r = p.parse_path(syntax::parse::parser::NoTypesAllowed);
	p.abort_if_errors();
	r
}

pub fn parse_path_vec(s: &str) -> Vec<ast::Ident> {
	s.split_str("::").map(|i| str_to_ident(i)).collect()
}

pub fn parse_block(e: &str) -> P<ast::Block> {
	let ps = syntax::parse::new_parse_sess();
	let mut p = syntax::parse::new_parser_from_source_str(&ps, Vec::new(), "file".to_string(), e.to_string());
	let r = p.parse_block();
	p.abort_if_errors();
	r
}

pub fn parse_type(e: &str) -> P<ast::Ty> {
	let ps = syntax::parse::new_parse_sess();
	let mut p = syntax::parse::new_parser_from_source_str(&ps, Vec::new(), "file".to_string(), e.to_string());
	let r = p.parse_ty();
	p.abort_if_errors();
	r
}
<|endoftext|>