mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-30 04:27:45 +00:00
commit
333e58283f
1 changed files with 40 additions and 52 deletions
92
src/wc/wc.rs
92
src/wc/wc.rs
|
@ -19,6 +19,7 @@ use std::io::{print, File, BufferedReader};
|
||||||
use std::io::fs::PathExtensions;
|
use std::io::fs::PathExtensions;
|
||||||
use std::io::stdio::stdin_raw;
|
use std::io::stdio::stdin_raw;
|
||||||
use std::result::Result as StdResult;
|
use std::result::Result as StdResult;
|
||||||
|
use std::borrow::IntoCow;
|
||||||
use getopts::Matches;
|
use getopts::Matches;
|
||||||
|
|
||||||
#[path = "../common/util.rs"]
|
#[path = "../common/util.rs"]
|
||||||
|
@ -37,7 +38,7 @@ struct Result {
|
||||||
static NAME: &'static str = "wc";
|
static NAME: &'static str = "wc";
|
||||||
|
|
||||||
pub fn uumain(args: Vec<String>) -> isize {
|
pub fn uumain(args: Vec<String>) -> isize {
|
||||||
let program = args[0].clone();
|
let program = &args[0][];
|
||||||
let opts = [
|
let opts = [
|
||||||
getopts::optflag("c", "bytes", "print the byte counts"),
|
getopts::optflag("c", "bytes", "print the byte counts"),
|
||||||
getopts::optflag("m", "chars", "print the character counts"),
|
getopts::optflag("m", "chars", "print the character counts"),
|
||||||
|
@ -59,7 +60,7 @@ pub fn uumain(args: Vec<String>) -> isize {
|
||||||
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).as_slice());
|
print(&getopts::usage("Print newline, word and byte counts for each FILE", &opts)[]);
|
||||||
println!("");
|
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;
|
||||||
|
@ -70,12 +71,13 @@ pub fn uumain(args: Vec<String>) -> isize {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut files = matches.free.clone();
|
let files = if matches.free.is_empty() {
|
||||||
if files.is_empty() {
|
vec!["-".to_string()].into_cow()
|
||||||
files = vec!("-".to_string());
|
} else {
|
||||||
}
|
matches.free[].into_cow()
|
||||||
|
};
|
||||||
|
|
||||||
match wc(files, &matches) {
|
match wc(&files[], &matches) {
|
||||||
Ok(()) => ( /* pass */ ),
|
Ok(()) => ( /* pass */ ),
|
||||||
Err(e) => return e
|
Err(e) => return e
|
||||||
}
|
}
|
||||||
|
@ -95,7 +97,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: Vec<String>, matches: &Matches) -> StdResult<(), isize> {
|
pub fn wc(files: &[String], matches: &Matches) -> StdResult<(), isize> {
|
||||||
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;
|
||||||
|
@ -106,57 +108,43 @@ pub fn wc(files: Vec<String>, matches: &Matches) -> StdResult<(), isize> {
|
||||||
let mut max_str_len: usize = 0;
|
let mut max_str_len: usize = 0;
|
||||||
|
|
||||||
for path in files.iter() {
|
for path in files.iter() {
|
||||||
let mut reader = try!(open(path.as_slice()));
|
let mut reader = try!(open(&path[]));
|
||||||
|
|
||||||
let mut line_count: usize = 0;
|
let mut line_count: usize = 0;
|
||||||
let mut word_count: usize = 0;
|
let mut word_count: usize = 0;
|
||||||
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 current_char_count: usize = 0;
|
|
||||||
let mut longest_line_length: usize = 0;
|
let mut longest_line_length: usize = 0;
|
||||||
|
|
||||||
loop {
|
// 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) {
|
||||||
match reader.read_until(LF) {
|
// GNU 'wc' only counts lines that end in LF as lines
|
||||||
Ok(raw_line) => {
|
if *raw_line.last().unwrap() == LF {
|
||||||
// GNU 'wc' only counts lines that end in LF as lines
|
line_count += 1;
|
||||||
if *raw_line.last().unwrap() == LF {
|
|
||||||
line_count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte_count += raw_line.len();
|
|
||||||
|
|
||||||
// try and convert the bytes to UTF-8 first
|
|
||||||
match from_utf8(raw_line.as_slice()) {
|
|
||||||
Ok(line) => {
|
|
||||||
word_count += line.words().count();
|
|
||||||
current_char_count = line.chars().count();
|
|
||||||
char_count += current_char_count;
|
|
||||||
},
|
|
||||||
Err(..) => {
|
|
||||||
word_count += raw_line.as_slice().split(|&x| is_word_seperator(x)).count();
|
|
||||||
for byte in raw_line.iter() {
|
|
||||||
match byte.is_ascii() {
|
|
||||||
true => {
|
|
||||||
current_char_count += 1;
|
|
||||||
}
|
|
||||||
false => { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
char_count += current_char_count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if current_char_count > longest_line_length {
|
|
||||||
// we subtract one here because `line.len()` includes the LF
|
|
||||||
// matches GNU 'wc' behaviour
|
|
||||||
longest_line_length = current_char_count - 1;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
byte_count += raw_line.len();
|
||||||
|
|
||||||
|
// try and convert the bytes to UTF-8 first
|
||||||
|
let current_char_count;
|
||||||
|
match from_utf8(&raw_line[]) {
|
||||||
|
Ok(line) => {
|
||||||
|
word_count += line.words().count();
|
||||||
|
current_char_count = line.chars().count();
|
||||||
|
},
|
||||||
|
Err(..) => {
|
||||||
|
word_count += raw_line.split(|&x| is_word_seperator(x)).count();
|
||||||
|
current_char_count = raw_line.iter().filter(|c|c.is_ascii()).count()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char_count += current_char_count;
|
||||||
|
|
||||||
|
if current_char_count > longest_line_length {
|
||||||
|
// we subtract one here because `line.len()` includes the LF
|
||||||
|
// matches GNU 'wc' behaviour
|
||||||
|
longest_line_length = current_char_count - 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
results.push(Result {
|
results.push(Result {
|
||||||
|
@ -182,7 +170,7 @@ pub fn wc(files: Vec<String>, matches: &Matches) -> StdResult<(), isize> {
|
||||||
}
|
}
|
||||||
|
|
||||||
for result in results.iter() {
|
for result in results.iter() {
|
||||||
print_stats(result.filename.as_slice(), 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 files.len() > 1 {
|
||||||
|
@ -222,7 +210,7 @@ fn print_stats(filename: &str, line_count: usize, word_count: usize, char_count:
|
||||||
}
|
}
|
||||||
|
|
||||||
if filename != "-" {
|
if filename != "-" {
|
||||||
println!(" {}", filename.as_slice());
|
println!(" {}", filename);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
println!("");
|
println!("");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue