summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRory Dudley2024-02-16 19:21:58 -0700
committerRory Dudley2024-02-16 19:21:58 -0700
commit508550c4d5c1b8933decfb47fc02481959ab0c65 (patch)
treeec83275b7c303fa1fbe5e30feae77981836af2b8
downloaddwarvish-508550c4d5c1b8933decfb47fc02481959ab0c65.tar.gz
Initial commit
An extremely miniamal shell. It is capable of forking processes, and passing arguments to them, but that's pretty much it.
Notes
Notes: This is pretty much a prototype, to see how easily something like a shell could be implemented in Rust.
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock7
-rw-r--r--Cargo.toml14
-rw-r--r--src/main.rs86
4 files changed, 108 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/target
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..73fb9be
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "dwarvish"
+version = "0.0.0"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..e7d40d3
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "dwarvish"
+version = "0.0.0"
+edition = "2021"
+license = "MIT"
+description = "A POSIX compliance shell and tiny functional programming language"
+
+[[bin]]
+name = "dwvsh"
+path = "src/main.rs"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..c592e51
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,86 @@
+use std::fs;
+use std::io;
+use std::io::Write;
+use std::process::Command;
+
+fn eval(paths: &[&str], prompt: &str) {
+ let mut bins: Vec<String> = Vec::new();
+
+ for path in paths {
+ let files = fs::read_dir(path).expect("Unable to read files in your path");
+ for file in files {
+ bins.push(file.unwrap().path().display().to_string());
+ }
+ }
+
+ loop {
+ // Output the prompt
+ io::stdout().flush().unwrap();
+ print!("{}", prompt);
+ io::stdout().flush().unwrap();
+
+ // Wait for user input
+ let mut input = String::new();
+ io::stdin()
+ .read_line(&mut input)
+ .expect("Unable to evaluate the input string");
+ let input = input.trim();
+
+ // Check if user wants to exit the shell
+ if input == "exit" || input == "quit" {
+ break;
+ }
+
+ // Parse command and arguments
+ let mut split = input.split(' ');
+ let cmd = match split.next() {
+ Some(str) if str.trim().is_empty() => continue,
+ Some(str) => str.trim(),
+ None => continue,
+ };
+
+ // Parse arguments
+ let mut args = vec![];
+ loop {
+ let next = split.next();
+ match next {
+ Some(str) => args.push(str),
+ None => break,
+ }
+ }
+
+ // Check if the command exists
+ let cmd = match bins.iter().find(|b| b.split("/").last().unwrap() == cmd) {
+ Some(cmd) => cmd,
+ None => {
+ println!("Command not found");
+ continue;
+ }
+ };
+
+ // Run the command (and wait for it to finish)
+ let mut child = match Command::new(cmd).args(args).spawn() {
+ Ok(ch) => ch,
+ Err(_) => {
+ println!("Unable to fork");
+ continue;
+ }
+ };
+ child.wait().unwrap();
+ }
+}
+
+fn main() {
+ let paths = [
+ "/bin",
+ "/sbin",
+ "/usr/bin",
+ "/usr/sbin",
+ "/usr/local/bin",
+ "/usr/local/sbin",
+ ];
+
+ let prompt = "|> ";
+
+ eval(&paths, prompt);
+}