Compare commits

..

No commits in common. "8c517ae8c739a0357d51762d42cca4ecbe5784a6" and "006dc284669c4119fd6e44dbb30eb2c3c8ade4bf" have entirely different histories.

7 changed files with 185 additions and 181 deletions

View file

@ -1,112 +0,0 @@
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<String>, &mut Variables, &mut ExitCode);
fn cd(args: &Vec<String>, variables: &mut Variables, exit_code: &mut ExitCode) {
let path: Option<PathBuf>;
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<String>, _variables: &mut Variables, exit_code: &mut ExitCode) {
exit_code.set_success();
}
fn exit(args: &Vec<String>, _variables: &mut Variables, exit_code: &mut ExitCode) {
if !args.is_empty() {
let raw_exit_code = match args[0].parse::<usize>() {
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<String>, 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<String>, 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<String>,
}
impl Builtin {
pub fn new(argv: &Vec<String>) -> Result<Self, ()> {
let mut args = argv.clone();
let program = args.remove(0);
let function: Option<BuiltinFunction> = 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)
}
}

81
src/command/builtins.rs Normal file
View file

@ -0,0 +1,81 @@
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<String>, _variables: &mut Variables, exit_code: &mut ExitCode) {
let path: Option<PathBuf>;
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<String>, _variables: &mut Variables, exit_code: &mut ExitCode) {
exit_code.set_success();
}
pub(crate) fn exit(args: &Vec<String>, _variables: &mut Variables, exit_code: &mut ExitCode) {
let raw_exit_code: Result<i32, IllegalNumberError>;
if args.is_empty() {
raw_exit_code = Ok(i32::from(exit_code.get()));
} else {
raw_exit_code = match args[0].parse::<usize>() {
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<String>, variables: &mut Variables, exit_code: &mut ExitCode) {
if !args.is_empty() {
for variable_name in args.iter() {
variables.unset(variable_name);
}
}
exit_code.set_success();
}
pub(super) fn export(args: &Vec<String>, 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();
}

View file

@ -0,0 +1,26 @@
use super::Builtin;
use super::Command;
use super::UnixProgram;
pub struct CommandBuilder {
argv: Vec<String>,
}
impl CommandBuilder {
pub fn new(argv: Vec<String>) -> Self {
Self { argv }
}
pub fn build(&self) -> Box<dyn Command> {
let builtin = Builtin::new(&self.argv);
let command: Box<dyn Command>;
if builtin.is_err() {
command = Box::from(UnixProgram::new(&self.argv));
} else {
command = Box::from(builtin.unwrap());
}
command
}
}

View file

@ -1,35 +1,92 @@
pub mod builtin; pub mod builtins;
pub mod command_builder;
pub mod command_sequence; pub mod command_sequence;
pub mod unix_program;
use crate::error;
use crate::error::CommandNotFoundError;
use crate::exit_code::ExitCode; use crate::exit_code::ExitCode;
use crate::variables::Variables; use crate::variables::Variables;
use builtin::Builtin;
use unix_program::UnixProgram; type BuiltinFunction = fn(&Vec<String>, &mut Variables, &mut ExitCode);
#[derive(Debug)]
pub struct NoSuchBuiltinError;
pub trait Command { pub trait Command {
fn spawn(&mut self, variables: &mut Variables, exit_code: &mut ExitCode); fn spawn(&mut self, variables: &mut Variables, exit_code: &mut ExitCode);
} }
pub struct CommandBuilder { pub struct Builtin {
argv: Vec<String>, function: BuiltinFunction,
args: Vec<String>,
} }
impl CommandBuilder { impl Builtin {
pub fn new(argv: Vec<String>) -> Self { pub fn new(argv: &Vec<String>) -> Result<Self, NoSuchBuiltinError> {
Self { argv } let mut args = argv.clone();
} let program = args.remove(0);
pub fn build(&self) -> Box<dyn Command> { let function: Option<BuiltinFunction> = match program.as_str() {
let builtin = Builtin::new(&self.argv); "cd" => Some(builtins::cd),
let command: Box<dyn Command>; "exit" => Some(builtins::exit),
"unset" => Some(builtins::unset),
"export" => Some(builtins::export),
":" => Some(builtins::colon),
_ => None,
};
if builtin.is_err() { if function.is_some() {
command = Box::from(UnixProgram::new(&self.argv)); Ok(Self {
function: function.unwrap(),
args,
})
} else { } else {
command = Box::from(builtin.unwrap()); Err(NoSuchBuiltinError)
}
}
} }
command impl Command for Builtin {
fn spawn(&mut self, variables: &mut Variables, exit_code: &mut ExitCode) {
(self.function)(&self.args, variables, exit_code)
}
}
pub struct UnixProgram {
command: std::process::Command,
}
impl UnixProgram {
pub fn new(argv: &Vec<String>) -> 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();
}
} }
} }

View file

@ -1,44 +0,0 @@
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<String>) -> 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();
}
}
}

View file

@ -1,14 +1,10 @@
use crate::command::builtins;
use crate::command::Command; use crate::command::Command;
use crate::exit_code::ExitCode; use crate::exit_code::ExitCode;
use crate::interface::get_user_input; use crate::interface::get_user_input;
use crate::parser::parse; use crate::parser::parse;
use crate::variables::Variables; use crate::variables::Variables;
pub fn exit(exit_code: &mut ExitCode) {
println!("exit");
std::process::exit(i32::from(exit_code.get()));
}
pub fn run() { pub fn run() {
let mut current_exit_code = ExitCode::new(); let mut current_exit_code = ExitCode::new();
let mut variables = Variables::new(); let mut variables = Variables::new();
@ -24,7 +20,7 @@ pub fn run() {
} }
} else { } else {
println!(); println!();
exit(&mut current_exit_code); builtins::exit(&vec![], &mut variables, &mut current_exit_code);
} }
} }
} }

View file

@ -1,5 +1,5 @@
use crate::command::command_builder::CommandBuilder;
use crate::command::command_sequence::CommandSequence; use crate::command::command_sequence::CommandSequence;
use crate::command::CommandBuilder;
use crate::interface::get_user_input; use crate::interface::get_user_input;
use crate::variables::Variables; use crate::variables::Variables;
use std::collections::VecDeque; use std::collections::VecDeque;