diff --git a/base64/base64.rs b/base64/base64.rs index a05c9c520..b5315c9af 100644 --- a/base64/base64.rs +++ b/base64/base64.rs @@ -9,10 +9,12 @@ * that was distributed with this source code. */ +#[feature(phase)]; #[feature(macro_rules)]; extern crate serialize; extern crate getopts; +#[phase(syntax, link)] extern crate log; use std::char; use std::io::{println, File, stdin, stdout}; diff --git a/cat/cat.rs b/cat/cat.rs index cd940fd4b..9eae55a6b 100644 --- a/cat/cat.rs +++ b/cat/cat.rs @@ -15,7 +15,9 @@ extern crate getopts; use std::os; -use std::io::{print, stdin, stdout, File}; +use std::io::{print, File}; +use std::io::stdio::{stdout_raw, stdin_raw}; +use std::io::{BufferedReader, BufferedWriter}; fn main() { let args = os::args(); @@ -95,7 +97,6 @@ fn is_newline_char(byte: u8) -> bool { } pub fn exec(files: ~[~str], number: NumberingMode, show_nonprint: bool, show_ends: bool, show_tabs: bool, squeeze_blank: bool) { - let mut writer = stdout(); if NumberNone != number || show_nonprint || show_ends || show_tabs || squeeze_blank { let mut counter: uint = 1; @@ -107,57 +108,42 @@ pub fn exec(files: ~[~str], number: NumberingMode, show_nonprint: bool, show_end None => { continue } }; + let mut writer = BufferedWriter::with_capacity(1024 * 8, stdout_raw()); let mut at_line_start = true; - let mut buf = [0, .. 2]; + let mut buf = ~[0, .. 1024 * 4]; loop { // reading from a TTY seems to raise a condition on // EOF, rather than return Some(0) like a file. match reader.read(buf) { Ok(n) if n != 0 => { - for byte in buf.slice_to(n).iter() { - if at_line_start && (number == NumberAll || (number == NumberNonEmpty && !is_newline_char(*byte))) { - match write!(&mut writer as &mut Writer, "{0:6u}\t", counter) { - Ok(_) => (), Err(err) => fail!("{}", err) - }; + for &byte in buf.slice_to(n).iter() { + if at_line_start && (number == NumberAll || (number == NumberNonEmpty && !is_newline_char(byte))) { + (write!(&mut writer as &mut Writer, "{0:6u}\t", counter)).unwrap(); counter += 1; at_line_start = false; } - if is_numbering && *byte == LF { + if is_numbering && byte == LF { at_line_start = true; } - if show_tabs && *byte == TAB { - match writer.write(bytes!("^I")) { - Ok(_) => (), Err(err) => fail!("{}", err) - }; - } else if show_ends && *byte == LF { - match writer.write(bytes!("$\n")) { - Ok(_) => (), Err(err) => fail!("{}", err) - }; - } else if show_nonprint && (*byte < 32 || *byte >= 127) && !is_newline_char(*byte) { - let mut byte = *byte; + if show_tabs && byte == TAB { + writer.write(bytes!("^I")).unwrap(); + } else if show_ends && byte == LF { + writer.write(bytes!("$\n")).unwrap(); + } else if show_nonprint && (byte < 32 || byte >= 127) && !is_newline_char(byte) { + let mut byte = byte; if byte >= 128 { - match writer.write(bytes!("M-")) { - Ok(_) => (), Err(err) => fail!("{}", err) - }; + writer.write(bytes!("M-")).unwrap(); byte = byte - 128; } if byte < 32 { - match writer.write(['^' as u8, byte + 64]) { - Ok(_) => (), Err(err) => fail!("{}", err) - }; + writer.write(['^' as u8, byte + 64]).unwrap(); } else if byte == 127 { - match writer.write(['^' as u8, byte - 64]) { - Ok(_) => (), Err(err) => fail!("{}", err) - }; + writer.write(['^' as u8, byte - 64]).unwrap(); } else { - match writer.write([byte]) { - Ok(_) => (), Err(err) => fail!("{}", err) - }; + writer.write_u8(byte).unwrap(); } } else { - match writer.write([*byte]) { - Ok(_) => (), Err(err) => fail!("{}", err) - }; + writer.write_u8(byte).unwrap(); } } }, @@ -168,7 +154,8 @@ pub fn exec(files: ~[~str], number: NumberingMode, show_nonprint: bool, show_end return; } - let mut buf = [0, .. 100000]; + let mut writer = stdout_raw(); + let mut buf = ~[0, .. 1024 * 64]; // passthru mode for path in files.iter() { let mut reader = match open(path.to_owned()) { @@ -181,9 +168,7 @@ pub fn exec(files: ~[~str], number: NumberingMode, show_nonprint: bool, show_end // rather than return Some(0) like a file. match reader.read(buf) { Ok(n) if n != 0 => { - match writer.write(buf.slice_to(n)) { - Ok(_) => (), Err(err) => fail!("{}", err) - } + writer.write(buf.slice_to(n)).unwrap(); }, _ => break } } @@ -192,7 +177,7 @@ pub fn exec(files: ~[~str], number: NumberingMode, show_nonprint: bool, show_end fn open(path: ~str) -> Option<~Reader> { if "-" == path { - return Some(~stdin() as ~Reader); + return Some(~stdin_raw() as ~Reader); } match File::open(&std::path::Path::new(path.as_slice())) { @@ -200,3 +185,4 @@ fn open(path: ~str) -> Option<~Reader> { Err(e) => fail!("cat: {0:s}: {1:s}", path, e.to_str()) } } +/* vim: set ai ts=4 sw=4 sts=4 et : */ diff --git a/cp/cp.rs b/cp/cp.rs new file mode 100644 index 000000000..f61bd99b8 --- /dev/null +++ b/cp/cp.rs @@ -0,0 +1,178 @@ +#[crate_id(name="cp", vers="1.0.0", author="Jordy Dickinson")]; +#[feature(macro_rules)]; +#[feature(phase)]; + +/* + * This file is part of the uutils coreutils package. + * + * (c) Jordy Dickinson + * + * For the full copyright and license information, please view the LICENSE file + * that was distributed with this source code. + */ + +extern crate getopts; +#[phase(syntax, link)] extern crate log; + +use std::os; +use std::io; +use std::io::fs; + +use getopts::{ + getopts, + optflag, + usage, +}; + +#[deriving(Eq)] +pub enum Mode { + Copy, + Help, + Version, +} + +fn main() { + let args = os::args(); + let opts = ~[ + optflag("h", "help", "display this help and exit"), + optflag("", "version", "output version information and exit"), + ]; + let matches = match getopts(args.tail(), opts) { + Ok(m) => m, + Err(e) => { + error!("error: {:s}", e.to_err_msg()); + fail!() + }, + }; + + let progname = args[0].clone(); + let usage = usage("Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.", opts); + let mode = if matches.opt_present("version") { + Version + } else if matches.opt_present("help") { + Help + } else { + Copy + }; + + match mode { + Copy => copy(matches), + Help => help(progname, usage), + Version => version(), + } +} + +fn version() { + println!("cp 1.0.0"); +} + +fn help(progname: &str, usage: &str) { + let msg = format!("Usage: {0} SOURCE DEST\n \ + or: {0} SOURCE... DIRECTORY\n \ + or: {0} -t DIRECTORY SOURCE\n\ + \n\ + {1}", progname, usage); + println!("{}", msg); +} + +fn copy(matches: getopts::Matches) { + let sources = if matches.free.len() < 1 { + error!("error: Missing SOURCE argument. Try --help."); + fail!() + } else { + // All but the last argument: + matches.free.slice(0, matches.free.len() - 2) + .map(|arg| ~Path::new(arg.clone())) + }; + let dest = if matches.free.len() < 2 { + error!("error: Missing DEST argument. Try --help."); + fail!() + } else { + // Only the last argument: + ~Path::new(matches.free[matches.free.len() - 1].clone()) + }; + + assert!(sources.len() >= 1); + + if sources.len() == 1 { + let source = sources[0].clone(); + let same_file = match paths_refer_to_same_file(source, dest) { + Ok(b) => b, + Err(e) => if e.kind == io::FileNotFound { + false + } else { + error!("error: {:s}", e.to_str()); + fail!() + } + }; + + if same_file { + error!("error: \"{:s}\" and \"{:s}\" are the same file", + source.display().to_str(), + dest.display().to_str()); + fail!(); + } + + let io_result = fs::copy(source, dest); + + if io_result.is_err() { + let err = io_result.unwrap_err(); + error!("error: {:s}", err.to_str()); + fail!(); + } + } else { + if fs::stat(dest).unwrap().kind != io::TypeDirectory { + error!("error: TARGET must be a directory"); + fail!(); + } + + for source in sources.iter() { + if fs::stat(*source).unwrap().kind != io::TypeFile { + error!("error: \"{:s}\" is not a file", source.display().to_str()); + continue; + } + + let mut full_dest = dest.clone(); + + full_dest.push(source.filename_str().unwrap()); + + println!("{:s}", full_dest.display().to_str()); + + let io_result = fs::copy(*source, full_dest); + + if io_result.is_err() { + let err = io_result.unwrap_err(); + error!("error: {:s}", err.to_str()); + fail!() + } + } + } +} + +pub fn paths_refer_to_same_file(p1: &Path, p2: &Path) -> io::IoResult { + let mut raw_p1 = ~p1.clone(); + let mut raw_p2 = ~p2.clone(); + + let p1_lstat = match fs::lstat(raw_p1) { + Ok(stat) => stat, + Err(e) => return Err(e), + }; + + let p2_lstat = match fs::lstat(raw_p2) { + Ok(stat) => stat, + Err(e) => return Err(e), + }; + + // We have to take symlinks and relative paths into account. + if p1_lstat.kind == io::TypeSymlink { + raw_p1 = ~fs::readlink(raw_p1).unwrap(); + } + raw_p1 = ~os::make_absolute(raw_p1); + + if p2_lstat.kind == io::TypeSymlink { + raw_p2 = ~fs::readlink(raw_p2).unwrap(); + } + raw_p2 = ~os::make_absolute(raw_p2); + + Ok(raw_p1 == raw_p2) +} diff --git a/tee/tee.rs b/tee/tee.rs index 43cf53894..16ab9fabe 100644 --- a/tee/tee.rs +++ b/tee/tee.rs @@ -1,5 +1,7 @@ #[crate_id(name="tee", vers="1.0.0", author="Aleksander Bielawski")]; #[license="MIT"]; +#[feature(phase)]; +#[feature(macro_rules)]; /* * This file is part of the uutils coreutils package. @@ -11,6 +13,7 @@ */ extern crate getopts; +#[phase(syntax, link)] extern crate log; use std::io::{println, stdin, stdout, Append, File, Truncate, Write}; use std::io::{IoResult};