aboutsummaryrefslogtreecommitdiff
path: root/src/commandline/command.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/commandline/command.rs')
-rw-r--r--src/commandline/command.rs161
1 files changed, 161 insertions, 0 deletions
diff --git a/src/commandline/command.rs b/src/commandline/command.rs
new file mode 100644
index 0000000..d00f420
--- /dev/null
+++ b/src/commandline/command.rs
@@ -0,0 +1,161 @@
+use std::io::{Error};
+use std::path::{PathBuf};
+use std::process::ExitStatus;
+use std::process::Command as Process;
+use super::builtins::{cd, set, unset};
+
+// > overwrite
+// >> append
+// | pipe
+
+#[derive(Debug)]
+enum Redirect {
+ Std,
+ FileOverwrite(String),
+ FileAppend(String),
+}
+
+#[derive(Debug, PartialEq, Copy, Clone)]
+pub(in crate::commandline) enum RunIf { Always, ExitSuccess, ExitFailure }
+
+impl RunIf {
+ pub(in crate::commandline) fn can_run(&self, status: &Option<ExitStatus>) -> bool {
+ if *self == RunIf::Always {
+ return true;
+ }
+ match status {
+ Some(s) => {
+ (*self == RunIf::ExitSuccess && s.success())
+ || (*self == RunIf::ExitFailure && !s.success())
+ }
+ None => true,
+ }
+ }
+}
+
+pub(in crate::commandline) enum RunResult {
+ Command(ExitStatus),
+ Builtin,
+}
+
+#[derive(Debug)]
+pub struct Command {
+ args: Vec<String>,
+ stdout: Redirect,
+ pub(in crate::commandline) when: RunIf,
+}
+
+impl Command {
+ pub(in crate::commandline) fn new(line: &str, when: RunIf) -> Command {
+ let (args, stdout) = tokenize(line);
+ Command { args, stdout, when }
+ }
+
+ pub(in crate::commandline) fn run(
+ &self,
+ home: &PathBuf,
+ status: &Option<ExitStatus>,
+ ) -> Result<RunResult, Error> {
+ match self.args[0].as_str() {
+ "!" => {
+ println!("{:?}", status);
+ Ok(RunResult::Builtin)
+ }
+ "cd" => cd(&self.args[1..], home),
+ "exit" => {
+ std::process::exit(0);
+ }
+ "set" => set(&self.args[1..]),
+ "unset" => unset(&self.args[1..]),
+ _ => {
+ let mut child = Process::new(&self.args[0]).args(&self.args[1..]).spawn()?;
+ Ok(RunResult::Command(child.wait().unwrap()))
+ }
+ }
+ }
+}
+
+enum TokenType {
+ Argument,
+ StdoutFileOverwrite,
+ StdoutFileAppend,
+}
+
+fn tokenize(line: &str) -> (Vec<String>, Redirect) {
+ let mut args: Vec<String> = Vec::new();
+ let mut stdout = Redirect::Std;
+
+ let mut iter = line.chars().peekable();
+ let mut token = String::new();
+ let mut token_type = TokenType::Argument;
+ let mut quote = false;
+
+ while let Some(i) = iter.next() {
+ match i {
+ ' ' => {
+ if quote {
+ token.push(' ');
+ }
+ }
+ '\'' => match iter.peek() {
+ Some(&'\'') | Some(&'>') | Some(&'&') => {
+ token.push(iter.next().unwrap());
+ }
+ _ => {
+ quote = !quote;
+ }
+ },
+ '>' => {
+ if iter.peek() == Some(&'>') {
+ token_type = TokenType::StdoutFileAppend;
+ iter.next();
+ } else {
+ token_type = TokenType::StdoutFileOverwrite;
+ }
+ }
+ _ => {
+ token.push(i);
+ }
+ }
+
+ if !token.is_empty() && ((iter.peek() == Some(&' ') && !quote) || iter.peek() == None) {
+ match token_type {
+ TokenType::Argument => args.push(token),
+ TokenType::StdoutFileOverwrite => stdout = Redirect::FileOverwrite(token),
+ TokenType::StdoutFileAppend => stdout = Redirect::FileAppend(token),
+ }
+ token = String::new();
+ }
+ }
+
+ (args, stdout)
+}
+/*
+#[test]
+fn test_tokenizer() {
+ {
+ let ls = tokenize("ls -l");
+ assert_eq!(ls.args, vec!("ls", "-l"));
+ let string = tokenize("ls -l 'something else'");
+ assert_eq!(string.args, vec!("ls", "-l", "something else"));
+ let escape = tokenize("ls -l 'junction jan''s'");
+ assert_eq!(escape.args, vec!("ls", "-l", "junction jan\'s"));
+ }
+ {
+ let o = tokenize("&& ls");
+ assert_eq!(o.args, vec!("ls"));
+ assert_eq!(o.when, RunOn::ExitSuccess);
+ let f = tokenize("|| ls");
+ assert_eq!(f.args, vec!("ls"));
+ assert_eq!(f.when, RunOn::ExitFailure);
+ }
+ println!("{:?}", tokenize("ls -l something'>"));
+ println!("{:?}", tokenize("ls -l something'>'>"));
+ println!("{:?}", tokenize("ls -l something >output"));
+ println!("{:?}", tokenize("ls -l something > output"));
+ println!("{:?}", tokenize("ls -l something >'junction jan''s'"));
+ println!("{:?}", tokenize("ls -l something >>output"));
+ println!("{:?}", tokenize("ls -l something >> output"));
+ println!("{:?}", tokenize("ls -l something >>'junction jan''s'"));
+}
+*/