From 0548e74cb3227716cf445f27bd64b8c0b4d0f981 Mon Sep 17 00:00:00 2001 From: Rory Dudley Date: Mon, 26 Feb 2024 23:14:13 -0700 Subject: Cleanup recite(), custom errors, fixed forking First off, moved the giant match statements out of recite(), and into macros in src/recite/ps.rs. There still needs to be two, since any verse using the 'couplet' meter will need to redirect its STDOUT. Now the recite() function returns a Result<(), Mishap>, which can be invoked when calling the incant_ functions. Custom errors were added in the form of 'Mishap''s. They are intended to be returned from the incant_ functions, in the event that something goes wrong with the Command::spawn() or Child::wait(). They each take a String, which should be the verb or stanza that was entered by the user. The incant_ functions separate the functionality of each type of meter from the recite() function. They return a Result, where i32 is the exit code of the program that ran, and Mishap is a possible error. Before, the shell was cheating at forking a process to the background. It would actually spawn a thread to wait for that process to finish. Now, the program simply registers a handler for SIGCHLD, and uses libc's waitpid() function to reap the child process, and print some output to the user, indicating that it's finished. --- src/recite/erro.rs | 15 ++++++++++++ src/recite/ps.rs | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 src/recite/erro.rs create mode 100644 src/recite/ps.rs (limited to 'src/recite') 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()), + })? + } + }; +} -- cgit v1.2.3