From 49f3f0ea32e534499f7f56ab04a1b8ce877b0e2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Ci=C4=99=C5=BCarkiewicz?= Date: Wed, 19 Mar 2014 11:38:11 -0700 Subject: [PATCH 1/6] Fix compilation for latest rustc. Some warning are still there. (cherry picked from commit 5c690b33d60725d8ef90c8531adf832f9afd27a8) Conflicts: cp/cp.rs --- base64/base64.rs | 2 + cp/cp.rs | 178 +++++++++++++++++++++++++++++++++++++++++++++++ tee/tee.rs | 3 + 3 files changed, 183 insertions(+) create mode 100644 cp/cp.rs 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/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}; From fb8e502980137653b78d98ca9e5f1c2a67ec5590 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Ci=C4=99=C5=BCarkiewicz?= Date: Wed, 19 Mar 2014 09:48:47 -0700 Subject: [PATCH 2/6] Add vim formatting comment. Because otherwise, I can't do any work. ;) (cherry picked from commit 05d026d0d001f745154c81a131782516581b7be4) --- cat/cat.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/cat/cat.rs b/cat/cat.rs index cd940fd4b..815c08fbe 100644 --- a/cat/cat.rs +++ b/cat/cat.rs @@ -200,3 +200,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 : */ From 3ab18651775f125a6cfb07e184ea6c29482c4789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Ci=C4=99=C5=BCarkiewicz?= Date: Wed, 19 Mar 2014 09:35:33 -0700 Subject: [PATCH 3/6] Use raw stdin/stdio. Buffered one is expensive and serves no purpose. (cherry picked from commit ace707d5044026b1167b3326692c8c8f118e05e4) --- cat/cat.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cat/cat.rs b/cat/cat.rs index 815c08fbe..9c806d9b1 100644 --- a/cat/cat.rs +++ b/cat/cat.rs @@ -15,7 +15,8 @@ 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}; fn main() { let args = os::args(); @@ -95,7 +96,7 @@ 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(); + let mut writer = stdout_raw(); if NumberNone != number || show_nonprint || show_ends || show_tabs || squeeze_blank { let mut counter: uint = 1; @@ -192,7 +193,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())) { From a42bdea8ac37c8c8c739015da4f55d4468a6e9a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Ci=C4=99=C5=BCarkiewicz?= Date: Wed, 19 Mar 2014 09:42:34 -0700 Subject: [PATCH 4/6] Use Buffered input/output where it makes sense. (cherry picked from commit c084bb1568d62d0e3e17151c8a4e859a95805a07) --- cat/cat.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cat/cat.rs b/cat/cat.rs index 9c806d9b1..1cb42c35d 100644 --- a/cat/cat.rs +++ b/cat/cat.rs @@ -17,6 +17,7 @@ extern crate getopts; use std::os; use std::io::{print, File}; use std::io::stdio::{stdout_raw, stdin_raw}; +use std::io::{BufferedReader, BufferedWriter}; fn main() { let args = os::args(); @@ -96,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_raw(); if NumberNone != number || show_nonprint || show_ends || show_tabs || squeeze_blank { let mut counter: uint = 1; @@ -108,6 +108,7 @@ 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]; loop { @@ -170,6 +171,7 @@ pub fn exec(files: ~[~str], number: NumberingMode, show_nonprint: bool, show_end } let mut buf = [0, .. 100000]; + let mut writer = stdout_raw(); // passthru mode for path in files.iter() { let mut reader = match open(path.to_owned()) { From 893ab7c761dd51f298e01c755b0bd678da595481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Ci=C4=99=C5=BCarkiewicz?= Date: Wed, 19 Mar 2014 09:48:05 -0700 Subject: [PATCH 5/6] Increase buffers for boost in performance. (cherry picked from commit 4b702bc9522503b88d9084de2ce5780f75ee9e23) --- cat/cat.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cat/cat.rs b/cat/cat.rs index 1cb42c35d..fbba1d622 100644 --- a/cat/cat.rs +++ b/cat/cat.rs @@ -110,7 +110,7 @@ pub fn exec(files: ~[~str], number: NumberingMode, show_nonprint: bool, show_end 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. @@ -170,8 +170,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()) { From a93023372c4f740b69bd5635f58a0d4812c6b722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Ci=C4=99=C5=BCarkiewicz?= Date: Wed, 19 Mar 2014 09:47:06 -0700 Subject: [PATCH 6/6] Use `.unwrap()` and &byte for cleaner code. (cherry picked from commit 0a91290d912d9193f707879bba5865e43b2094da) --- cat/cat.rs | 50 ++++++++++++++++---------------------------------- 1 file changed, 16 insertions(+), 34 deletions(-) diff --git a/cat/cat.rs b/cat/cat.rs index fbba1d622..9eae55a6b 100644 --- a/cat/cat.rs +++ b/cat/cat.rs @@ -116,50 +116,34 @@ pub fn exec(files: ~[~str], number: NumberingMode, show_nonprint: bool, show_end // 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(); } } }, @@ -184,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 } }