Skip to content

Commit

Permalink
basic cat and write
Browse files Browse the repository at this point in the history
  • Loading branch information
soohoonc committed Jun 9, 2024
1 parent 7de5668 commit f3619eb
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 69 deletions.
13 changes: 6 additions & 7 deletions src/wasm/src/filesystem/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
14 changes: 7 additions & 7 deletions src/wasm/src/filesystem/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
217 changes: 183 additions & 34 deletions src/wasm/src/shell/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -162,6 +174,7 @@ fn ls(&self) -> String {
output.push_str(arg.as_str());
output.push_str(" ");
}
output.push_str(" ");
output
}

Expand All @@ -178,51 +191,187 @@ fn ls(&self) -> String {
" ".to_string()
}

pub fn execute(&mut self, input: Statement) -> String {
match &input.command[..] {
fn cat(&self, args: Vec<String>) -> 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<File> = 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>) -> 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<Rc<RefCell<Node>>> = 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<Statement>) -> 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" => "<a href=\"https://github.com/soohoonc/\" target=\"_blank\">github</a>".to_owned(),
"help" => serde_json::to_string("<p className=\"text-emerald-500\">\nhelp command\n</p>").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(),
"cp" => "cp command".to_owned(),
"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
}
}
50 changes: 29 additions & 21 deletions src/wasm/src/shell/lexer.rs
Original file line number Diff line number Diff line change
@@ -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<String>,
pub options: Vec<String>,
pub arguments: Vec<String>,
}
Expand All @@ -18,6 +16,7 @@ impl Statement {
pub fn new() -> Statement {
Statement {
command: String::new(),
operators: Vec::new(),
options: Vec::new(),
arguments: Vec::new(),
}
Expand All @@ -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),
}
Expand All @@ -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<Statement> {
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
}
}

0 comments on commit f3619eb

Please sign in to comment.