diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main.rs | 20 | ||||
-rw-r--r-- | src/recite.rs | 181 | ||||
-rw-r--r-- | src/recite/erro.rs | 15 | ||||
-rw-r--r-- | src/recite/ps.rs | 71 |
4 files changed, 172 insertions, 115 deletions
diff --git a/src/main.rs b/src/main.rs index 986e006..44f2726 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ mod recite; +use libc::{waitpid, WNOHANG}; use recite::path::prefresh; use recite::Poem; use std::io::{self, Write}; @@ -53,11 +54,12 @@ fn repl(path: &Vec<&Path>, prompt: &str) { // Parse a poem let poem = Poem::read(poetry); match poem { - Some(poem) => { - poem.recite(path, &mut bins); - } + Some(poem) => match poem.recite(path, &mut bins) { + Ok(_) => {} + Err(e) => eprintln!("dwvsh: {}", e), + }, None => {} - } + }; } } @@ -87,6 +89,16 @@ fn main() { io::stdout().flush().unwrap(); }) .unwrap(); + + signal_hook::low_level::register(signal_hook::consts::SIGCHLD, move || { + let mut status: i32 = -1; + let pid: i32 = waitpid(-1, &mut status, WNOHANG); + if pid != -1 { + print!("[&] + done {}", pid); + io::stdout().flush().unwrap(); + } + }) + .unwrap(); }; // Begin evaluating commands diff --git a/src/recite.rs b/src/recite.rs index 4e1dc1f..bfcd6b1 100644 --- a/src/recite.rs +++ b/src/recite.rs @@ -1,5 +1,10 @@ +pub mod erro; pub mod path; +mod ps; +use crate::ctask; +use crate::task; use core::fmt; +use erro::Mishap; use path::prefresh; use std::io::{self, Write}; use std::path::Path; @@ -44,6 +49,56 @@ impl fmt::Display for Meter { } } +impl Meter { + fn incant_none(verse: &Verse, out: &mut String) -> Result<i32, Mishap> { + let child = task!(verse, out); + + let output = child + .wait_with_output() + .map_err(|_| Mishap::Terminated(verse.stanza.to_string()))?; + + if !output.status.success() { + return Err(Mishap::Else(verse.stanza.to_string())); + } + + Ok(output.status.code().unwrap_or(0)) + } + + fn incant_couplet(verse: &Verse, out: &mut String) -> Result<i32, Mishap> { + let child = ctask!(verse, out); + + let output = child + .wait_with_output() + .map_err(|_| Mishap::Terminated(verse.stanza.to_string()))?; + + if !output.status.success() { + return Err(Mishap::Else(verse.stanza.to_string())); + } + + out.push_str( + String::from_utf8_lossy(&output.stdout) + .into_owned() + .as_str(), + ); + + Ok(output.status.code().unwrap_or(0)) + } + + fn incant_quiet(verse: &Verse, out: &mut String) -> Result<i32, Mishap> { + let child = task!(verse, out); + println!("[&] {}", child.id()); + Ok(0) + } + + fn incant_and(verse: &Verse, out: &mut String) -> Result<i32, Mishap> { + Meter::incant_none(verse, out) + } + + fn incant_string(verse: &Verse, out: &mut String) -> Result<i32, Mishap> { + Meter::incant_none(verse, out) + } +} + /// Holds a program to be called /// /// This is simply the first word in a full command [String], dilineated via @@ -259,7 +314,7 @@ impl Poem { /// None => {} /// } /// ``` - pub fn recite(&self, path: &Vec<&Path>, bins: &mut Vec<String>) -> bool { + pub fn recite(&self, path: &Vec<&Path>, bins: &mut Vec<String>) -> Result<(), Mishap> { // Variable for storing the output of a piped verse let mut out: String = String::new(); @@ -300,121 +355,25 @@ impl Poem { } } - // If the verse is a couplet, it means it needs the output of the - // previous verse on `STDIN` - if verse.couplet { - match verse.meter { - Meter::Couplet => { - let mut child = Command::new(verse.verb()) - .args(verse.clause()) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn() - .expect("dwvsh: error 0"); - - let stdin = child.stdin.as_mut().expect("dwvsh: error 6"); - stdin.write_all(&out.as_bytes()).expect("dwvsh: error 7"); - out.clear(); - - let output = child.wait_with_output().unwrap(); - out = String::from_utf8_lossy(&output.stdout).to_string(); + // Incant the verse, based on its meter + match verse.meter { + Meter::None => Meter::incant_none(verse, &mut out)?, + Meter::Couplet => Meter::incant_couplet(verse, &mut out)?, + Meter::Quiet => Meter::incant_quiet(verse, &mut out)?, + Meter::And => Meter::incant_and(verse, &mut out)?, + Meter::String => match Meter::incant_string(verse, &mut out) { + Ok(_) => 0, + Err(e) => { + eprintln!("dwvsh: {}", e); + 1 } - Meter::Quiet => { - let mut child = Command::new(verse.verb()) - .args(verse.clause()) - .stdin(Stdio::piped()) - .spawn() - .expect("dwvsh: error 1"); - - let stdin = child.stdin.as_mut().expect("dwvsh: error 8"); - stdin.write_all(&out.as_bytes()).expect("dwvsh: error 9"); - out.clear(); - - print!("[f] {}", child.id()); - std::thread::spawn(move || { - child.wait().unwrap(); - println!("[f] +done {}", child.id()); - io::stdout().flush().unwrap(); - }); - } - Meter::String => { - let mut child = Command::new(verse.verb()) - .args(verse.clause()) - .spawn() - .expect("dwvsh: error 5"); - - let stdin = child.stdin.as_mut().expect("dwvsh: error 8"); - stdin.write_all(&out.as_bytes()).expect("dwvsh: error 9"); - out.clear(); - - child.wait().unwrap(); - } - Meter::And | Meter::None => { - let mut child = Command::new(verse.verb()) - .args(verse.clause()) - .stdin(Stdio::piped()) - .spawn() - .expect("dwvsh: error 2"); - - let stdin = child.stdin.as_mut().expect("dwvsh: error 10"); - stdin.write_all(&out.as_bytes()).expect("dwvsh: error 11"); - out.clear(); - - if !child.wait().unwrap().success() { - break; - } - } - }; - } else { - match verse.meter { - Meter::Couplet => { - let child = Command::new(verse.verb()) - .args(verse.clause()) - .stdout(Stdio::piped()) - .spawn() - .expect("dwvsh: error 3"); - - let output = child.wait_with_output().unwrap(); - out = String::from_utf8_lossy(&output.stdout).to_string(); - } - Meter::Quiet => { - let mut child = Command::new(verse.verb()) - .args(verse.clause()) - .spawn() - .expect("dwvsh: error 4"); - - println!("[f] {}", child.id()); - std::thread::spawn(move || { - child.wait().unwrap(); - print!("[f] +done {}\n", child.id()); - io::stdout().flush().unwrap(); - }); - } - Meter::String => { - let mut child = Command::new(verse.verb()) - .args(verse.clause()) - .spawn() - .expect("dwvsh: error 5"); - - child.wait().unwrap(); - } - Meter::And | Meter::None => { - let mut child = Command::new(verse.verb()) - .args(verse.clause()) - .spawn() - .expect("dwvsh: error 5"); - - if !child.wait().unwrap().success() { - break; - } - } - }; - } + }, + }; } // If we've successfully exited the loop, then all verse's were // properly recited - true + Ok(()) } /// Parse a [Poem] from a raw [String] input diff --git a/src/recite/erro.rs b/src/recite/erro.rs new file mode 100644 index 0000000..00f57b3 --- /dev/null +++ b/src/recite/erro.rs @@ -0,0 +1,15 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum Mishap { + #[error("broken pipe: {0}")] + BrokenPipe(String), + // #[error("exec format error: {0}")] + // ExecFormat(String), + #[error("permission denied: {0}")] + PermissionDenied(String), + #[error("terminated: {0}")] + Terminated(String), + #[error("exec error: {0}")] + Else(String), +} diff --git a/src/recite/ps.rs b/src/recite/ps.rs new file mode 100644 index 0000000..3557505 --- /dev/null +++ b/src/recite/ps.rs @@ -0,0 +1,71 @@ +#[macro_export] +macro_rules! task { + ($verse:expr, $out:expr) => { + if $verse.couplet { + let mut child = Command::new($verse.verb()) + .args($verse.clause()) + .stdin(Stdio::piped()) + .spawn() + .map_err(|e| match e.kind() { + io::ErrorKind::PermissionDenied => Mishap::PermissionDenied($verse.verb()), + _ => Mishap::Else($verse.verb()), + })?; + + let stdin = child + .stdin + .as_mut() + .ok_or(Mishap::BrokenPipe($verse.verb()))?; + stdin + .write_all(&$out.as_bytes()) + .map_err(|_| Mishap::BrokenPipe($verse.verb()))?; + $out.clear(); + + child + } else { + Command::new($verse.verb()) + .args($verse.clause()) + .spawn() + .map_err(|e| match e.kind() { + io::ErrorKind::PermissionDenied => Mishap::PermissionDenied($verse.verb()), + _ => Mishap::Else($verse.verb()), + })? + } + }; +} + +#[macro_export()] +macro_rules! ctask { + ($verse:expr, $out:expr) => { + if $verse.couplet { + let mut child = Command::new($verse.verb()) + .args($verse.clause()) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + .map_err(|e| match e.kind() { + io::ErrorKind::PermissionDenied => Mishap::PermissionDenied($verse.verb()), + _ => Mishap::Else($verse.verb()), + })?; + + let stdin = child + .stdin + .as_mut() + .ok_or(Mishap::BrokenPipe($verse.verb()))?; + stdin + .write_all(&$out.as_bytes()) + .map_err(|_| Mishap::BrokenPipe($verse.verb()))?; + $out.clear(); + + child + } else { + Command::new($verse.verb()) + .args($verse.clause()) + .stdout(Stdio::piped()) + .spawn() + .map_err(|e| match e.kind() { + io::ErrorKind::PermissionDenied => Mishap::PermissionDenied($verse.verb()), + _ => Mishap::Else($verse.verb()), + })? + } + }; +} |