Compare commits

...

7 commits

8 changed files with 112 additions and 12 deletions

63
src/command/builtin.rs Normal file
View file

@ -0,0 +1,63 @@
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<String>) -> ExitCode;
pub struct Builtin {
function: BuiltinFunction,
args: Vec<String>,
}
impl Builtin {
pub fn new(argv: &Vec<String>) -> Result<Self, NoSuchBuiltinError> {
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)
}
}
#[derive(Debug)]
pub struct NoSuchBuiltinError;
fn cd(args: &Vec<String>) -> 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,
};
}
let exit_code: ExitCode;
if path.is_some() {
exit_code = match set_current_dir(path.unwrap()) {
Ok(()) => ExitCode::success(),
Err(_e) => ExitCode::new(2),
};
} else {
exit_code = ExitCode::success();
}
if exit_code.get() != 0 {
print_error("lol");
}
exit_code
}

View file

@ -0,0 +1,31 @@
use super::builtin::Builtin;
use super::unix_program::UnixProgram;
use super::Command;
pub struct CommandBuilder {
argv: Vec<String>,
}
impl CommandBuilder {
pub fn new() -> Self {
Self { argv: Vec::new() }
}
pub fn argv(&mut self, argv: Vec<String>) -> &Self {
self.argv = argv;
self
}
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

@ -7,16 +7,17 @@ pub struct CommandSequence {
} }
impl CommandSequence { impl CommandSequence {
pub fn new(command: impl Command + 'static) -> Self { pub fn new(command: Box<dyn Command>) -> Self {
Self { Self {
command: Box::new(command), command,
next_command: None, next_command: None,
} }
} }
pub fn add(&mut self, command: impl Command + 'static) { #[allow(dead_code)]
pub fn add(&mut self, command: Box<dyn Command>) {
if self.next_command.is_none() { if self.next_command.is_none() {
self.next_command = Some(Box::new(CommandSequence::new(command))); self.next_command = Some(Box::new(Self::new(command)));
} else { } else {
self.next_command.as_mut().unwrap().add(command); self.next_command.as_mut().unwrap().add(command);
} }

View file

@ -1,3 +1,5 @@
pub mod builtin;
pub mod command_builder;
pub mod command_sequence; pub mod command_sequence;
pub mod unix_program; pub mod unix_program;

View file

@ -7,7 +7,8 @@ pub struct UnixProgram {
} }
impl UnixProgram { impl UnixProgram {
pub fn new(mut argv: Vec<String>) -> Self { pub fn new(argv: &Vec<String>) -> Self {
let mut argv = argv.clone();
let program = argv.remove(0); let program = argv.remove(0);
let mut command = std::process::Command::new(&program); let mut command = std::process::Command::new(&program);
command.args(argv); command.args(argv);
@ -39,7 +40,7 @@ impl Command for UnixProgram {
"{}: command not found", "{}: command not found",
self.command.get_program().to_str().unwrap() self.command.get_program().to_str().unwrap()
); );
print_error(message); print_error(message.as_str());
ExitCode::not_found() ExitCode::not_found()
} }
} }

View file

@ -1,6 +1,6 @@
use std::path::Path; use std::path::Path;
pub fn print_error(message: String) { pub fn print_error(message: &str) {
let name = std::env::args().next().unwrap(); let name = std::env::args().next().unwrap();
let name = Path::new(&name).file_name().unwrap().to_str().unwrap(); let name = Path::new(&name).file_name().unwrap().to_str().unwrap();

View file

@ -14,4 +14,8 @@ impl ExitCode {
pub fn not_found() -> Self { pub fn not_found() -> Self {
Self { exit_code: 127 } Self { exit_code: 127 }
} }
pub fn success() -> Self {
Self { exit_code: 0 }
}
} }

View file

@ -1,14 +1,12 @@
use crate::command::command_builder::CommandBuilder;
use crate::command::command_sequence::CommandSequence; use crate::command::command_sequence::CommandSequence;
use crate::command::unix_program::UnixProgram;
pub fn parse_command_line(line: String) -> Option<CommandSequence> { pub fn parse_command_line(line: String) -> Option<CommandSequence> {
let argv: Vec<String> = line.split_whitespace().map(|s| s.to_string()).collect(); let argv: Vec<String> = line.split_whitespace().map(|s| s.to_string()).collect();
if !argv.is_empty() { if !argv.is_empty() {
let command = UnixProgram::new(argv); let command = CommandBuilder::new().argv(argv).build();
let command_sequence = CommandSequence::new(command); Some(CommandSequence::new(command))
Some(command_sequence)
} else { } else {
None None
} }