From 66edb724bd3a3df2235e89be27405bfecf6faf21 Mon Sep 17 00:00:00 2001 From: fdai7451 Date: Thu, 19 Jan 2023 13:49:27 +0100 Subject: [PATCH] feat: use shlex to parse line --- Cargo.lock | 7 +++++++ Cargo.toml | 1 + src/builtins/cd.rs | 4 ++-- src/builtins/exit.rs | 2 +- src/builtins/mod.rs | 2 +- src/error.rs | 1 + src/execute.rs | 4 ++-- src/main.rs | 3 +++ src/parse.rs | 40 +++++++--------------------------------- 9 files changed, 25 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 96877eb..cd9af18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -174,6 +174,7 @@ name = "pmuw-project" version = "0.1.0" dependencies = [ "rustyline", + "shlex", ] [[package]] @@ -267,6 +268,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "shlex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" + [[package]] name = "smallvec" version = "1.10.0" diff --git a/Cargo.toml b/Cargo.toml index 33030f2..c097580 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,3 +5,4 @@ edition = "2021" [dependencies] rustyline = "10.1.0" +shlex = "1.1" diff --git a/src/builtins/cd.rs b/src/builtins/cd.rs index 63777d5..14230fa 100644 --- a/src/builtins/cd.rs +++ b/src/builtins/cd.rs @@ -2,7 +2,7 @@ use std::env::set_current_dir; use crate::error::ShellError; -pub fn run(args: &[&str]) -> Result<(), ShellError> { - set_current_dir(args[0]); +pub fn run(args: Vec) -> Result<(), ShellError> { + set_current_dir(args.get(0).unwrap()); Ok(()) } diff --git a/src/builtins/exit.rs b/src/builtins/exit.rs index dd56735..8bf4196 100644 --- a/src/builtins/exit.rs +++ b/src/builtins/exit.rs @@ -2,4 +2,4 @@ use crate::error::ShellError; pub fn run() -> Result<(), ShellError> { Err(ShellError::Exit) -} \ No newline at end of file +} diff --git a/src/builtins/mod.rs b/src/builtins/mod.rs index 9d78357..c02da93 100644 --- a/src/builtins/mod.rs +++ b/src/builtins/mod.rs @@ -8,7 +8,7 @@ pub fn is_builtin(keyword: &str) -> bool { BUILTINS.contains(&keyword) } -pub fn execute_builtin(keyword: &str, args: &[&str]) -> Result<(), ShellError> { +pub fn execute_builtin(keyword: &str, args: Vec) -> Result<(), ShellError> { match keyword { "exit" => exit::run()?, "cd" => cd::run(args)?, diff --git a/src/error.rs b/src/error.rs index 76a2717..2f11ccf 100644 --- a/src/error.rs +++ b/src/error.rs @@ -5,4 +5,5 @@ pub enum ShellError { Exit, NotFound(Command), ExecuteFailure(String), + MalformedArgs(String), } diff --git a/src/execute.rs b/src/execute.rs index 8cc28bf..d48f58d 100644 --- a/src/execute.rs +++ b/src/execute.rs @@ -9,10 +9,10 @@ pub fn interpret(line: &str) -> Result<(), ShellError> { if line.is_empty() { return Err(ShellError::EmptyLine); } - let (keyword, args) = parse_line(line); + let (keyword, args) = parse_line(line)?; if is_builtin(keyword) { - execute_builtin(keyword, &args)?; + execute_builtin(keyword, args)?; } else { let mut command = Command::new(keyword); command.args(args); diff --git a/src/main.rs b/src/main.rs index f3fa492..7d66488 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,6 +34,9 @@ fn main() -> Result<()> { Err(ShellError::ExecuteFailure(msg)) => { eprintln!("{}", msg) } + Err(ShellError::MalformedArgs(args)) => { + eprintln!("Malformed arguments: {}", args) + } }, Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => { break; diff --git a/src/parse.rs b/src/parse.rs index c194120..5e2ebff 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -1,37 +1,11 @@ -pub fn parse_line(line: &str) -> (&str, Vec<&str>) { - let tokens = tokenize(line); +use crate::error::ShellError; - let keyword = tokens[0]; - let mut args: Vec<&str> = Vec::new(); +pub fn parse_line(line: &str) -> Result<(&str, Vec), ShellError> { + let (keyword, unparsed_args) = line.split_once(' ').unwrap_or((line, "")); - if tokens.len() > 1 { - args = tokens[1..].to_vec(); - } - - (keyword, args) -} - -fn tokenize(line: &str) -> Vec<&str> { - line.trim().split(' ').collect::>() -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_tokenize() { - assert_eq!( - tokenize("keyword arg1 arg2 arg3"), - vec!["keyword", "arg1", "arg2", "arg3"] - ); - } - - #[test] - fn test_parse_line() { - assert_eq!( - parse_line("keyword arg1 arg2 arg3"), - ("keyword", vec!["arg1", "arg2", "arg3"]) - ); + if let Some(args) = shlex::split(unparsed_args) { + Ok((keyword, args)) + } else { + Err(ShellError::MalformedArgs(unparsed_args.to_string())) } }