Implemented assignments, working on job control
This commit is contained in:
104
src/procio.rs
104
src/procio.rs
@@ -1,6 +1,6 @@
|
||||
use std::{fmt::Debug, ops::{Deref, DerefMut}};
|
||||
|
||||
use crate::{libsh::error::ShResult, parse::Redir, prelude::*};
|
||||
use crate::{libsh::error::ShResult, parse::{Redir, RedirType}, prelude::*};
|
||||
|
||||
// Credit to fish-shell for many of the implementation ideas present in this module
|
||||
// https://fishshell.com/
|
||||
@@ -46,6 +46,8 @@ impl Debug for Box<dyn IoInfo> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A redirection to a raw fildesc
|
||||
/// e.g. `2>&1`
|
||||
#[derive(Debug)]
|
||||
pub struct IoFd {
|
||||
tgt_fd: RawFd,
|
||||
@@ -81,6 +83,8 @@ impl IoInfo for IoFd {
|
||||
}
|
||||
}
|
||||
|
||||
/// A redirection to a file
|
||||
/// e.g. `> file.txt`
|
||||
#[derive(Debug)]
|
||||
pub struct IoFile {
|
||||
tgt_fd: RawFd,
|
||||
@@ -112,6 +116,8 @@ impl IoInfo for IoFile {
|
||||
}
|
||||
}
|
||||
|
||||
/// A redirection to a pipe
|
||||
/// e.g. `echo foo | sed s/foo/bar/`
|
||||
#[derive(Debug)]
|
||||
pub struct IoPipe {
|
||||
tgt_fd: RawFd,
|
||||
@@ -150,9 +156,32 @@ impl IoInfo for IoPipe {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FdWriter {
|
||||
tgt: OwnedFd
|
||||
}
|
||||
|
||||
impl FdWriter {
|
||||
pub fn new(fd: i32) -> Self {
|
||||
let tgt = unsafe { OwnedFd::from_raw_fd(fd) };
|
||||
Self { tgt }
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for FdWriter {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
Ok(write(&self.tgt, buf)?)
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A struct wrapping three fildescs representing `stdin`, `stdout`, and `stderr` respectively
|
||||
#[derive(Debug)]
|
||||
pub struct IoGroup(OwnedFd,OwnedFd,OwnedFd);
|
||||
|
||||
/// A single stack frame used with the IoStack
|
||||
/// Each stack frame represents the redirections of a single command
|
||||
#[derive(Default,Debug)]
|
||||
pub struct IoFrame {
|
||||
redirs: Vec<Redir>,
|
||||
@@ -163,6 +192,42 @@ impl<'e> IoFrame {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
pub fn from_redirs(redirs: Vec<Redir>) -> Self {
|
||||
Self { redirs, saved_io: None }
|
||||
}
|
||||
|
||||
/// This method returns a 2-tuple of `IoFrames`.
|
||||
/// This is to be used in the case of shell structures such as `if-then` and `while-do`.
|
||||
/// # Params
|
||||
/// * redirs: a vector of redirections
|
||||
///
|
||||
/// # Returns
|
||||
/// * An `IoFrame` containing all of the redirections which target stdin
|
||||
/// * An `IoFrame` containing all of the redirections which target stdout/stderr
|
||||
///
|
||||
/// # Purpose
|
||||
/// In the case of something like `if cat; then echo foo; fi < input.txt > output.txt`
|
||||
/// This will cleanly separate the redirections such that `cat` can receive the input from input.txt
|
||||
/// and `echo foo` can redirect it's output to output.txt
|
||||
pub fn cond_and_body(redirs: Vec<Redir>) -> (Self, Self) {
|
||||
let mut output_redirs = vec![];
|
||||
let mut input_redirs = vec![];
|
||||
for redir in redirs {
|
||||
match redir.class {
|
||||
RedirType::Input => input_redirs.push(redir),
|
||||
RedirType::Pipe => {
|
||||
match redir.io_info.tgt_fd() {
|
||||
STDIN_FILENO => input_redirs.push(redir),
|
||||
STDOUT_FILENO |
|
||||
STDERR_FILENO => output_redirs.push(redir),
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
_ => output_redirs.push(redir)
|
||||
}
|
||||
}
|
||||
(Self::from_redirs(input_redirs),Self::from_redirs(output_redirs))
|
||||
}
|
||||
pub fn save(&'e mut self) {
|
||||
unsafe {
|
||||
let saved_in = OwnedFd::from_raw_fd(dup(STDIN_FILENO).unwrap());
|
||||
@@ -171,7 +236,7 @@ impl<'e> IoFrame {
|
||||
self.saved_io = Some(IoGroup(saved_in,saved_out,saved_err));
|
||||
}
|
||||
}
|
||||
pub fn redirect(&'e mut self) -> ShResult<'e,()> {
|
||||
pub fn redirect(&mut self) -> ShResult<()> {
|
||||
self.save();
|
||||
for redir in &mut self.redirs {
|
||||
let io_info = &mut redir.io_info;
|
||||
@@ -182,12 +247,11 @@ impl<'e> IoFrame {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn restore(&'e mut self) -> ShResult<'e,()> {
|
||||
pub fn restore(&mut self) -> ShResult<()> {
|
||||
while let Some(mut redir) = self.pop() {
|
||||
redir.io_info.close().ok();
|
||||
redir.io_info.close()?;
|
||||
}
|
||||
if let Some(saved) = self.saved_io.take() {
|
||||
dbg!(&saved);
|
||||
dup2(saved.0.as_raw_fd(), STDIN_FILENO)?;
|
||||
dup2(saved.1.as_raw_fd(), STDOUT_FILENO)?;
|
||||
dup2(saved.2.as_raw_fd(), STDERR_FILENO)?;
|
||||
@@ -209,6 +273,12 @@ impl DerefMut for IoFrame {
|
||||
}
|
||||
}
|
||||
|
||||
/// A stack that maintains the current state of I/O for commands
|
||||
///
|
||||
/// This struct maintains the current state of I/O for the `Dispatcher` struct
|
||||
/// Each executed command requires an `IoFrame` in order to perform redirections.
|
||||
/// As nodes are walked through by the `Dispatcher`, it pushes new frames in certain contexts, and pops frames in others.
|
||||
/// Each command calls pop_frame() in order to get the current IoFrame in order to perform redirection
|
||||
#[derive(Default)]
|
||||
pub struct IoStack {
|
||||
stack: Vec<IoFrame>,
|
||||
@@ -229,13 +299,31 @@ impl<'e> IoStack {
|
||||
pub fn push_to_frame(&mut self, redir: Redir) {
|
||||
self.curr_frame_mut().push(redir)
|
||||
}
|
||||
/// Pop the current stack frame
|
||||
/// This differs from using `pop()` because it always returns a stack frame
|
||||
/// If `self.pop()` would empty the `IoStack`, it instead uses `std::mem::take()` to take the last frame
|
||||
/// There will always be at least one frame in the `IoStack`.
|
||||
pub fn pop_frame(&mut self) -> IoFrame {
|
||||
if self.stack.len() > 1 {
|
||||
self.stack.pop().unwrap()
|
||||
self.pop().unwrap()
|
||||
} else {
|
||||
std::mem::take(self.curr_frame_mut())
|
||||
}
|
||||
}
|
||||
/// Push a new stack frame.
|
||||
pub fn push_frame(&mut self, frame: IoFrame) {
|
||||
self.push(frame)
|
||||
}
|
||||
/// Flatten the `IoStack`
|
||||
/// All of the current stack frames will be flattened into a single one
|
||||
/// Not sure what use this will serve, but my gut said this was worthy of writing
|
||||
pub fn flatten(&mut self) {
|
||||
let mut flat_frame = IoFrame::new();
|
||||
while let Some(mut frame) = self.pop() {
|
||||
flat_frame.append(&mut frame)
|
||||
}
|
||||
self.push(flat_frame);
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for IoStack {
|
||||
@@ -250,3 +338,7 @@ impl DerefMut for IoStack {
|
||||
&mut self.stack
|
||||
}
|
||||
}
|
||||
|
||||
pub fn borrow_fd<'f>(fd: i32) -> BorrowedFd<'f> {
|
||||
unsafe { BorrowedFd::borrow_raw(fd) }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user