shell pipe function prototype finished
This commit is contained in:
parent
9c0f88ec91
commit
e5f81ad604
2 changed files with 67 additions and 22 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
true
|
let pid = child.id();
|
||||||
|
lastpid = pid;
|
||||||
|
state.children.push(child);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
err = format!("failed to spawn: {}", chld_spwn.err().unwrap());
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
eprintln!("file not found");
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue