use std::io::Write;
use std::path::Path;
use crate::builtins::{take_flags, usage_error};
use crate::interp::Flow;
use crate::io::{CommandIo, OutTarget};
pub(crate) fn echo(args: &[String], stdout: OutTarget) -> Flow {
let (suppress_newline, rest) = match args.first() {
Some(first) if first == "-n" => (true, &args[1..]),
_ => (false, args),
};
let mut writer = stdout.writer();
let text = rest.join(" ");
if suppress_newline {
let _ = write!(writer, "{text}");
} else {
let _ = writeln!(writer, "{text}");
}
Flow::Next(0)
}
pub(crate) fn cat(args: &[String], cwd: &Path, io: CommandIo) -> Flow {
let CommandIo {
stdin,
stdout,
stderr,
} = io;
let rest = match take_flags(args, &[]) {
Ok((_, rest)) => rest,
Err(flag) => return usage_error(stderr, format_args!("cat: invalid option: {flag}")),
};
let mut out = stdout.writer();
if rest.is_empty() {
let mut input = stdin.reader();
let _ = std::io::copy(&mut input, &mut out);
return Flow::Next(0);
}
drop(stdin);
let mut err = stderr.writer();
let mut failed = false;
for arg in rest {
match std::fs::File::open(cwd.join(arg)) {
Ok(mut file) => {
if let Err(error) = std::io::copy(&mut file, &mut out) {
failed = true;
let _ = writeln!(err, "cat: {arg}: {error}");
}
}
Err(_) => {
failed = true;
let _ = writeln!(err, "cat: {arg}: no such file");
}
}
}
Flow::Next(if failed { 1 } else { 0 })
}