implemented load-with.... still need docstring and to fix some write errors

This commit is contained in:
Ava Apples Affine 2023-03-28 20:47:55 -07:00
parent ab14ba4b5e
commit e8cf59b7a7
Signed by: affine
GPG key ID: 3A4645B8CF806069
2 changed files with 156 additions and 16 deletions

View file

@ -22,6 +22,7 @@ use crate::run;
use std::collections::VecDeque;
use std::cell::RefCell;
use std::rc::Rc;
use std::fs::File;
use std::process::{Command, Child, Stdio};
use nix::unistd;
use ctrlc;
@ -137,26 +138,148 @@ examples:
(l ping -c ping-count google.com))
(l emacs -nw (concat HOME '/.relishrc'))
";
fn load_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellState) -> Result<Ctr, String> {
if ast.is_empty() {
Err("need at least one argument".to_string())
} else {
let mut args = VecDeque::from(args_from_ast(ast, syms));
if let Some(filepath) = run::find_on_path(args.pop_front().unwrap()) {
launch_command(
filepath,
&Vec::from(args.make_contiguous()),
Stdio::inherit(),
Stdio::inherit(),
Stdio::inherit(),
false,
state,
)?;
Ok(Ctr::Integer(state.last_exit_code.into()))
if args.is_empty() {
Err("empty command".to_string())
} else {
Err("file not found".to_string())
if let Some(filepath) = run::find_on_path(args.pop_front().unwrap()) {
launch_command(
filepath,
&Vec::from(args.make_contiguous()),
Stdio::inherit(),
Stdio::inherit(),
Stdio::inherit(),
false,
state,
)?;
Ok(Ctr::Integer(state.last_exit_code.into()))
} else {
Err("file not found".to_string())
}
}
}
}
// TODO: rework this callback to reduce spaghett
const LOAD_WITH_DOCSTRING: &str = "";
fn load_with_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellState) -> Result<Ctr, String> {
if ast.len() != 2 {
Err("exactly two arguments needed".to_string())
} else {
if let Ctr::Seg(ref fd_redirect_forms) = *ast.car {
let mut stdout: Option<Stdio> = None;
let mut stdin: Option<Stdio> = None;
let mut stderr: Option<Stdio> = None;
let mut e: Option<String> = None;
if !fd_redirect_forms.circuit(&mut |arg: &Ctr| -> bool {
// of the form Seg(Str(fd), Seg(Str(filepath)))
if let Ctr::Seg(ref io_redir) = arg {
if let Ctr::String(ref fd) = *io_redir.car {
if let Ctr::Seg(ref io_file) = *io_redir.cdr {
if let Ctr::String(ref filename) = *io_file.car {
match fd.as_str() {
"stdin" => {
if !stdin.is_none() {
e = Some(format!("stdin already defined"));
return false
}
let input = File::open(filename);
if !input.is_ok() {
e = Some(format!("input file does not exist"));
return false
}
stdin = Some(Stdio::from(input.ok().unwrap()));
return true
},
"stdout" => {
if !stdout.is_none() {
e = Some(format!("stdout already defined"));
return false
}
let out = File::open(filename).or(File::create(filename));
if !out.is_ok() {
e = Some(out.unwrap_err().to_string());
return false
}
stdout = Some(Stdio::from(out.ok().unwrap()));
return true
},
"stderr" => {
if !stderr.is_none() {
e = Some(format!("stderr already defined"));
return false
}
let err = File::open(filename).or(File::create(filename));
if !err.is_ok() {
e = Some(err.unwrap_err().to_string());
return false
}
stderr = Some(Stdio::from(err.ok().unwrap()));
return true
},
_ => {
e = Some(format!("can only override stdin, stdout, or stderr"));
false
}
}
} else {
e = Some(format!("{} is not a string", *io_file.car));
false
}
} else {
e = Some(format!("fd override must have both an fd and a filename"));
false
}
} else {
e = Some(format!("{} is not a string", *io_redir.car));
false
}
} else {
e = Some(format!("not a list: {}", arg));
false
}
}) {
return Err(e.unwrap())
}
// now deal with the actual command
if let Ctr::Seg(ref command_forms) = *ast.cdr {
let mut args: VecDeque<String>;
if let Ctr::Seg(ref command) = *command_forms.car {
args = VecDeque::from(args_from_ast(command, syms));
} else {
return Err("command not list".to_string())
}
if args.is_empty() {
Err("empty command".to_string())
} else {
if let Some(filepath) = run::find_on_path(args.pop_front().unwrap()) {
launch_command(
filepath,
&Vec::from(args.make_contiguous()),
stdin.or(Some(Stdio::inherit())).unwrap(),
stdout.or(Some(Stdio::inherit())).unwrap(),
stderr.or(Some(Stdio::inherit())).unwrap(),
false,
state,
)?;
Ok(Ctr::Integer(state.last_exit_code.into()))
} else {
Err("file not found".to_string())
}
}
} else {
Err("second argument expected to be a list of command elements".to_string())
}
} else {
Err("first argument expected to be a list of lists".to_string())
}
}
}
@ -215,6 +338,7 @@ pub fn load_posix_shell(syms: &mut SymTable, shell_state: Rc<RefCell<ShellState>
let load_ss = shell_state.clone();
let bg_ss = shell_state.clone();
let q_ss = shell_state.clone();
let lw_ss = shell_state.clone();
syms.insert(
String::from("l"),
@ -272,6 +396,21 @@ pub fn load_posix_shell(syms: &mut SymTable, shell_state: Rc<RefCell<ShellState>
},
);
syms.insert(
String::from("load-with"),
Symbol {
name: String::from("load-with"),
args: Args::Lazy(2),
conditional_branches: true,
docs: String::from(LOAD_WITH_DOCSTRING),
value: ValueType::Internal(Rc::new(move |ast: &Seg, symtable: &mut SymTable| -> Result<Ctr, String> {
load_with_callback(ast, symtable, &mut lw_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);
}