2015-12-08 02:42:08 +00:00
|
|
|
#![crate_name = "uu_sum"]
|
2014-05-28 00:57:33 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* This file is part of the uutils coreutils package.
|
|
|
|
*
|
|
|
|
* (c) T. Jameson Little <t.jameson.little@gmail.com>
|
|
|
|
*
|
|
|
|
* 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;
|
|
|
|
|
2015-11-24 01:00:51 +00:00
|
|
|
#[macro_use]
|
|
|
|
extern crate uucore;
|
|
|
|
|
2015-05-06 18:12:30 +00:00
|
|
|
use std::fs::File;
|
|
|
|
use std::io::{Read, Result, stdin, Write};
|
|
|
|
use std::path::Path;
|
2014-05-28 00:57:33 +00:00
|
|
|
|
|
|
|
static NAME: &'static str = "sum";
|
2015-11-25 09:52:10 +00:00
|
|
|
static VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
2014-05-28 00:57:33 +00:00
|
|
|
|
2015-05-06 18:12:30 +00:00
|
|
|
fn bsd_sum(mut reader: Box<Read>) -> (usize, u16) {
|
2015-01-08 12:58:23 +00:00
|
|
|
let mut buf = [0; 1024];
|
2014-05-28 00:57:33 +00:00
|
|
|
let mut blocks_read = 0;
|
|
|
|
let mut checksum: u16 = 0;
|
|
|
|
loop {
|
2014-11-19 20:55:25 +00:00
|
|
|
match reader.read(&mut buf) {
|
2014-05-28 00:57:33 +00:00
|
|
|
Ok(n) if n != 0 => {
|
|
|
|
blocks_read += 1;
|
2015-01-24 09:44:48 +00:00
|
|
|
for &byte in buf[..n].iter() {
|
2014-05-28 00:57:33 +00:00
|
|
|
checksum = (checksum >> 1) + ((checksum & 1) << 15);
|
2015-11-25 08:50:37 +00:00
|
|
|
checksum = checksum.wrapping_add(byte as u16);
|
2014-05-28 00:57:33 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => break,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
(blocks_read, checksum)
|
|
|
|
}
|
|
|
|
|
2015-05-06 18:12:30 +00:00
|
|
|
fn sysv_sum(mut reader: Box<Read>) -> (usize, u16) {
|
2015-01-08 12:58:23 +00:00
|
|
|
let mut buf = [0; 512];
|
2014-05-28 00:57:33 +00:00
|
|
|
let mut blocks_read = 0;
|
2015-11-25 08:50:37 +00:00
|
|
|
let mut ret = 0u32;
|
2014-05-28 00:57:33 +00:00
|
|
|
|
|
|
|
loop {
|
2014-11-19 20:55:25 +00:00
|
|
|
match reader.read(&mut buf) {
|
2014-05-28 00:57:33 +00:00
|
|
|
Ok(n) if n != 0 => {
|
|
|
|
blocks_read += 1;
|
2015-01-24 09:44:48 +00:00
|
|
|
for &byte in buf[..n].iter() {
|
2015-11-25 08:50:37 +00:00
|
|
|
ret = ret.wrapping_add(byte as u32);
|
2014-05-28 00:57:33 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => break,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = (ret & 0xffff) + (ret >> 16);
|
|
|
|
ret = (ret & 0xffff) + (ret >> 16);
|
|
|
|
|
|
|
|
(blocks_read, ret as u16)
|
|
|
|
}
|
|
|
|
|
2015-05-06 18:12:30 +00:00
|
|
|
fn open(name: &str) -> Result<Box<Read>> {
|
2014-10-05 01:09:52 +00:00
|
|
|
match name {
|
2015-05-06 18:12:30 +00:00
|
|
|
"-" => Ok(Box::new(stdin()) as Box<Read>),
|
2014-10-05 01:09:52 +00:00
|
|
|
_ => {
|
|
|
|
let f = try!(File::open(&Path::new(name)));
|
2015-05-06 18:12:30 +00:00
|
|
|
Ok(Box::new(f) as Box<Read>)
|
2014-10-05 01:09:52 +00:00
|
|
|
}
|
|
|
|
}
|
2014-05-28 00:57:33 +00:00
|
|
|
}
|
|
|
|
|
2015-02-06 13:48:07 +00:00
|
|
|
pub fn uumain(args: Vec<String>) -> i32 {
|
2015-05-21 18:42:42 +00:00
|
|
|
let mut opts = getopts::Options::new();
|
|
|
|
|
|
|
|
opts.optflag("r", "", "use the BSD compatible algorithm (default)");
|
|
|
|
opts.optflag("s", "sysv", "use System V compatible algorithm");
|
|
|
|
opts.optflag("h", "help", "show this help message");
|
|
|
|
opts.optflag("v", "version", "print the version and exit");
|
|
|
|
|
|
|
|
let matches = match opts.parse(&args[1..]) {
|
2014-05-28 00:57:33 +00:00
|
|
|
Ok(m) => m,
|
2014-06-15 10:50:40 +00:00
|
|
|
Err(f) => crash!(1, "Invalid options\n{}", f)
|
2014-05-28 00:57:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
if matches.opt_present("help") {
|
2015-05-21 18:42:42 +00:00
|
|
|
let msg = format!("{0} {1}
|
|
|
|
|
|
|
|
Usage:
|
|
|
|
{0} [OPTION]... [FILE]...
|
|
|
|
|
|
|
|
Checksum and count the blocks in a file.", NAME, VERSION);
|
|
|
|
println!("{}\nWith no FILE, or when FILE is -, read standard input.", opts.usage(&msg));
|
2014-06-08 07:56:37 +00:00
|
|
|
return 0;
|
2014-05-28 00:57:33 +00:00
|
|
|
}
|
|
|
|
if matches.opt_present("version") {
|
2015-05-21 18:42:42 +00:00
|
|
|
println!("{} {}", NAME, VERSION);
|
2014-06-08 07:56:37 +00:00
|
|
|
return 0;
|
2014-05-28 00:57:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let sysv = matches.opt_present("sysv");
|
|
|
|
|
2014-06-18 10:36:12 +00:00
|
|
|
let files = if matches.free.is_empty() {
|
2016-01-05 19:42:52 +00:00
|
|
|
vec!["-".to_owned()]
|
2014-05-28 00:57:33 +00:00
|
|
|
} else {
|
2014-06-18 10:36:12 +00:00
|
|
|
matches.free
|
2014-05-28 00:57:33 +00:00
|
|
|
};
|
|
|
|
|
2015-08-14 04:10:15 +00:00
|
|
|
let print_names = if sysv {
|
|
|
|
files.len() > 1 || files[0] != "-"
|
|
|
|
} else {
|
|
|
|
files.len() > 1
|
|
|
|
};
|
2014-06-18 10:38:19 +00:00
|
|
|
|
2016-01-05 19:42:52 +00:00
|
|
|
for file in &files {
|
2015-05-06 18:12:30 +00:00
|
|
|
let reader = match open(file) {
|
2014-06-18 10:36:12 +00:00
|
|
|
Ok(f) => f,
|
|
|
|
_ => crash!(1, "unable to open file")
|
|
|
|
};
|
|
|
|
let (blocks, sum) = if sysv {
|
|
|
|
sysv_sum(reader)
|
|
|
|
} else {
|
|
|
|
bsd_sum(reader)
|
|
|
|
};
|
|
|
|
|
2014-06-18 10:38:19 +00:00
|
|
|
if print_names {
|
|
|
|
println!("{} {} {}", sum, blocks, file);
|
|
|
|
} else {
|
|
|
|
println!("{} {}", sum, blocks);
|
|
|
|
}
|
2014-06-18 10:36:12 +00:00
|
|
|
}
|
2014-06-08 07:56:37 +00:00
|
|
|
|
2014-06-12 04:41:53 +00:00
|
|
|
0
|
2014-05-28 00:57:33 +00:00
|
|
|
}
|