From c4cd1e2c165c4f34ebf67fa9350f8732b2aeca13 Mon Sep 17 00:00:00 2001 From: Rory Dudley Date: Tue, 4 Jun 2024 16:25:32 -0600 Subject: Updated the way built-in commands are called/used Previously, built-in commands were fairly primitive, merely outputting STDOUT and STDERR with the print! macros. However, we need them to behave like normal programs, that is: - Acknowledge their verse's meter (forking, piping, etc.), - Ability to capture STDOUT and STDERR (>, 2>), - and Affect the currently running environment. For these reasons, the anthology was reworked, and now contains the Anthology struct, which mimics both std::process::{Child, Command}. The AnthologyStdin helper struct was also created, for built-ins to take input on STDIN, though no built-in is currently using it. Each built-ins' incant functions were updated to return a std::process::Output. It contains output from STDOUT, output from STDERR, and the exit code of the "process". A fix was also implemented for aliases, where the STDOUT and STDERR vectors were not being copied to the newly constructed verse. --- src/poem/anthology/which.rs | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) (limited to 'src/poem/anthology/which.rs') diff --git a/src/poem/anthology/which.rs b/src/poem/anthology/which.rs index 515b52e..6fe709c 100644 --- a/src/poem/anthology/which.rs +++ b/src/poem/anthology/which.rs @@ -1,16 +1,20 @@ use crate::compose::Environment; use crate::poem::Verse; +use std::os::unix::process::ExitStatusExt; +use std::process::{ExitStatus, Output}; -pub fn incant(verse: &Verse, out: &mut Vec, env: &Environment) -> i32 { +pub fn incant(clause: &Option>, uout: bool, uerr: bool, env: &Environment) -> Output { let mut status = 0; - match verse.clause() { + let mut out: Vec = Vec::new(); + let mut err: Vec = Vec::new(); + match clause { Some(clause) => { let mut output: String; for word in clause { // Check if it's an alias - if env.aliases.contains_key(&word) { - output = format!("{}: aliased to {}\n", word, env.aliases.get(&word).unwrap()); - if verse.couplet > 0 { + if env.aliases.contains_key(word) { + output = format!("{}: aliased to {}\n", word, env.aliases.get(word).unwrap()); + if uout { out.append(&mut output.as_bytes().to_vec()); } else { print!("{}", output); @@ -22,7 +26,7 @@ pub fn incant(verse: &Verse, out: &mut Vec, env: &Environment) -> i32 { match super::lookup(&word) { Some(_) => { output = format!("{}: shell built-in command\n", word); - if verse.couplet > 0 { + if uout { out.append(&mut output.as_bytes().to_vec()); } else { print!("{}", output); @@ -38,7 +42,7 @@ pub fn incant(verse: &Verse, out: &mut Vec, env: &Environment) -> i32 { match verb.spellcheck(&env.bins) { Some(i) => { output = format!("{}\n", env.bins[i]); - if verse.couplet > 0 { + if uout { out.append(&mut output.as_bytes().to_vec()); } else { print!("{}", output); @@ -47,15 +51,33 @@ pub fn incant(verse: &Verse, out: &mut Vec, env: &Environment) -> i32 { None => { output = format!("{} not found\n", word); status = 1; - eprint!("{}", output); + if uerr { + err.append(&mut output.as_bytes().to_vec()); + } else { + eprint!("{}", output); + } } } } } None => { - eprintln!("which: not enough arguments"); - return 1; + status = 1; + if uerr { + err.append(&mut "which: not enough arguments".as_bytes().to_vec()); + } else { + eprintln!("which: not enough arguments"); + } + return Output { + status: ExitStatus::from_raw(status), + stdout: out, + stderr: err, + }; } } - status + + Output { + status: ExitStatus::from_raw(status), + stdout: out, + stderr: err, + } } -- cgit v1.2.3