diff --git a/src/wasm/src/filesystem/file.rs b/src/wasm/src/filesystem/file.rs index a917b9f..3b63f34 100644 --- a/src/wasm/src/filesystem/file.rs +++ b/src/wasm/src/filesystem/file.rs @@ -12,11 +12,10 @@ impl File { data, } } - - // pub fn read(&self) -> String { - // self.data.clone() - // } - // pub fn write(&mut self, data: String) { - // self.data = data; - // } + pub fn read(&self) -> String { + self.data.clone() + } + pub fn write(&mut self, data: String) { + self.data = data; + } } diff --git a/src/wasm/src/filesystem/node.rs b/src/wasm/src/filesystem/node.rs index 96bff5c..a836a7e 100644 --- a/src/wasm/src/filesystem/node.rs +++ b/src/wasm/src/filesystem/node.rs @@ -37,13 +37,13 @@ impl Node { } } - // pub fn as_file(&self) -> Option<&File> { - // if let NodeType::File(ref file) = self.node_type { - // Some(file) - // } else { - // None - // } - // } + pub fn as_file(&self) -> Option<&File> { + if let NodeType::File(ref file) = self.node_type { + Some(file) + } else { + None + } + } pub fn get_node_type(&self) -> NodeType { self.node_type.clone() diff --git a/src/wasm/src/shell/exec.rs b/src/wasm/src/shell/exec.rs index a01e9be..d6b5aef 100644 --- a/src/wasm/src/shell/exec.rs +++ b/src/wasm/src/shell/exec.rs @@ -69,7 +69,13 @@ fn ls(&self) -> String { "/".to_owned() } }; - let mut current_node = Rc::clone(&self.current); + let mut current_node = { + if new_path.starts_with("/") { + Rc::clone(&self.root) + } else { + Rc::clone(&self.current) + } + }; console::log_1(&JsValue::from_str(new_path.as_str())); for path in new_path.split("/").filter(|&x| !x.is_empty()) { // console::log_1(&JsValue::from_str(path)); @@ -120,7 +126,13 @@ fn ls(&self) -> String { return "usage: mkdir [-pv] [-m mode] directory_name ...".to_string() } let new_path = args.first().unwrap().clone(); - let mut current_node = Rc::clone(&self.current); + let mut current_node = { + if new_path.starts_with("/") { + Rc::clone(&self.root) + } else { + Rc::clone(&self.current) + } + }; if current_node.borrow().as_directory().is_none() { return "Not a directory".to_string(); } @@ -162,6 +174,7 @@ fn ls(&self) -> String { output.push_str(arg.as_str()); output.push_str(" "); } + output.push_str(" "); output } @@ -178,20 +191,175 @@ fn ls(&self) -> String { " ".to_string() } - pub fn execute(&mut self, input: Statement) -> String { - match &input.command[..] { +fn cat(&self, args: Vec) -> String { + if args.is_empty() { + return "usage: cat file_name".to_string(); + } + + let file_name = args[0].clone(); + let mut current_node = if file_name.starts_with("/") { + Rc::clone(&self.root) + } else { + Rc::clone(&self.current) + }; + + let parts: Vec<&str> = file_name.split('/').filter(|&x| !x.is_empty()).collect(); + let mut file_node: Option = None; + let mut found = false; + + for (i, node) in parts.iter().enumerate() { + let children = current_node.borrow().get_children(); + for child in children { + let child_node = Rc::clone(&child); + if child_node.borrow().get_name() == *node { + match child_node.borrow().get_node_type() { + NodeType::File(ref file) => { + if i == parts.len() - 1 { + file_node = Some(file.clone()); + found = true; + } else { + return "Not a directory".to_string(); + } + }, + NodeType::Directory(_) => { + if i < parts.len() - 1 { + current_node = Rc::clone(&child_node); + found = true; + } else { + return "Unsupported action for cat".to_string(); + } + } + } + break; // Exit the inner loop once the match is found + } + } + if !found { + return "File not found".to_string(); + } + found = false; // Reset found for the next iteration + } + + match file_node { + Some(file_node) => file_node.read(), + None => "File not found".to_string(), + } +} + +fn write(&self, args: Vec) -> String { + // Validate arguments + if args.len() < 2 { + return "usage: write file_name 'content'".to_string(); + } + + let file_name = args[0].clone(); + let content = args[1].clone(); + + let mut current_node = if file_name.starts_with("/") { + Rc::clone(&self.root) + } else { + Rc::clone(&self.current) + }; + + let parts: Vec<&str> = file_name.split('/').filter(|&x| !x.is_empty()).collect(); + let mut file_node: Option>> = None; + let mut found = false; + + for (i, node) in parts.iter().enumerate() { + let children = current_node.borrow().get_children(); + for child in children { + let child_node = Rc::clone(&child); + if child_node.borrow().get_name() == *node { + match child_node.borrow().get_node_type() { + NodeType::File(ref file) => { + if i == parts.len() - 1 { + file_node = Some(Rc::clone(&child)); + found = true; + } else { + return "File not found".to_string(); + } + }, + NodeType::Directory(_) => { + if i < parts.len() - 1 { + current_node = Rc::clone(&child_node); + found = true; + } else { + return "Unsupported action for write".to_string(); + } + } + } + break; // Exit the inner loop once the match is found + } + } + if !found { + return "File not found".to_string(); + } + found = false; // Reset found for the next iteration + } + + match file_node { + Some(file_node) => { + match file_node.borrow().get_node_type() { + NodeType::Directory(_) => { + return "Not a file".to_string(); + }, + NodeType::File(ref mut file) => { + file.write(content) + } + } + }, + None => return "File not found".to_string(), + } + return " ".to_string(); +} + +pub fn execute(&mut self, statements: Vec) -> String { + let mut output = String::new(); + // let mut previous_output = None; + + for (i, statement) in statements.iter().enumerate() { + if i > 0 { + if let Some(op) = statements[i - 1].operators.last() { + match op.as_str() { + // "|" => { + // // Handle piping (not implemented in this example) + // // Assume piping is handled via previous_output + // previous_output = Some(output.clone()); + // } + // ">" => { + // // Handle output redirection + // if let Some(file_name) = statement.arguments.first() { + // std::fs::write(file_name, output.clone()).expect("Unable to write file"); + // output.clear(); + // } + // } + // ">>" => { + // // Handle append output redirection + // if let Some(file_name) = statement.arguments.first() { + // use std::fs::OpenOptions; + // let mut file = OpenOptions::new().append(true).open(file_name).expect("Unable to open file"); + // use std::io::Write; + // write!(file, "{}", output).expect("Unable to write file"); + // output.clear(); + // } + // } + _ => {} + } + } + } + + output = match &statement.command[..] { "" => " ".to_owned(), "github" => "github".to_owned(), "help" => serde_json::to_string("

\nhelp command\n

").unwrap(), "license" => "license command".to_owned(), "ls" => Self::ls(self), "pwd" => Self::pwd(self), - "cd" => Self::cd(self, input.arguments), + "cd" => Self::cd(self, statement.arguments.clone()), "clear" => "".to_owned(), - "echo" => Self::echo(self, input.arguments), - "cat" => "cat command".to_owned(), - "touch" => Self::touch(self, input.arguments), - "mkdir" => Self::mkdir(self, input.arguments), + "echo" => Self::echo(self, statement.arguments.clone()), + "cat" => Self::cat(self, statement.arguments.clone()), + "touch" => Self::touch(self, statement.arguments.clone()), + "mkdir" => Self::mkdir(self, statement.arguments.clone()), "rm" => "rm command".to_owned(), "rmdir" => "rmdir command".to_owned(), "mv" => "mv command".to_owned(), @@ -199,30 +367,11 @@ fn ls(&self) -> String { "exit" => "Goodbye!".to_owned(), "whoami" => "root".to_owned(), "which" => "which command".to_owned(), - // "alias" => "alias command".to_owned(), - // "env" => "env command".to_owned(), - // "grep" => "grep command".to_owned(), - // "find" => "find command".to_owned(), - // "export" => "export command".to_owned(), - // "wc" => "wc command".to_owned(), - // "nano" => "nano command".to_owned(), - // "vi" => "vi command".to_owned(), - // "vim" => "vim command".to_owned(), - // "emacs" => "emacs command".to_owned(), - // "sed" => "sed command".to_owned(), - // "chmod" => "chmod command".to_owned(), - // "chown" => "chown command".to_owned(), - // "chgrp" => "chgrp command".to_owned(), - // "useradd" => "useradd command".to_owned(), - // "userdel" => "userdel command".to_owned(), - // "passwd" => "passwd command".to_owned(), - // "su" => "su command".to_owned(), - // "sudo" => "sudo command".to_owned(), - // "ln" => "ln command".to_owned(), - // "who" => "who command".to_owned(), - // "top" => "top command".to_owned(), - // "man" => "man command".to_owned(), + "write" => Self::write(self, statement.arguments.clone()), command => (command.to_owned() + ": command not found").to_owned(), - } - } + }; + } + + output +} } \ No newline at end of file diff --git a/src/wasm/src/shell/lexer.rs b/src/wasm/src/shell/lexer.rs index d1d3564..af20fc4 100644 --- a/src/wasm/src/shell/lexer.rs +++ b/src/wasm/src/shell/lexer.rs @@ -1,15 +1,13 @@ -/** - * Parse commands, by space, arguments and options for now. - */ - pub enum Token { Command(String), + Operator(String), Option(String), Argument(String), } pub struct Statement { pub command: String, + pub operators: Vec, pub options: Vec, pub arguments: Vec, } @@ -18,6 +16,7 @@ impl Statement { pub fn new() -> Statement { Statement { command: String::new(), + operators: Vec::new(), options: Vec::new(), arguments: Vec::new(), } @@ -26,6 +25,7 @@ impl Statement { pub fn push(&mut self, token: Token) { match token { Token::Command(command) => self.command = command, + Token::Operator(operator) => self.operators.push(operator), Token::Option(option) => self.options.push(option), Token::Argument(argument) => self.arguments.push(argument), } @@ -39,27 +39,35 @@ impl Lexer { Lexer {} } - /** A shitty lexer for now... only one statement at a time - * Want to add piping and redirections later - */ - pub fn lex(&self, input: &str) -> Statement { - let mut statement = Statement::new(); + pub fn lex(&self, input: &str) -> Vec { + let mut statements = Vec::new(); + let mut current_statement = Statement::new(); let mut input_split = input.split_whitespace(); - if let Some(command) = input_split.next() { - statement.push(Token::Command(command.to_string())); - for argument in input_split { - if argument.starts_with("--") { - statement.push(Token::Option(argument.to_string())); - } else if argument.starts_with("-") { - argument.chars().skip(1).for_each(|c| { - statement.push(Token::Option(c.to_string())); - }); - } else { - statement.push(Token::Argument(argument.to_string())); + while let Some(token) = input_split.next() { + match token { + "|" | ">" | ">>" => { + current_statement.push(Token::Operator(token.to_string())); + statements.push(current_statement); + current_statement = Statement::new(); + } + _ => { + if current_statement.command.is_empty() { + current_statement.push(Token::Command(token.to_string())); + } else if token.starts_with("--") { + current_statement.push(Token::Option(token.to_string())); + } else if token.starts_with("-") { + token.chars().skip(1).for_each(|c| { + current_statement.push(Token::Option(c.to_string())); + }); + } else { + current_statement.push(Token::Argument(token.to_string())); + } } } } - statement + + statements.push(current_statement); + statements } } \ No newline at end of file