summaryrefslogtreecommitdiffstats
path: root/src/poem/elements
diff options
context:
space:
mode:
Diffstat (limited to 'src/poem/elements')
-rw-r--r--src/poem/elements/verse.rs242
-rw-r--r--src/poem/elements/verse/logic.rs219
2 files changed, 251 insertions, 210 deletions
diff --git a/src/poem/elements/verse.rs b/src/poem/elements/verse.rs
index a1ae65f..42d7c6a 100644
--- a/src/poem/elements/verse.rs
+++ b/src/poem/elements/verse.rs
@@ -1,13 +1,18 @@
use super::rune::Rune;
use super::stanza::Stanza;
use super::word::Word;
+use crate::poem::anthology::Anthology;
use crate::poem::Poem;
+mod logic;
+use crate::compose::Environment;
+use crate::incant;
use libc::{waitpid, WNOHANG};
+use std::fmt::Debug;
use std::fs::OpenOptions;
use std::io::{self, Read, Write};
use std::os::unix::process::CommandExt;
use std::path::Path;
-use std::process::{Command, Output, Stdio};
+use std::process::{Child, Command, Output, Stdio};
use std::sync::{Arc, Mutex};
/// A [Stanza] and it's [meter](Rune)
@@ -27,6 +32,22 @@ pub struct Verse {
pub meter: Rune,
}
+pub trait Forkable<T> {
+ fn fork(&mut self, env: &mut Environment) -> Result<T, io::Error>;
+}
+
+impl Forkable<Child> for Command {
+ fn fork(&mut self, _env: &mut Environment) -> Result<Child, io::Error> {
+ self.spawn()
+ }
+}
+
+impl Forkable<Anthology> for Anthology {
+ fn fork(&mut self, env: &mut Environment) -> Result<Anthology, io::Error> {
+ self.spawn(env)
+ }
+}
+
impl Verse {
/// Create a new [Verse]
///
@@ -234,6 +255,8 @@ impl Verse {
&mut self,
out: &mut Vec<u8>,
pids: &mut Arc<Mutex<Vec<i32>>>,
+ env: &mut Environment,
+ anthology: Option<usize>,
) -> Result<i32, io::Error> {
// Read files into 'out' if Rune::Read is present in the verse's IO
if self.io.contains(&Rune::Read) {
@@ -250,217 +273,16 @@ impl Verse {
}
}
- // Build the command
- let mut command = Command::new(self.verb());
- command.args(self.clause().unwrap_or(vec![]));
-
- // Determine couplet status
- if self.couplet == 1 {
- // Verse is the left half of a couplet
- command.stdout(Stdio::piped());
- } else if self.couplet == 2 {
- // Verse is the right half of a couplet
- command.stdin(Stdio::piped());
- } else if self.couplet == 3 {
- // Verse is taking in and piping out output
- command.stdout(Stdio::piped());
- command.stdin(Stdio::piped());
- }
-
- // Setup for other IO
- if self.io.contains(&Rune::Write) || self.io.contains(&Rune::Addendum) {
- command.stdout(Stdio::piped());
- }
- if self.io.contains(&Rune::Write2) || self.io.contains(&Rune::Addendum2) {
- command.stderr(Stdio::piped());
- }
- if self.io.contains(&Rune::WriteAll) || self.io.contains(&Rune::AddendumAll) {
- command.stdout(Stdio::piped());
- command.stderr(Stdio::piped());
- }
-
- // Detach the process group, if in the [Rune::Quiet] meter
- if self.meter == Rune::Quiet {
- command.process_group(0);
- }
-
- // Spawn the process
- let mut child = command.spawn()?;
-
- // Pipe in command, if we're the right side of a couplet
- if self.couplet > 1 {
- let stdin = child.stdin.as_mut().ok_or(io::ErrorKind::BrokenPipe)?;
- stdin.write_all(&out)?;
- out.clear();
- }
-
- // Determine what to do based on the meter
- let mut output: Output;
- let mut err: Vec<u8> = Vec::new();
- match self.meter {
- Rune::None | Rune::And | Rune::Continue => {
- output = child.wait_with_output()?;
- if self.io.contains(&Rune::Write) || self.io.contains(&Rune::Addendum) {
- out.append(&mut output.stdout);
- }
- if self.io.contains(&Rune::Write2) || self.io.contains(&Rune::Addendum2) {
- err.append(&mut output.stderr);
- }
- if self.io.contains(&Rune::WriteAll) || self.io.contains(&Rune::AddendumAll) {
- out.append(&mut output.stdout);
- err.append(&mut output.stderr);
- }
+ // Build and run the command
+ match anthology {
+ Some(_) => {
+ let mut command = Anthology::new(self.verb());
+ incant!(self.verb(), command, out, pids, env, self)
}
- Rune::Couplet => {
- output = child.wait_with_output()?;
- out.append(&mut output.stdout);
- if self.io.contains(&Rune::Write2) || self.io.contains(&Rune::Addendum2) {
- err.append(&mut output.stderr);
- }
- if self.io.contains(&Rune::WriteAll) || self.io.contains(&Rune::AddendumAll) {
- err.append(&mut output.stderr);
- }
+ None => {
+ let mut command = Command::new(self.verb());
+ incant!(self.verb(), command, out, pids, env, self)
}
- Rune::Quiet => {
- println!("[&] {}", child.id());
-
- pids.lock().unwrap().push(child.id() as i32);
- let stanza = self.stanza.join(" ").to_string();
- let pids = Arc::clone(pids);
-
- unsafe {
- signal_hook::low_level::register(signal_hook::consts::SIGCHLD, move || {
- for pid in pids.lock().unwrap().iter() {
- let mut pid = *pid;
- let mut status: i32 = 0;
- pid = waitpid(pid, &mut status, WNOHANG);
- if pid > 0 {
- print!("\n[&] + done {}", stanza);
- io::stdout().flush().unwrap();
- }
- }
- })
- .unwrap();
- }
-
- return Ok(0);
- }
- _ => unreachable!(),
- }
-
- // Perform IO operations
- let mut oi = 0;
- let mut ei = 0;
- self.io.retain(|rune| *rune != Rune::Read);
- for io in self.io.iter() {
- let (f, f2) = match *io {
- Rune::Write => {
- oi += 1;
- (
- Some(
- OpenOptions::new()
- .create(true)
- .write(true)
- .open(&self.op[oi - 1])?,
- ),
- None,
- )
- }
- Rune::Write2 => {
- ei += 1;
- (
- None,
- Some(
- OpenOptions::new()
- .create(true)
- .write(true)
- .open(&self.ep[ei - 1])?,
- ),
- )
- }
- Rune::WriteAll => {
- oi += 1;
- ei += 1;
- (
- Some(
- OpenOptions::new()
- .create(true)
- .write(true)
- .open(&self.op[oi - 1])?,
- ),
- Some(
- OpenOptions::new()
- .create(true)
- .write(true)
- .open(&self.ep[ei - 1])?,
- ),
- )
- }
- Rune::Addendum => {
- oi += 1;
- (
- Some(
- OpenOptions::new()
- .create(true)
- .append(true)
- .open(&self.op[oi - 1])?,
- ),
- None,
- )
- }
- Rune::Addendum2 => {
- ei += 1;
- (
- None,
- Some(
- OpenOptions::new()
- .create(true)
- .append(true)
- .open(&self.ep[ei - 1])?,
- ),
- )
- }
- Rune::AddendumAll => {
- oi += 1;
- ei += 1;
- (
- Some(
- OpenOptions::new()
- .create(true)
- .append(true)
- .open(&self.op[oi - 1])?,
- ),
- Some(
- OpenOptions::new()
- .create(true)
- .append(true)
- .open(&self.ep[ei - 1])?,
- ),
- )
- }
- _ => unreachable!(),
- };
-
- match f {
- Some(mut file) => file.write(out)?,
- None => 0,
- };
-
- match f2 {
- Some(mut file) => file.write(&err)?,
- None => 0,
- };
}
-
- if !output.status.success() {
- return Ok(output.status.code().unwrap_or(-1));
- }
-
- err.clear();
- if self.meter != Rune::Couplet {
- out.clear();
- }
-
- Ok(output.status.code().unwrap_or(0))
}
}
diff --git a/src/poem/elements/verse/logic.rs b/src/poem/elements/verse/logic.rs
new file mode 100644
index 0000000..c1d3d62
--- /dev/null
+++ b/src/poem/elements/verse/logic.rs
@@ -0,0 +1,219 @@
+#[macro_export]
+macro_rules! incant {
+ ($verb:expr, $command:expr, $out:expr, $pids:expr, $env:expr, $self:expr) => {{
+ $command.args($self.clause().unwrap_or(vec![]));
+
+ // Determine couplet status
+ if $self.couplet == 1 {
+ // Verse is the left half of a couplet
+ $command.stdout(Stdio::piped());
+ } else if $self.couplet == 2 {
+ // Verse is the right half of a couplet
+ $command.stdin(Stdio::piped());
+ } else if $self.couplet == 3 {
+ // Verse is taking in and piping out output
+ $command.stdout(Stdio::piped());
+ $command.stdin(Stdio::piped());
+ }
+
+ // Setup for other IO
+ if $self.io.contains(&Rune::Write) || $self.io.contains(&Rune::Addendum) {
+ $command.stdout(Stdio::piped());
+ }
+ if $self.io.contains(&Rune::Write2) || $self.io.contains(&Rune::Addendum2) {
+ $command.stderr(Stdio::piped());
+ }
+ if $self.io.contains(&Rune::WriteAll) || $self.io.contains(&Rune::AddendumAll) {
+ $command.stdout(Stdio::piped());
+ $command.stderr(Stdio::piped());
+ }
+
+ // Detach the process group, if in the [Rune::Quiet] meter
+ if $self.meter == Rune::Quiet {
+ $command.process_group(0);
+ }
+
+ // Spawn the process
+ let mut child = $command.fork($env)?;
+
+ // Pipe in command, if we're the right side of a couplet
+ if $self.couplet > 1 {
+ let stdin = child.stdin.as_mut().ok_or(io::ErrorKind::BrokenPipe)?;
+ stdin.write_all(&$out)?;
+ $out.clear();
+ }
+
+ // Determine what to do based on the meter
+ let mut output: Output;
+ let mut err: Vec<u8> = Vec::new();
+ match $self.meter {
+ Rune::None | Rune::And | Rune::Continue => {
+ output = child.wait_with_output()?;
+ if $self.io.contains(&Rune::Write) || $self.io.contains(&Rune::Addendum) {
+ $out.append(&mut output.stdout);
+ }
+ if $self.io.contains(&Rune::Write2) || $self.io.contains(&Rune::Addendum2) {
+ err.append(&mut output.stderr);
+ }
+ if $self.io.contains(&Rune::WriteAll) || $self.io.contains(&Rune::AddendumAll) {
+ $out.append(&mut output.stdout);
+ err.append(&mut output.stderr);
+ }
+ }
+ Rune::Couplet => {
+ output = child.wait_with_output()?;
+ $out.append(&mut output.stdout);
+ if $self.io.contains(&Rune::Write2) || $self.io.contains(&Rune::Addendum2) {
+ err.append(&mut output.stderr);
+ }
+ if $self.io.contains(&Rune::WriteAll) || $self.io.contains(&Rune::AddendumAll) {
+ err.append(&mut output.stderr);
+ }
+ }
+ Rune::Quiet => {
+ println!("[&] {}", child.id());
+
+ $pids.lock().unwrap().push(child.id() as i32);
+ let stanza = $self.stanza.join(" ").to_string();
+ let pids = Arc::clone($pids);
+
+ unsafe {
+ signal_hook::low_level::register(signal_hook::consts::SIGCHLD, move || {
+ for pid in pids.lock().unwrap().iter() {
+ let mut pid = *pid;
+ let mut status: i32 = 0;
+ pid = waitpid(pid, &mut status, WNOHANG);
+ if pid > 0 {
+ print!("\n[&] + done {}", stanza);
+ io::stdout().flush().unwrap();
+ }
+ }
+ })
+ .unwrap();
+ }
+
+ return Ok(0);
+ }
+ _ => unreachable!(),
+ }
+
+ // Perform IO operations
+ let mut oi = 0;
+ let mut ei = 0;
+ $self.io.retain(|rune| *rune != Rune::Read);
+ for io in $self.io.iter() {
+ let (f, f2) = match *io {
+ Rune::Write => {
+ oi += 1;
+ (
+ Some(
+ OpenOptions::new()
+ .create(true)
+ .truncate(true)
+ .write(true)
+ .open(&$self.op[oi - 1])?,
+ ),
+ None,
+ )
+ }
+ Rune::Write2 => {
+ ei += 1;
+ (
+ None,
+ Some(
+ OpenOptions::new()
+ .create(true)
+ .truncate(true)
+ .write(true)
+ .open(&$self.ep[ei - 1])?,
+ ),
+ )
+ }
+ Rune::WriteAll => {
+ oi += 1;
+ ei += 1;
+ (
+ Some(
+ OpenOptions::new()
+ .create(true)
+ .truncate(true)
+ .write(true)
+ .open(&$self.op[oi - 1])?,
+ ),
+ Some(
+ OpenOptions::new()
+ .create(true)
+ .truncate(true)
+ .write(true)
+ .open(&$self.ep[ei - 1])?,
+ ),
+ )
+ }
+ Rune::Addendum => {
+ oi += 1;
+ (
+ Some(
+ OpenOptions::new()
+ .create(true)
+ .append(true)
+ .open(&$self.op[oi - 1])?,
+ ),
+ None,
+ )
+ }
+ Rune::Addendum2 => {
+ ei += 1;
+ (
+ None,
+ Some(
+ OpenOptions::new()
+ .create(true)
+ .append(true)
+ .open(&$self.ep[ei - 1])?,
+ ),
+ )
+ }
+ Rune::AddendumAll => {
+ oi += 1;
+ ei += 1;
+ (
+ Some(
+ OpenOptions::new()
+ .create(true)
+ .append(true)
+ .open(&$self.op[oi - 1])?,
+ ),
+ Some(
+ OpenOptions::new()
+ .create(true)
+ .append(true)
+ .open(&$self.ep[ei - 1])?,
+ ),
+ )
+ }
+ _ => unreachable!(),
+ };
+
+ match f {
+ Some(mut file) => file.write($out)?,
+ None => 0,
+ };
+
+ match f2 {
+ Some(mut file) => file.write(&err)?,
+ None => 0,
+ };
+ }
+
+ if !output.status.success() {
+ return Ok(output.status.code().unwrap_or(-1));
+ }
+
+ err.clear();
+ if $self.meter != Rune::Couplet {
+ $out.clear();
+ }
+
+ Ok(output.status.code().unwrap_or(0))
+ }};
+}