use std::collections::HashMap;
use std::io::{Error, ErrorKind};
use std::slice::Iter;
use std::iter::Peekable;
use crate::{CmdResult, FunResult};
use crate::sym_table::resolve_name;
use crate::parser;
use crate::process;
#[macro_export]
macro_rules! run_fun {
($($cur:tt)*) => {
$crate::run_fun(
&$crate::source_text!(run_fun),
&$crate::parse_sym_table!($($cur)*),
&file!(),
line!())
};
}
#[macro_export]
macro_rules! run_cmd {
($($cur:tt)*) => {
$crate::run_cmd(
&$crate::source_text!(run_cmd),
&$crate::parse_sym_table!($($cur)*),
&file!(),
line!())
};
}
#[doc(hidden)]
pub fn run_fun(
cmd: &str,
sym_table: &HashMap<String, String>,
file: &str,
line: u32,
) -> FunResult {
let cmds = resolve_name(&cmd, &sym_table, &file, line);
let cmd_argv = parser::parse_cmds(&cmds);
let mut cmd_iter = cmd_argv.iter().peekable();
let mut cmd_env = process::Env::new();
let mut ret = String::new();
while let Some(_) = cmd_iter.peek() {
run_builtin_cmds(&mut cmd_iter, &mut cmd_env)?;
if let Some(cmd) = cmd_iter.next() {
ret = run_pipe::<FunResult>(&cmd)?;
}
}
Ok(ret)
}
#[doc(hidden)]
pub fn run_cmd(
cmd: &str,
sym_table: &HashMap<String, String>,
file: &str,
line: u32,
) -> CmdResult {
let cmds = resolve_name(&cmd, &sym_table, &file, line);
let cmd_argv = parser::parse_cmds(&cmds);
let mut cmd_iter = cmd_argv.iter().peekable();
let mut cmd_env = process::Env::new();
while let Some(_) = cmd_iter.peek() {
run_builtin_cmds(&mut cmd_iter, &mut cmd_env)?;
if let Some(cmd) = cmd_iter.next() {
run_pipe::<CmdResult>(&cmd)?;
}
}
Ok(())
}
fn run_builtin_cmds(cmd_iter: &mut Peekable<Iter<String>>, cmd_env: &mut process::Env) -> CmdResult {
if let Some(cmd) = cmd_iter.peek() {
let mut arg_iter = cmd.split_whitespace();
let arg0 = arg_iter.next().unwrap();
if arg0 == "cd" {
let mut dir = arg_iter.next().unwrap().trim().to_owned();
if arg_iter.next() != None {
let err = Error::new(
ErrorKind::Other,
format!("{} format wrong: {}", arg0, cmd),
);
return Err(err);
}
if !dir.starts_with("/") {
process::ENV_VARS.with(|vars| {
if let Some(cmd_lib_pwd) = vars.borrow().get("PWD") {
dir = format!("{}/{}", cmd_lib_pwd, dir);
} else {
dir = format!("{}/{}", std::env::current_dir().unwrap().to_str().unwrap(), dir);
}
});
}
dir = parser::trim_quotes(&dir);
if !std::path::Path::new(&dir).exists() {
let err_msg = format!("cd: {}: No such file or directory", dir);
eprintln!("{}", err_msg);
let err = Error::new(
ErrorKind::Other,
err_msg,
);
return Err(err);
}
cmd_env.set("PWD".to_string(), dir);
cmd_iter.next();
}
}
Ok(())
}
fn run_pipe<T: process::ProcessResult>(full_command: &str) -> T {
let pipe_argv = parser::parse_pipes(full_command.trim());
let mut last_proc = process::Process::new(pipe_argv[0].clone());
for pipe_cmd in pipe_argv.iter().skip(1) {
last_proc.pipe(pipe_cmd.clone());
}
last_proc.wait::<T>()
}