diff --git a/src/command/builtin.rs b/src/command/builtin.rs new file mode 100644 index 0000000..63a96b1 --- /dev/null +++ b/src/command/builtin.rs @@ -0,0 +1,112 @@ +use super::Command; +use crate::error; +use crate::error::CdError; +use crate::error::IllegalNumberError; +use crate::exit_code::ExitCode; +use crate::variables::Variables; + +use std::{env::set_current_dir, path::PathBuf}; + +type BuiltinFunction = fn(&Vec, &mut Variables, &mut ExitCode); + +fn cd(args: &Vec, variables: &mut Variables, exit_code: &mut ExitCode) { + let path: Option; + + if !args.is_empty() { + path = Some(PathBuf::from(&args[0])); + } else { + path = match variables.get("HOME").as_str() { + "" => None, + path => Some(PathBuf::from(path)), + }; + } + + exit_code.set_success(); + if path.is_some() { + let path = path.unwrap(); + let result = set_current_dir(&path); + + if result.is_err() { + let error = CdError::new(&args[0]); + error::print(Box::new(error)); + exit_code.set(2); + } + } +} + +fn colon(_args: &Vec, _variables: &mut Variables, exit_code: &mut ExitCode) { + exit_code.set_success(); +} + +fn exit(args: &Vec, _variables: &mut Variables, exit_code: &mut ExitCode) { + if !args.is_empty() { + let raw_exit_code = match args[0].parse::() { + Ok(parsed) => Ok(u8::try_from(parsed % 256).unwrap()), + Err(_e) => Err(IllegalNumberError::new("exit", args[0].as_str())), + }; + + if raw_exit_code.is_ok() { + exit_code.set(raw_exit_code.unwrap()); + } else { + error::print(Box::new(raw_exit_code.unwrap_err())); + exit_code.set(2); + () + } + } + + crate::control::exit(exit_code); +} + +fn unset(args: &Vec, variables: &mut Variables, exit_code: &mut ExitCode) { + for variable_name in args.iter() { + variables.unset(variable_name); + } + + exit_code.set_success(); +} + +fn export(args: &Vec, variables: &mut Variables, exit_code: &mut ExitCode) { + for variable in args.iter() { + let assignation: Vec<&str> = variable.split('=').collect(); + + if assignation.len() == 2 { + variables.set(&assignation[0], &assignation[1]); + } + + variables.export(&assignation[0]); + } + + exit_code.set_success(); +} + +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); + + let function: Option = match program.as_str() { + "cd" => Some(cd), + "exit" => Some(exit), + "unset" => Some(unset), + "export" => Some(export), + ":" => Some(colon), + _ => None, + }; + + match function { + Some(function) => Ok(Self { function, args }), + None => Err(()), + } + } +} + +impl Command for Builtin { + fn spawn(&mut self, variables: &mut Variables, exit_code: &mut ExitCode) { + (self.function)(&self.args, variables, exit_code) + } +} diff --git a/src/command/builtins.rs b/src/command/builtins.rs deleted file mode 100644 index 6de1cde..0000000 --- a/src/command/builtins.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::error; -use crate::error::CdError; -use crate::error::IllegalNumberError; -use crate::exit_code::ExitCode; -use crate::variables::Variables; - -use std::env; -use std::{env::set_current_dir, path::PathBuf}; - -pub(super) fn cd(args: &Vec, _variables: &mut Variables, exit_code: &mut ExitCode) { - let path: Option; - - if !args.is_empty() { - path = Some(PathBuf::from(&args[0])); - } else { - path = match env::var("HOME") { - Ok(var) => Some(PathBuf::from(var)), - Err(_e) => None, - }; - } - - exit_code.set_success(); - if path.is_some() { - let path = path.unwrap(); - let result = set_current_dir(&path); - - if result.is_err() { - let error = CdError::new(&args[0]); - error::print(Box::new(error)); - exit_code.set(2); - } - } -} - -pub(super) fn colon(_args: &Vec, _variables: &mut Variables, exit_code: &mut ExitCode) { - exit_code.set_success(); -} - -pub(crate) fn exit(args: &Vec, _variables: &mut Variables, exit_code: &mut ExitCode) { - let raw_exit_code: Result; - - if args.is_empty() { - raw_exit_code = Ok(i32::from(exit_code.get())); - } else { - raw_exit_code = match args[0].parse::() { - Ok(parsed) => Ok(i32::try_from(parsed % 256).unwrap()), - Err(_e) => Err(IllegalNumberError::new("exit", args[0].as_str())), - }; - } - - if raw_exit_code.is_ok() { - println!("exit"); - std::process::exit(raw_exit_code.unwrap()); - } else { - error::print(Box::new(raw_exit_code.unwrap_err())); - } -} - -pub(super) fn unset(args: &Vec, variables: &mut Variables, exit_code: &mut ExitCode) { - for variable_name in args.iter() { - variables.unset(variable_name); - } - - exit_code.set_success(); -} - -pub(super) fn export(args: &Vec, variables: &mut Variables, exit_code: &mut ExitCode) { - for variable in args.iter() { - let assignation: Vec<&str> = variable.split('=').collect(); - - if assignation.len() == 2 { - variables.set(&assignation[0], &assignation[1]); - } - - variables.export(&assignation[0]); - } - - exit_code.set_success(); -} diff --git a/src/command/command_builder.rs b/src/command/command_builder.rs deleted file mode 100644 index 9c523a7..0000000 --- a/src/command/command_builder.rs +++ /dev/null @@ -1,26 +0,0 @@ -use super::Builtin; -use super::Command; -use super::UnixProgram; - -pub struct CommandBuilder { - argv: Vec, -} - -impl CommandBuilder { - pub fn new(argv: Vec) -> Self { - Self { argv } - } - - pub fn build(&self) -> Box { - let builtin = Builtin::new(&self.argv); - let command: Box; - - if builtin.is_err() { - command = Box::from(UnixProgram::new(&self.argv)); - } else { - command = Box::from(builtin.unwrap()); - } - - command - } -} diff --git a/src/command/mod.rs b/src/command/mod.rs index 3a955a6..b35d681 100644 --- a/src/command/mod.rs +++ b/src/command/mod.rs @@ -1,85 +1,35 @@ -pub mod builtins; -pub mod command_builder; +pub mod builtin; pub mod command_sequence; +pub mod unix_program; -use crate::error; -use crate::error::CommandNotFoundError; use crate::exit_code::ExitCode; use crate::variables::Variables; - -type BuiltinFunction = fn(&Vec, &mut Variables, &mut ExitCode); +use builtin::Builtin; +use unix_program::UnixProgram; pub trait Command { fn spawn(&mut self, variables: &mut Variables, exit_code: &mut ExitCode); } -pub struct Builtin { - function: BuiltinFunction, - args: Vec, +pub struct CommandBuilder { + argv: Vec, } -impl Builtin { - pub fn new(argv: &Vec) -> Result { - let mut args = argv.clone(); - let program = args.remove(0); - - let function: Option = match program.as_str() { - "cd" => Some(builtins::cd), - "exit" => Some(builtins::exit), - "unset" => Some(builtins::unset), - "export" => Some(builtins::export), - ":" => Some(builtins::colon), - _ => None, - }; - - match function { - Some(function) => Ok(Self { function, args }), - None => Err(()), - } +impl CommandBuilder { + pub fn new(argv: Vec) -> Self { + Self { argv } } -} -impl Command for Builtin { - fn spawn(&mut self, variables: &mut Variables, exit_code: &mut ExitCode) { - (self.function)(&self.args, variables, exit_code) - } -} + pub fn build(&self) -> Box { + let builtin = Builtin::new(&self.argv); + let command: Box; -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, _variables: &mut Variables, exit_code: &mut ExitCode) { - let handle = self.command.spawn(); - - if handle.is_ok() { - let raw_exit_code = handle - .unwrap() - .wait() - .expect("error waiting for the child") - .code() - .unwrap_or(1); - - exit_code.set(match u8::try_from(raw_exit_code) { - Ok(code) => code, - Err(_e) => u8::MAX, - }); + if builtin.is_err() { + command = Box::from(UnixProgram::new(&self.argv)); } else { - let error = CommandNotFoundError::new(self.command.get_program().to_str().unwrap()); - error::print(Box::new(error)); - exit_code.set_command_not_found(); + command = Box::from(builtin.unwrap()); } + + command } } diff --git a/src/command/unix_program.rs b/src/command/unix_program.rs new file mode 100644 index 0000000..0122a86 --- /dev/null +++ b/src/command/unix_program.rs @@ -0,0 +1,44 @@ +use super::Command; +use crate::error; +use crate::error::CommandNotFoundError; +use crate::exit_code::ExitCode; +use crate::variables::Variables; + +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, _variables: &mut Variables, exit_code: &mut ExitCode) { + let handle = self.command.spawn(); + + if handle.is_ok() { + let raw_exit_code = handle + .unwrap() + .wait() + .expect("error waiting for the child") + .code() + .unwrap_or(1); + + exit_code.set(match u8::try_from(raw_exit_code) { + Ok(code) => code, + Err(_e) => u8::MAX, + }); + } else { + let error = CommandNotFoundError::new(self.command.get_program().to_str().unwrap()); + error::print(Box::new(error)); + exit_code.set_command_not_found(); + } + } +} diff --git a/src/control.rs b/src/control.rs index 42a2be3..4886006 100644 --- a/src/control.rs +++ b/src/control.rs @@ -1,10 +1,14 @@ -use crate::command::builtins; use crate::command::Command; use crate::exit_code::ExitCode; use crate::interface::get_user_input; use crate::parser::parse; use crate::variables::Variables; +pub fn exit(exit_code: &mut ExitCode) { + println!("exit"); + std::process::exit(i32::from(exit_code.get())); +} + pub fn run() { let mut current_exit_code = ExitCode::new(); let mut variables = Variables::new(); @@ -20,7 +24,7 @@ pub fn run() { } } else { println!(); - builtins::exit(&vec![], &mut variables, &mut current_exit_code); + exit(&mut current_exit_code); } } } diff --git a/src/parser.rs b/src/parser.rs index 171525c..21b957c 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,5 +1,5 @@ -use crate::command::command_builder::CommandBuilder; use crate::command::command_sequence::CommandSequence; +use crate::command::CommandBuilder; use crate::interface::get_user_input; use crate::variables::Variables; use std::collections::VecDeque;