From 508550c4d5c1b8933decfb47fc02481959ab0c65 Mon Sep 17 00:00:00 2001 From: Rory Dudley Date: Fri, 16 Feb 2024 19:21:58 -0700 Subject: Initial commit An extremely miniamal shell. It is capable of forking processes, and passing arguments to them, but that's pretty much it. --- .gitignore | 1 + Cargo.lock | 7 +++++ Cargo.toml | 14 ++++++++++ src/main.rs | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/main.rs 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 = 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); +} -- cgit v1.2.3