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
- Shell module
- pipe control flow construct
- ignore job control signals (if needed)
- background processes
- 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:
(pipe
(ls -la)
(grep '*.rs')
(grep '.rs')
(tr -d '.rs'))";
fn pipe_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellState) -> Result<Ctr, String> {
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<RefCell<ShellState>
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<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")) {
eprintln!("WARNING: couldn't set sig handler: {}", e);
}