diff --git a/src/command/builtin.rs b/src/command/builtins.rs similarity index 52% rename from src/command/builtin.rs rename to src/command/builtins.rs index d0d3db3..8201c9e 100644 --- a/src/command/builtin.rs +++ b/src/command/builtins.rs @@ -1,15 +1,9 @@ -use super::Command; use crate::{error::print_error, exit_code::ExitCode}; use std::env; use std::{env::set_current_dir, path::PathBuf}; -type BuiltinFunction = fn(&Vec) -> ExitCode; - -#[derive(Debug)] -pub struct NoSuchBuiltinError; - -fn cd(args: &Vec) -> ExitCode { +pub fn cd(args: &Vec) -> ExitCode { let path: Option; if !args.is_empty() { @@ -37,27 +31,3 @@ fn cd(args: &Vec) -> ExitCode { exit_code } - -pub struct Builtin { - function: BuiltinFunction, - args: Vec, -} - -impl Builtin { - pub fn new(argv: &Vec) -> Result { - let mut args = argv.clone(); - let program = args.remove(0); - - if program == "cd" { - Ok(Self { function: cd, args }) - } else { - Err(NoSuchBuiltinError) - } - } -} - -impl Command for Builtin { - fn spawn(&mut self) -> ExitCode { - (self.function)(&self.args) - } -} diff --git a/src/command/command_builder.rs b/src/command/command_builder.rs index 69a476c..9c523a7 100644 --- a/src/command/command_builder.rs +++ b/src/command/command_builder.rs @@ -1,6 +1,6 @@ -use super::builtin::Builtin; -use super::unix_program::UnixProgram; +use super::Builtin; use super::Command; +use super::UnixProgram; pub struct CommandBuilder { argv: Vec, diff --git a/src/command/command_sequence.rs b/src/command/command_sequence.rs index ee7a09e..4918d76 100644 --- a/src/command/command_sequence.rs +++ b/src/command/command_sequence.rs @@ -2,22 +2,27 @@ use crate::command::Command; use crate::exit_code::ExitCode; pub struct CommandSequence { - command: Box, + command: Option>, next_command: Option>, } impl CommandSequence { - pub fn new(command: Box) -> Self { + pub fn new() -> Self { Self { - command, + command: None, next_command: None, } } - #[allow(dead_code)] pub fn add(&mut self, command: Box) { - if self.next_command.is_none() { - self.next_command = Some(Box::new(Self::new(command))); + if self.command.is_none() { + self.command = Some(command); + } else if self.next_command.is_none() { + let new_command = Self { + command: Some(command), + next_command: None, + }; + self.next_command = Some(Box::new(new_command)); } else { self.next_command.as_mut().unwrap().add(command); } @@ -26,10 +31,14 @@ impl CommandSequence { impl Command for CommandSequence { fn spawn(&mut self) -> ExitCode { - let mut exit_code = self.command.spawn(); + let mut exit_code = ExitCode::success(); - if self.next_command.is_some() { - exit_code = self.next_command.as_mut().unwrap().spawn(); + if self.command.is_some() { + exit_code = self.command.as_mut().unwrap().spawn(); + + if self.next_command.is_some() { + exit_code = self.next_command.as_mut().unwrap().spawn(); + } } exit_code diff --git a/src/command/mod.rs b/src/command/mod.rs index da38895..07fa206 100644 --- a/src/command/mod.rs +++ b/src/command/mod.rs @@ -1,10 +1,94 @@ -pub mod builtin; +mod builtins; pub mod command_builder; pub mod command_sequence; -pub mod unix_program; +use crate::error::print_error; use crate::exit_code::ExitCode; +type BuiltinFunction = fn(&Vec) -> ExitCode; + +#[derive(Debug)] +pub struct NoSuchBuiltinError; + pub trait Command { fn spawn(&mut self) -> ExitCode; } + +pub struct Builtin { + function: BuiltinFunction, + args: Vec, +} + +impl Builtin { + pub fn new(argv: &Vec) -> Result { + let mut args = argv.clone(); + let program = args.remove(0); + + if program == "cd" { + Ok(Self { + function: builtins::cd, + args, + }) + } else { + Err(NoSuchBuiltinError) + } + } +} + +impl Command for Builtin { + fn spawn(&mut self) -> ExitCode { + (self.function)(&self.args) + } +} + +pub struct UnixProgram { + command: std::process::Command, +} + +impl UnixProgram { + pub fn new(argv: &Vec) -> Self { + let mut argv = argv.clone(); + let program = argv.remove(0); + let mut command = std::process::Command::new(&program); + command.args(argv); + + Self { command } + } +} + +impl Command for UnixProgram { + fn spawn(&mut self) -> ExitCode { + let handle = self.command.spawn(); + + if handle.is_ok() { + let exit_code = handle + .unwrap() + .wait() + .expect("error waiting for the child") + .code() + .unwrap_or(1); + + let exit_code = match u8::try_from(exit_code) { + Ok(code) => ExitCode::new(code), + Err(_e) => ExitCode::new(u8::MAX), + }; + + exit_code + } else { + let message = format!( + "{}: command not found", + self.command.get_program().to_str().unwrap() + ); + print_error(message.as_str()); + ExitCode::not_found() + } + } +} + +struct Nothing; + +impl Command for Nothing { + fn spawn(&mut self) -> ExitCode { + ExitCode::success() + } +} diff --git a/src/command/unix_program.rs b/src/command/unix_program.rs deleted file mode 100644 index a7df9c5..0000000 --- a/src/command/unix_program.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::command::Command; -use crate::error::print_error; -use crate::exit_code::ExitCode; - -pub struct UnixProgram { - command: std::process::Command, -} - -impl UnixProgram { - pub fn new(argv: &Vec) -> Self { - let mut argv = argv.clone(); - let program = argv.remove(0); - let mut command = std::process::Command::new(&program); - command.args(argv); - - Self { command } - } -} - -impl Command for UnixProgram { - fn spawn(&mut self) -> ExitCode { - let handle = self.command.spawn(); - - if handle.is_ok() { - let exit_code = handle - .unwrap() - .wait() - .expect("error waiting for the child") - .code() - .unwrap_or(1); - - let exit_code = match u8::try_from(exit_code) { - Ok(code) => ExitCode::new(code), - Err(_e) => ExitCode::new(u8::MAX), - }; - - exit_code - } else { - let message = format!( - "{}: command not found", - self.command.get_program().to_str().unwrap() - ); - print_error(message.as_str()); - ExitCode::not_found() - } - } -} diff --git a/src/control.rs b/src/control.rs index 86c0a2e..5695a78 100644 --- a/src/control.rs +++ b/src/control.rs @@ -1,7 +1,7 @@ use crate::command::Command; use crate::exit_code::ExitCode; use crate::interface::{get_user_input, print_prompt}; -use crate::parser::parse_command_line; +use crate::parser::parse; fn exit(code: &ExitCode) { let code = i32::from(code.get()); @@ -17,7 +17,7 @@ pub fn run() { let user_input = get_user_input(); if user_input.is_some() { - let command_sequence = parse_command_line(user_input.unwrap()); + let command_sequence = parse(user_input.unwrap()); if command_sequence.is_some() { current_exit_code = command_sequence.unwrap().spawn(); diff --git a/src/parser.rs b/src/parser.rs index 057499e..cb9207e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -17,7 +17,7 @@ fn parse_quote(characters: &mut Vec) -> Result, current_arg: &mut String) -> Vec { +fn parse_main(characters: &mut Vec, current_arg: &mut String) -> Vec { if characters.is_empty() { vec![] } else { @@ -26,34 +26,40 @@ fn build_argv(characters: &mut Vec, current_arg: &mut String) -> Vec = vec![current_arg.clone()]; - argv.append(&mut build_argv(characters, &mut String::from(""))); + argv.append(&mut parse_main(characters, &mut String::from(""))); argv } else { - build_argv(characters, current_arg) + parse_main(characters, current_arg) } } else if current_char == '\'' { let mut argv = vec![parse_quote(characters).unwrap()]; - argv.append(&mut build_argv(characters, &mut String::default())); + argv.append(&mut parse_main(characters, &mut String::default())); argv } else { current_arg.push(current_char); - build_argv(characters, current_arg) + parse_main(characters, current_arg) } } } -pub fn parse_command_line(line: String) -> Option { +pub fn parse(line: String) -> Option { let mut characters: Vec = line.chars().rev().collect(); - let argv = build_argv(&mut characters, &mut String::default()); + + None + /* + let argv = parse_main(&mut characters, &mut String::default()); if !argv.is_empty() { let command = CommandBuilder::new(argv).build(); - Some(CommandSequence::new(command)) + let mut command_sequence = CommandSequence::new(); + command_sequence.add(command); + Some(command_sequence) } else { None } + */ } #[derive(Debug)]