From e5f81ad604d09aac0e0bfdfb138928edf9c112d4 Mon Sep 17 00:00:00 2001 From: Ava Hahn Date: Fri, 7 Apr 2023 12:21:22 -0700 Subject: [PATCH] shell pipe function prototype finished --- Readme.org | 1 - src/stl/posix.rs | 88 ++++++++++++++++++++++++++++++++++++------------ 2 files changed, 67 insertions(+), 22 deletions(-) diff --git a/Readme.org b/Readme.org index d843061..345ec56 100644 --- a/Readme.org +++ b/Readme.org @@ -483,7 +483,6 @@ Note: this section only tracks the state of incomplete TODO items. Having everyt ** TODO Pre-alpha tasks - Shell module - - pipe control flow construct - ignore job control signals (if needed) - background processes - be able to list all background processes with j function diff --git a/src/stl/posix.rs b/src/stl/posix.rs index 470fd6f..d428846 100644 --- a/src/stl/posix.rs +++ b/src/stl/posix.rs @@ -172,48 +172,79 @@ Each one has their output redirected to the input of the next one. Example: (pipe (ls -la) - (grep '*.rs') + (grep '.rs') (tr -d '.rs'))"; fn pipe_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellState) -> Result { if ast.is_empty() { return Err("need at least one argument".to_string()) } - let mut input = Stdio::inherit(); + let mut err: String = String::new(); + // posix layer will never control pid 0 + let mut lastpid = 0; if !ast.circuit(&mut |arg: &Ctr| -> bool { if let Ctr::Seg(command_form) = arg { - let args = VecDeque::from(args_from_ast(ast, syms)); + let mut args = VecDeque::from(args_from_ast(command_form, syms)); if args.is_empty() { return false } if let Some(filepath) = run::find_on_path(args.pop_front().unwrap()) { - let tmp = Stdio::piped(); - // TODO Youll just have to break open launch_command here - // youll need seperate calls for .stdin and .stdout anyways - // and also the move semantics are not working - launch_command( - filepath, - &Vec::from(args.make_contiguous()), - input, - Stdio::inherit(), - tmp, - false, - state, - ).unwrap(); - input = tmp; - true + let mut newchld = Command::new(filepath); + newchld.args(Vec::from(args.make_contiguous())) + .stderr(Stdio::inherit()) + .stdout(Stdio::piped()); + + if let Some(pos) = state.children + .iter() + .position(|x| x.id() == lastpid) + { + newchld.stdin(state.children.remove(pos).stdout.unwrap()); + } + + let chld_spwn = newchld.spawn(); + if let Ok(child) = chld_spwn { + let pid = child.id(); + lastpid = pid; + state.children.push(child); + true + } else { + err = format!("failed to spawn: {}", chld_spwn.err().unwrap()); + false + } + } else { - eprintln!("file not found"); + err = "file not found".to_string(); false } } else { + err = format!("{} not a shell command", arg); false } }) { - Err("all arguments must be full shell commands".to_string()) + Err(err) } else { - Ok(Ctr::None) + if lastpid > 0 { + if let Some(pos) = state.children + .iter() + .position(|x| x.id() == lastpid) + { + let chld = state.children.remove(pos); + let exit = chld.wait_with_output() + .expect("failed to wait on last child"); + state.last_exit_code = exit.status + .code() + .or_else(|| {Some(-1)}) + .unwrap(); + + println!("{}", String::from_utf8_lossy(&exit.stdout)); + Ok(Ctr::Integer(state.last_exit_code.into())) + } else { + Err(format!("lost last child (pid {})", lastpid)) + } + } else { + Err("impossible error state".to_string()) + } } } @@ -458,6 +489,7 @@ pub fn load_posix_shell(syms: &mut SymTable, shell_state: Rc let q_ss = shell_state.clone(); let lw_ss = shell_state.clone(); let lts_ss = shell_state.clone(); + let p_ss = shell_state.clone(); syms.insert( String::from("l"), @@ -543,6 +575,20 @@ pub fn load_posix_shell(syms: &mut SymTable, shell_state: Rc }, ); + syms.insert( + String::from("pipe"), + Symbol { + name: String::from("pipe"), + args: Args::Infinite, + conditional_branches: true, + docs: String::from(PIPE_DOCSTRING), + value: ValueType::Internal(Rc::new(move |ast: &Seg, symtable: &mut SymTable| -> Result { + pipe_callback(ast, symtable, &mut p_ss.clone().borrow_mut()) + })), + ..Default::default() + }, + ); + if let Err(e) = ctrlc::set_handler(move || println!("POSIX layer caught SIG-something")) { eprintln!("WARNING: couldn't set sig handler: {}", e); }