1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-08-02 05:57:46 +00:00
This commit is contained in:
kwantam 2015-04-27 18:19:56 -04:00
parent 143aea72ee
commit a122849e7c

View file

@ -1,5 +1,5 @@
#![crate_name = "wc"] #![crate_name = "wc"]
#![feature(collections, old_io, old_path, rustc_private, str_words)] #![feature(rustc_private, path_ext)]
/* /*
* This file is part of the uutils coreutils package. * This file is part of the uutils coreutils package.
@ -13,15 +13,15 @@
extern crate getopts; extern crate getopts;
extern crate libc; extern crate libc;
use std::ascii::AsciiExt;
use std::str::from_utf8;
use std::old_io::{print, File, BufferedReader};
use std::old_io::fs::PathExtensions;
use std::old_io::stdio::stdin_raw;
use std::result::Result as StdResult;
use std::borrow::IntoCow;
use getopts::Matches; use getopts::Matches;
use std::ascii::AsciiExt;
use std::fs::{File, PathExt};
use std::io::{stdin, BufRead, BufReader, Read, Write};
use std::path::Path;
use std::result::Result as StdResult;
use std::str::from_utf8;
#[path = "../common/util.rs"] #[path = "../common/util.rs"]
#[macro_use] #[macro_use]
mod util; mod util;
@ -49,7 +49,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
getopts::optflag("V", "version", "output version information and exit"), getopts::optflag("V", "version", "output version information and exit"),
]; ];
let matches = match getopts::getopts(args.tail(), &opts) { let mut matches = match getopts::getopts(&args[1..], &opts) {
Ok(m) => m, Ok(m) => m,
Err(f) => { Err(f) => {
crash!(1, "Invalid options\n{}", f) crash!(1, "Invalid options\n{}", f)
@ -60,8 +60,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
println!("Usage:"); println!("Usage:");
println!(" {0} [OPTION]... [FILE]...", program); println!(" {0} [OPTION]... [FILE]...", program);
println!(""); println!("");
print(&getopts::usage("Print newline, word and byte counts for each FILE", &opts)[..]); println!("{}", getopts::usage("Print newline, word and byte counts for each FILE", &opts));
println!("");
println!("With no FILE, or when FILE is -, read standard input."); println!("With no FILE, or when FILE is -, read standard input.");
return 0; return 0;
} }
@ -71,13 +70,11 @@ pub fn uumain(args: Vec<String>) -> i32 {
return 0; return 0;
} }
let files = if matches.free.is_empty() { if matches.free.is_empty() {
vec!["-".to_string()].into_cow() matches.free.push("-".to_string());
} else { }
matches.free[..].into_cow()
};
match wc(&files[..], &matches) { match wc(&matches) {
Ok(()) => ( /* pass */ ), Ok(()) => ( /* pass */ ),
Err(e) => return e Err(e) => return e
} }
@ -97,7 +94,7 @@ fn is_word_seperator(byte: u8) -> bool {
byte == SPACE || byte == TAB || byte == CR || byte == SYN || byte == FF byte == SPACE || byte == TAB || byte == CR || byte == SYN || byte == FF
} }
pub fn wc(files: &[String], matches: &Matches) -> StdResult<(), i32> { pub fn wc(matches: &Matches) -> StdResult<(), i32> {
let mut total_line_count: usize = 0; let mut total_line_count: usize = 0;
let mut total_word_count: usize = 0; let mut total_word_count: usize = 0;
let mut total_char_count: usize = 0; let mut total_char_count: usize = 0;
@ -107,7 +104,7 @@ pub fn wc(files: &[String], matches: &Matches) -> StdResult<(), i32> {
let mut results = vec!(); let mut results = vec!();
let mut max_str_len: usize = 0; let mut max_str_len: usize = 0;
for path in files.iter() { for path in matches.free.iter() {
let mut reader = try!(open(&path[..])); let mut reader = try!(open(&path[..]));
let mut line_count: usize = 0; let mut line_count: usize = 0;
@ -115,10 +112,18 @@ pub fn wc(files: &[String], matches: &Matches) -> StdResult<(), i32> {
let mut byte_count: usize = 0; let mut byte_count: usize = 0;
let mut char_count: usize = 0; let mut char_count: usize = 0;
let mut longest_line_length: usize = 0; let mut longest_line_length: usize = 0;
let mut raw_line = Vec::new();
// reading from a TTY seems to raise a condition on, rather than return Some(0) like a file. // reading from a TTY seems to raise a condition on, rather than return Some(0) like a file.
// hence the option wrapped in a result here // hence the option wrapped in a result here
while let Ok(raw_line) = reader.read_until(LF) { while match reader.read_until(LF, &mut raw_line) {
Ok(n) if n > 0 => true,
Err(ref e) if raw_line.len() > 0 => {
show_warning!("Error while reading {}: {}", path, e);
raw_line.len() > 0
},
_ => false,
} {
// GNU 'wc' only counts lines that end in LF as lines // GNU 'wc' only counts lines that end in LF as lines
if *raw_line.last().unwrap() == LF { if *raw_line.last().unwrap() == LF {
line_count += 1; line_count += 1;
@ -130,7 +135,7 @@ pub fn wc(files: &[String], matches: &Matches) -> StdResult<(), i32> {
let current_char_count; let current_char_count;
match from_utf8(&raw_line[..]) { match from_utf8(&raw_line[..]) {
Ok(line) => { Ok(line) => {
word_count += line.words().count(); word_count += line.split_whitespace().count();
current_char_count = line.chars().count(); current_char_count = line.chars().count();
}, },
Err(..) => { Err(..) => {
@ -145,6 +150,8 @@ pub fn wc(files: &[String], matches: &Matches) -> StdResult<(), i32> {
// matches GNU 'wc' behaviour // matches GNU 'wc' behaviour
longest_line_length = current_char_count - 1; longest_line_length = current_char_count - 1;
} }
raw_line.truncate(0);
} }
results.push(Result { results.push(Result {
@ -173,7 +180,7 @@ pub fn wc(files: &[String], matches: &Matches) -> StdResult<(), i32> {
print_stats(&result.filename[..], result.lines, result.words, result.chars, result.bytes, result.max_line_length, matches, max_str_len); print_stats(&result.filename[..], result.lines, result.words, result.chars, result.bytes, result.max_line_length, matches, max_str_len);
} }
if files.len() > 1 { if matches.free.len() > 1 {
print_stats("total", total_line_count, total_word_count, total_char_count, total_byte_count, total_longest_line_length, matches, max_str_len); print_stats("total", total_line_count, total_word_count, total_char_count, total_byte_count, total_longest_line_length, matches, max_str_len);
} }
@ -217,10 +224,10 @@ fn print_stats(filename: &str, line_count: usize, word_count: usize, char_count:
} }
} }
fn open(path: &str) -> StdResult<BufferedReader<Box<Reader+'static>>, i32> { fn open(path: &str) -> StdResult<BufReader<Box<Read+'static>>, i32> {
if "-" == path { if "-" == path {
let reader = Box::new(stdin_raw()) as Box<Reader>; let reader = Box::new(stdin()) as Box<Read>;
return Ok(BufferedReader::new(reader)); return Ok(BufReader::new(reader));
} }
let fpath = Path::new(path); let fpath = Path::new(path);
@ -229,8 +236,8 @@ fn open(path: &str) -> StdResult<BufferedReader<Box<Reader+'static>>, i32> {
} }
match File::open(&fpath) { match File::open(&fpath) {
Ok(fd) => { Ok(fd) => {
let reader = Box::new(fd) as Box<Reader>; let reader = Box::new(fd) as Box<Read>;
Ok(BufferedReader::new(reader)) Ok(BufReader::new(reader))
} }
Err(e) => { Err(e) => {
show_error!("wc: {}: {}", path, e); show_error!("wc: {}: {}", path, e);