use std::fs::File;
use std::io::Write;
use std::os::unix::io::{FromRawFd, RawFd};
use errno::errno;
use crate::tools;
use crate::types::{Command, CommandLine, CommandResult, Redirection};
fn _get_std_fds(redirects: &[Redirection]) -> (Option<RawFd>, Option<RawFd>) {
if redirects.is_empty() {
return (None, None);
}
let mut fd_out = None;
let mut fd_err = None;
for i in 0..redirects.len() {
let item = &redirects[i];
if item.0 == "1" {
let mut _fd_candidate = None;
if item.2 == "&2" {
let (_fd_out, _fd_err) = _get_std_fds(&redirects[i + 1..]);
if let Some(fd) = _fd_err {
_fd_candidate = Some(fd);
} else {
_fd_candidate = unsafe { Some(libc::dup(2)) };
}
} else {
let append = item.1 == ">>";
if let Ok(fd) = tools::create_raw_fd_from_file(&item.2, append) {
_fd_candidate = Some(fd);
}
}
if let Some(fd) = fd_out {
unsafe {
libc::close(fd);
}
}
fd_out = _fd_candidate;
}
if item.0 == "2" {
let mut _fd_candidate = None;
if item.2 == "&1" {
if let Some(fd) = fd_out {
_fd_candidate = unsafe { Some(libc::dup(fd)) };
}
} else {
let append = item.1 == ">>";
if let Ok(fd) = tools::create_raw_fd_from_file(&item.2, append) {
_fd_candidate = Some(fd);
}
}
if let Some(fd) = fd_err {
unsafe {
libc::close(fd);
}
}
fd_err = _fd_candidate;
}
}
(fd_out, fd_err)
}
fn _get_dupped_stdout_fd(cmd: &Command, cl: &CommandLine) -> RawFd {
if cl.with_pipeline() {
return 1;
}
let (_fd_out, _fd_err) = _get_std_fds(&cmd.redirects_to);
if let Some(fd) = _fd_err {
unsafe {
libc::close(fd);
}
}
if let Some(fd) = _fd_out {
fd
} else {
let fd = unsafe { libc::dup(1) };
if fd == -1 {
let eno = errno();
println_stderr!("cicada: dup: {}", eno);
}
fd
}
}
fn _get_dupped_stderr_fd(cmd: &Command, cl: &CommandLine) -> RawFd {
if cl.with_pipeline() {
return 2;
}
let (_fd_out, _fd_err) = _get_std_fds(&cmd.redirects_to);
if let Some(fd) = _fd_out {
unsafe {
libc::close(fd);
}
}
if let Some(fd) = _fd_err {
fd
} else {
let fd = unsafe { libc::dup(2) };
if fd == -1 {
let eno = errno();
println_stderr!("cicada: dup: {}", eno);
}
fd
}
}
pub fn print_stdout(info: &str, cmd: &Command, cl: &CommandLine) {
let fd = _get_dupped_stdout_fd(cmd, cl);
if fd == -1 {
return;
}
unsafe {
let mut f = File::from_raw_fd(fd);
let info = info.trim_end_matches('\n');
match f.write_all(info.as_bytes()) {
Ok(_) => {}
Err(e) => {
println_stderr!("write_all: error: {}", e);
}
}
if !info.is_empty() {
match f.write_all(b"\n") {
Ok(_) => {}
Err(e) => {
println_stderr!("write_all: error: {}", e);
}
}
}
}
}
pub fn print_stderr(info: &str, cmd: &Command, cl: &CommandLine) {
let fd = _get_dupped_stderr_fd(cmd, cl);
if fd == -1 {
return;
}
unsafe {
let mut f = File::from_raw_fd(fd);
let info = info.trim_end_matches('\n');
match f.write_all(info.as_bytes()) {
Ok(_) => (),
Err(e) => {
println_stderr!("write_all: error: {}", e);
}
}
if !info.is_empty() {
match f.write_all(b"\n") {
Ok(_) => (),
Err(e) => {
println_stderr!("write_all: error: {}", e);
}
}
}
}
}
pub fn print_stderr_with_capture(
info: &str,
cr: &mut CommandResult,
cl: &CommandLine,
cmd: &Command,
capture: bool,
) {
cr.status = 1;
if capture {
cr.stderr = info.to_string();
} else {
print_stderr(info, cmd, cl);
}
}
pub fn print_stdout_with_capture(
info: &str,
cr: &mut CommandResult,
cl: &CommandLine,
cmd: &Command,
capture: bool,
) {
cr.status = 0;
if capture {
cr.stdout = info.to_string();
} else {
print_stdout(info, cmd, cl);
}
}