From aa51311f83857b26e021f8c0e32f32e952161901 Mon Sep 17 00:00:00 2001 From: "T. Jameson Little" Date: Tue, 27 May 2014 18:57:33 -0600 Subject: [PATCH] add sum --- Makefile | 1 + README.md | 1 - sum/sum.rs | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 sum/sum.rs diff --git a/Makefile b/Makefile index 4b48a3e29..34733f74d 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,7 @@ PROGS := \ rmdir \ sleep \ seq \ + sum \ tac \ tee \ touch \ diff --git a/README.md b/README.md index 46b23b1d6..67424489e 100644 --- a/README.md +++ b/README.md @@ -133,7 +133,6 @@ To do - stat - stdbuf - stty (in progress) -- sum - sync - tac-pipe - tail diff --git a/sum/sum.rs b/sum/sum.rs new file mode 100644 index 000000000..830dec78e --- /dev/null +++ b/sum/sum.rs @@ -0,0 +1,129 @@ +#![crate_id(name="sum", vers="1.0.0", author="T. Jameson Little")] +#![feature(macro_rules)] + +/* +* This file is part of the uutils coreutils package. +* +* (c) T. Jameson Little +* +* For the full copyright and license information, please view the LICENSE file +* that was distributed with this source code. +*/ + +extern crate getopts; +extern crate libc; + +use std::os; +use std::io::{File, IoResult, print}; +use std::io::stdio::{stdin_raw}; + +#[path="../common/util.rs"] +mod util; + +static VERSION: &'static str = "1.0.0"; +static NAME: &'static str = "sum"; + +fn bsd_sum(mut reader: Box) -> (uint, u16) { + let mut buf = ~[0, .. 1024]; + let mut blocks_read = 0; + let mut checksum: u16 = 0; + loop { + match reader.read(buf) { + Ok(n) if n != 0 => { + blocks_read += 1; + for &byte in buf.slice_to(n).iter() { + checksum = (checksum >> 1) + ((checksum & 1) << 15); + checksum += byte as u16; + } + }, + _ => break, + } + } + + (blocks_read, checksum) +} + +fn sysv_sum(mut reader: Box) -> (uint, u16) { + let mut buf = ~[0, .. 512]; + let mut blocks_read = 0; + let mut ret = 0; + + loop { + match reader.read(buf) { + Ok(n) if n != 0 => { + blocks_read += 1; + for &byte in buf.slice_to(n).iter() { + ret += byte as u32; + } + }, + _ => break, + } + } + + ret = (ret & 0xffff) + (ret >> 16); + ret = (ret & 0xffff) + (ret >> 16); + + (blocks_read, ret as u16) +} + +fn open(name: &str) -> IoResult> { + match name { + "-" => Ok(box stdin_raw() as Box), + _ => { + let f = try!(File::open(&Path::new(name))); + Ok(box f as Box) + } + } +} + +fn main() { + let args = os::args(); + let program = args.get(0).as_slice(); + let opts = [ + getopts::optflag("r", "", "use the BSD compatible algorithm (default)"), + getopts::optflag("s", "sysv", "use System V compatible algorithm"), + getopts::optflag("h", "help", "show this help message"), + getopts::optflag("v", "version", "print the version and exit"), + ]; + + let matches = match getopts::getopts(args.tail(), opts) { + Ok(m) => m, + Err(f) => crash!(1, "Invalid options\n{}", f.to_err_msg()) + }; + + if matches.opt_present("help") { + println!("{} {}", program, VERSION); + println!(""); + println!("Usage:"); + println!(" {0:s} [OPTION]... [FILE]...", program); + println!(""); + print(getopts::usage("checksum and count the blocks in a file", opts).as_slice()); + println!(""); + println!("With no FILE, or when FILE is -, read standard input."); + return; + } + if matches.opt_present("version") { + println!("{} {}", program, VERSION); + return; + } + + let sysv = matches.opt_present("sysv"); + + let file = if matches.free.is_empty() { + "-" + } else { + matches.free.get(0).as_slice() + }; + + let reader = match open(file) { + Ok(f) => f, + _ => crash!(1, "unable to open file") + }; + let (blocks, sum) = if sysv { + sysv_sum(reader) + } else { + bsd_sum(reader) + }; + + println!("{} {}", sum, blocks); +}