shell pipe function prototype finished

This commit is contained in:
Ava Apples Affine 2023-04-07 12:21:22 -07:00
parent 9c0f88ec91
commit e5f81ad604
Signed by: affine
GPG key ID: 3A4645B8CF806069
2 changed files with 67 additions and 22 deletions

View file

@ -483,7 +483,6 @@ Note: this section only tracks the state of incomplete TODO items. Having everyt
** TODO Pre-alpha tasks ** TODO Pre-alpha tasks
- Shell module - Shell module
- pipe control flow construct
- ignore job control signals (if needed) - ignore job control signals (if needed)
- background processes - background processes
- be able to list all background processes with j function - be able to list all background processes with j function

View file

@ -172,48 +172,79 @@ Each one has their output redirected to the input of the next one.
Example: Example:
(pipe (pipe
(ls -la) (ls -la)
(grep '*.rs') (grep '.rs')
(tr -d '.rs'))"; (tr -d '.rs'))";
fn pipe_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellState) -> Result<Ctr, String> { fn pipe_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellState) -> Result<Ctr, String> {
if ast.is_empty() { if ast.is_empty() {
return Err("need at least one argument".to_string()) 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 !ast.circuit(&mut |arg: &Ctr| -> bool {
if let Ctr::Seg(command_form) = arg { 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() { if args.is_empty() {
return false return false
} }
if let Some(filepath) = run::find_on_path(args.pop_front().unwrap()) { if let Some(filepath) = run::find_on_path(args.pop_front().unwrap()) {
let tmp = Stdio::piped(); let mut newchld = Command::new(filepath);
// TODO Youll just have to break open launch_command here newchld.args(Vec::from(args.make_contiguous()))
// youll need seperate calls for .stdin and .stdout anyways .stderr(Stdio::inherit())
// and also the move semantics are not working .stdout(Stdio::piped());
launch_command(
filepath, if let Some(pos) = state.children
&Vec::from(args.make_contiguous()), .iter()
input, .position(|x| x.id() == lastpid)
Stdio::inherit(), {
tmp, newchld.stdin(state.children.remove(pos).stdout.unwrap());
false, }
state,
).unwrap(); let chld_spwn = newchld.spawn();
input = tmp; if let Ok(child) = chld_spwn {
let pid = child.id();
lastpid = pid;
state.children.push(child);
true true
} else { } else {
eprintln!("file not found"); err = format!("failed to spawn: {}", chld_spwn.err().unwrap());
false
}
} else {
err = "file not found".to_string();
false false
} }
} else { } else {
err = format!("{} not a shell command", arg);
false false
} }
}) { }) {
Err("all arguments must be full shell commands".to_string()) Err(err)
} else { } 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<RefCell<ShellState>
let q_ss = shell_state.clone(); let q_ss = shell_state.clone();
let lw_ss = shell_state.clone(); let lw_ss = shell_state.clone();
let lts_ss = shell_state.clone(); let lts_ss = shell_state.clone();
let p_ss = shell_state.clone();
syms.insert( syms.insert(
String::from("l"), String::from("l"),
@ -543,6 +575,20 @@ pub fn load_posix_shell(syms: &mut SymTable, shell_state: Rc<RefCell<ShellState>
}, },
); );
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<Ctr, String> {
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")) { if let Err(e) = ctrlc::set_handler(move || println!("POSIX layer caught SIG-something")) {
eprintln!("WARNING: couldn't set sig handler: {}", e); eprintln!("WARNING: couldn't set sig handler: {}", e);
} }