From fac630d07cd5de4785c74d9a0a3b9d42670bd239 Mon Sep 17 00:00:00 2001 From: Arcterus Date: Fri, 28 Feb 2014 09:19:32 -0800 Subject: [PATCH] Add paste (closes #120) --- Makefile | 1 + paste/paste.rs | 102 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 paste/paste.rs diff --git a/Makefile b/Makefile index ca4309339..991eeb617 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,7 @@ PROGS := \ du \ false \ mkdir \ + paste \ printenv \ pwd \ rm \ diff --git a/paste/paste.rs b/paste/paste.rs new file mode 100644 index 000000000..2809c3d10 --- /dev/null +++ b/paste/paste.rs @@ -0,0 +1,102 @@ +#[crate_id(name = "paste", vers = "1.0.0", author = "Arcterus")]; + +/* + * This file is part of the uutils coreutils package. + * + * (c) Arcterus + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#[feature(macro_rules)]; + +extern crate getopts; + +use std::io; +use std::os; + +#[path = "../common/util.rs"] +mod util; + +static NAME: &'static str = "paste"; +static VERSION: &'static str = "1.0.0"; + +fn main() { + let args = os::args(); + let program = args[0].clone(); + + let opts = ~[ + getopts::optflag("s", "serial", "paste one file at a time instead of in parallel"), + getopts::optopt("d", "delimiters", "reuse characters from LIST instead of TABs", "LIST"), + getopts::optflag("h", "help", "display this help and exit"), + getopts::optflag("V", "version", "output version information and exit") + ]; + let matches = match getopts::getopts(args.tail(), opts) { + Ok(m) => m, + Err(f) => crash!(1, "{}", f.to_err_msg()) + }; + if matches.opt_present("help") { + println!("{} {}", NAME, VERSION); + println!(""); + println!("Usage:"); + println!(" {0:s} [OPTION]... [FILE]...", program); + println!(""); + print!("{}", getopts::usage("Write lines consisting of the sequentially corresponding lines from each FILE, separated by TABs, to standard output.", opts)); + } else if matches.opt_present("version") { + println!("{} {}", NAME, VERSION); + } else { + let serial = matches.opt_present("serial"); + let delimiters = match matches.opt_str("delimiters") { + Some(m) => m, + None => ~"\t" + }; + paste(matches.free, serial, delimiters); + } +} + +fn paste(filenames: ~[~str], serial: bool, delimiters: ~str) { + let mut files: ~[io::BufferedReader] = filenames.move_iter().map(|name| + io::BufferedReader::new(crash_if_err!(1, io::File::open(&Path::new(name)))) + ).collect(); + let mut delim_count = 0; + if serial { + for file in files.mut_iter() { + let mut output = ~""; + loop { + output = output + match file.read_line() { + Ok(line) => format!("{}{}", line.trim_right(), delimiters.char_at(delim_count % delimiters.len())), + Err(f) => if f.kind == io::EndOfFile { + break + } else { + crash!(1, "{}", f.to_str()) + } + }; + delim_count += 1; + } + output.pop_char(); + println!("{}", output); + } + } else { + loop { + let mut output = ~""; + let mut eof = 0; + for file in files.mut_iter() { + output = output + match file.read_line() { + Ok(line) => format!("{}{}", line.trim_right(), delimiters.char_at(delim_count % delimiters.len())), + Err(f) => if f.kind == io::EndOfFile { + eof += 1; + delimiters.char_at(delim_count % delimiters.len()).to_str() + } else { + crash!(1, "{}", f.to_str()) + } + }; + } + if files.len() == eof { + break; + } + output.pop_char(); + println!("{}", output); + } + } +}