diff --git a/src/tee/tee.rs b/src/tee/tee.rs index 32f17a64d..5b8bb2e7c 100644 --- a/src/tee/tee.rs +++ b/src/tee/tee.rs @@ -1,5 +1,5 @@ #![crate_name = "tee"] -#![feature(collections, core, old_io, old_path, rustc_private)] +#![feature(rustc_private)] /* * This file is part of the uutils coreutils package. @@ -13,16 +13,16 @@ extern crate getopts; #[macro_use] extern crate log; -use std::old_io::{println, stdin, stdout, Append, File, Truncate, Write}; -use std::old_io::{IoResult}; -use std::old_io::util::{copy, NullWriter, MultiWriter}; +use std::fs::OpenOptions; +use std::io::{copy, Error, ErrorKind, Read, Result, sink, stdin, stdout, Write}; +use std::path::{Path, PathBuf}; use getopts::{getopts, optflag, usage}; static NAME: &'static str = "tee"; static VERSION: &'static str = "1.0.0"; pub fn uumain(args: Vec) -> i32 { - match options(args.as_slice()).and_then(exec) { + match options(&args).and_then(exec) { Ok(_) => 0, Err(_) => 1 } @@ -34,10 +34,10 @@ struct Options { append: bool, ignore_interrupts: bool, print_and_exit: Option, - files: Box> + files: Vec } -fn options(args: &[String]) -> Result { +fn options(args: &Vec) -> Result { let opts = [ optflag("a", "append", "append to the given FILEs, do not overwrite"), optflag("i", "ignore-interrupts", "ignore interrupt signals"), @@ -45,18 +45,16 @@ fn options(args: &[String]) -> Result { optflag("V", "version", "output version information and exit"), ]; - let args: Vec = args.iter().map(|x| x.to_string()).collect(); - - getopts(args.tail(), &opts).map_err(|e| format!("{}", e)).and_then(|m| { + getopts(&args[1..], &opts).map_err(|e| Error::new(ErrorKind::Other, format!("{}", e))).and_then(|m| { let version = format!("{} {}", NAME, VERSION); - let program = args[0].as_slice(); + let program = &args[0][..]; let arguments = "[OPTION]... [FILE]..."; let brief = "Copy standard input to each FILE, and also to standard output."; let comment = "If a FILE is -, copy again to standard output."; let help = format!("{}\n\nUsage:\n {} {}\n\n{}\n{}", version, program, arguments, usage(brief, &opts), comment); - let mut names = m.free.clone().into_iter().collect::>(); + let mut names: Vec = m.free.clone().into_iter().collect(); names.push("-".to_string()); let to_print = if m.opt_present("help") { Some(help) } else if m.opt_present("version") { Some(version) } @@ -66,88 +64,111 @@ fn options(args: &[String]) -> Result { append: m.opt_present("append"), ignore_interrupts: m.opt_present("ignore-interrupts"), print_and_exit: to_print, - files: Box::new(names.iter().map(|name| Path::new(name.clone())).collect()) + files: names }) - }).map_err(|message| warn(message.as_slice())) + }).map_err(|message| warn(format!("{}", message).as_ref())) } -fn exec(options: Options) -> Result<(), ()> { +fn exec(options: Options) -> Result<()> { match options.print_and_exit { - Some(text) => Ok(println(text.as_slice())), + Some(text) => Ok(println!("{}", text)), None => tee(options) } } -fn tee(options: Options) -> Result<(), ()> { - let writers = options.files.iter().map(|path| open(path, options.append)).collect(); - let output = &mut MultiWriter::new(writers); - let input = &mut NamedReader { inner: Box::new(stdin()) as Box }; +fn tee(options: Options) -> Result<()> { + let writers: Vec> = options.files.clone().into_iter().map(|file| open(file, options.append)).collect(); + let output = &mut MultiWriter { writers: writers }; + let input = &mut NamedReader { inner: Box::new(stdin()) as Box }; if copy(input, output).is_err() || output.flush().is_err() { - Err(()) + Err(Error::new(ErrorKind::Other, "")) } else { Ok(()) } } -fn open(path: &Path, append: bool) -> Box { - let inner = if *path == Path::new("-") { - Box::new(stdout()) as Box +fn open(name: String, append: bool) -> Box { + let is_stdout = name == "-"; + let path = PathBuf::from(name); + let inner: Box = if is_stdout { + Box::new(stdout()) } else { - let mode = if append { Append } else { Truncate }; - match File::open_mode(path, mode, Write) { - Ok(file) => Box::new(file) as Box, - Err(_) => Box::new(NullWriter) as Box + let mut options = OpenOptions::new(); + let mode = if append { options.append(true) } else { options.truncate(true) }; + match mode.write(true).create(true).open(path.as_path()) { + Ok(file) => Box::new(file), + Err(_) => Box::new(sink()) } }; - Box::new(NamedWriter { inner: inner, path: Box::new(path.clone()) }) as Box + Box::new(NamedWriter { inner: inner, path: path }) as Box +} + +struct MultiWriter { + writers: Vec> +} + +impl Write for MultiWriter { + fn write(&mut self, buf: &[u8]) -> Result { + for writer in self.writers.iter_mut() { + try!(writer.write_all(buf)); + } + Ok(buf.len()) + } + + fn flush(&mut self) -> Result<()> { + for writer in self.writers.iter_mut() { + try!(writer.flush()); + } + Ok(()) + } } struct NamedWriter { - inner: Box, - path: Box + inner: Box, + path: PathBuf } -impl Writer for NamedWriter { - fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { - with_path(&*self.path.clone(), || { - let val = self.inner.write_all(buf); - if val.is_err() { - self.inner = Box::new(NullWriter) as Box; +impl Write for NamedWriter { + fn write(&mut self, buf: &[u8]) -> Result { + match self.inner.write(buf) { + Err(f) => { + self.inner = Box::new(sink()) as Box; + warn(format!("{}: {}", self.path.display(), f.to_string()).as_ref()); + Err(f) } - val - }) + okay => okay + } } - fn flush(&mut self) -> IoResult<()> { - with_path(&*self.path.clone(), || { - let val = self.inner.flush(); - if val.is_err() { - self.inner = Box::new(NullWriter) as Box; + fn flush(&mut self) -> Result<()> { + match self.inner.flush() { + Err(f) => { + self.inner = Box::new(sink()) as Box; + warn(format!("{}: {}", self.path.display(), f.to_string()).as_ref()); + Err(f) } - val - }) + okay => okay + } } } struct NamedReader { - inner: Box + inner: Box } -impl Reader for NamedReader { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - with_path(&Path::new("stdin"), || { - self.inner.read(buf) - }) +impl Read for NamedReader { + fn read(&mut self, buf: &mut [u8]) -> Result { + match self.inner.read(buf) { + Err(f) => { + warn(format!("{}: {}", Path::new("stdin").display(), f.to_string()).as_ref()); + Err(f) + } + okay => okay + } } } -fn with_path(path: &Path, mut cb: F) -> IoResult where F: FnMut() -> IoResult { - match cb() { - Err(f) => { warn(format!("{}: {}", path.display(), f.to_string()).as_slice()); Err(f) } - okay => okay - } -} - -fn warn(message: &str) { +fn warn(message: &str) -> Error { error!("tee: {}", message); + Error::new(ErrorKind::Other, format!("tee: {}", message)) }