use std::collections::HashMap;
use std::io::{self, Read, Write};
use crate::core;
use crate::parsers;
use crate::shell::{self, Shell};
use crate::types::{drain_env_tokens, CommandLine, CommandResult, Tokens};
pub fn run_procs_for_non_tty(sh: &mut Shell) {
let mut buffer = String::new();
let stdin = io::stdin();
let mut handle = stdin.lock();
match handle.read_to_string(&mut buffer) {
Ok(_) => {
log!("run non tty command: {}", &buffer);
run_command_line(sh, &buffer, false, false);
}
Err(e) => {
println!("cicada: stdin.read_to_string() failed: {:?}", e);
}
}
}
pub fn run_command_line(
sh: &mut Shell,
line: &str,
tty: bool,
capture: bool,
) -> Vec<CommandResult> {
let mut cr_list = Vec::new();
let mut status = 0;
let mut sep = String::new();
for token in parsers::parser_line::line_to_cmds(line) {
if token == ";" || token == "&&" || token == "||" {
sep = token.clone();
continue;
}
if sep == "&&" && status != 0 {
break;
}
if sep == "||" && status == 0 {
break;
}
let cmd = token.clone();
let cr = run_proc(sh, &cmd, tty, capture);
status = cr.status;
sh.previous_status = status;
cr_list.push(cr);
}
cr_list
}
fn line_to_tokens(sh: &mut Shell, line: &str) -> (Tokens, HashMap<String, String>) {
let linfo = parsers::parser_line::parse_line(line);
let mut tokens = linfo.tokens;
shell::do_expansion(sh, &mut tokens);
let envs = drain_env_tokens(&mut tokens);
(tokens, envs)
}
fn set_shell_vars(sh: &mut Shell, envs: &HashMap<String, String>) {
for (name, value) in envs.iter() {
sh.set_env(name, value);
}
}
fn run_proc(sh: &mut Shell, line: &str, tty: bool, capture: bool) -> CommandResult {
let log_cmd = !sh.cmd.starts_with(' ');
match CommandLine::from_line(line, sh) {
Ok(cl) => {
if cl.is_empty() {
if !cl.envs.is_empty() {
set_shell_vars(sh, &cl.envs);
}
return CommandResult::new();
}
let (term_given, cr) = core::run_pipeline(sh, &cl, tty, capture, log_cmd);
if term_given {
unsafe {
let gid = libc::getpgid(0);
shell::give_terminal_to(gid);
}
}
cr
}
Err(e) => {
println_stderr!("cicada: {}", e);
CommandResult::from_status(0, 1)
}
}
}
fn run_with_shell(sh: &mut Shell, line: &str) -> CommandResult {
let (tokens, envs) = line_to_tokens(sh, line);
if tokens.is_empty() {
set_shell_vars(sh, &envs);
return CommandResult::new();
}
match CommandLine::from_line(line, sh) {
Ok(c) => {
let (term_given, cr) = core::run_pipeline(sh, &c, false, true, false);
if term_given {
unsafe {
let gid = libc::getpgid(0);
shell::give_terminal_to(gid);
}
}
cr
}
Err(e) => {
println_stderr!("cicada: {}", e);
CommandResult::from_status(0, 1)
}
}
}
pub fn run(line: &str) -> CommandResult {
let mut sh = Shell::new();
run_with_shell(&mut sh, line)
}
#[cfg(test)]
mod tests {
use super::core::run_calculator;
use super::run_with_shell;
use super::shell;
use crate::libs;
#[test]
fn test_run_calculator() {
assert_eq!(
run_calculator("(1 + 2 * 3.0 - 1.5) / 0.2"),
Ok("27.5".to_string())
);
assert_eq!(run_calculator("(5 + 2 * 3 - 4) / 3"), Ok("2".to_string()));
assert_eq!(
run_calculator("((2 ^ 35) + (3^7) - 9740555) / 10000000"),
Ok("3435".to_string())
);
}
#[test]
fn test_run_itself() {
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
let f = File::open("./tests/run_procs.txt").expect("file not found");
let file = BufReader::new(&f);
let mut input = String::new();
let mut expected_stdout = String::new();
let mut sh = shell::Shell::new();
for (num, l) in file.lines().enumerate() {
let line = l.unwrap();
match num % 3 {
0 => {
input = line.clone();
}
1 => {
expected_stdout = line.clone();
}
2 => match run_with_shell(&mut sh, &input) {
cr => {
let ptn = if expected_stdout.is_empty() {
r"^$"
} else {
expected_stdout.as_str()
};
let matched = libs::re::re_contains(&cr.stdout.trim(), &ptn);
if !matched {
println!("\nSTDOUT Check Failed:");
println!("input: {}", &input);
println!("stdout: {:?}", &cr.stdout.trim());
println!("expected: {:?}", &expected_stdout);
println!("line number: {}\n", num);
}
assert!(matched);
let ptn = if line.is_empty() {
r"^$"
} else {
line.as_str()
};
let matched = libs::re::re_contains(&cr.stderr.trim(), &ptn);
if !matched {
println!("\nSTDERR Check Failed:");
println!("input: {}", &input);
println!("stderr: {:?}", &cr.stderr);
println!("expected: {}", &ptn);
println!("line number: {}\n", num + 1);
}
assert!(matched);
}
},
_ => {
assert!(false);
}
}
}
}
}