1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-31 13:07:46 +00:00

Merge pull request #582 from jbcrail/fix-split

Fix split.
This commit is contained in:
Heather 2015-05-09 08:10:50 +03:00
commit df27f5035c

View file

@ -1,5 +1,5 @@
#![crate_name = "split"] #![crate_name = "split"]
#![feature(collections, core, old_io, old_path, rustc_private)] #![feature(rustc_private)]
/* /*
* This file is part of the uutils coreutils package. * This file is part of the uutils coreutils package.
@ -13,9 +13,10 @@
extern crate getopts; extern crate getopts;
extern crate libc; extern crate libc;
use std::old_io as io;
use std::num::Int;
use std::char; use std::char;
use std::fs::{File, OpenOptions};
use std::io::{BufRead, BufReader, BufWriter, Read, stdin, stdout, Write};
use std::path::Path;
#[path = "../common/util.rs"] #[path = "../common/util.rs"]
#[macro_use] #[macro_use]
@ -36,7 +37,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 matches = match getopts::getopts(&args[1..], &opts) {
Ok(m) => m, Ok(m) => m,
Err(f) => crash!(1, "{}", f) Err(f) => crash!(1, "{}", f)
}; };
@ -47,7 +48,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
println!("Usage:"); println!("Usage:");
println!(" {0} [OPTION]... [INPUT [PREFIX]]", NAME); println!(" {0} [OPTION]... [INPUT [PREFIX]]", NAME);
println!(""); println!("");
io::print(getopts::usage("Output fixed-size pieces of INPUT to PREFIXaa, PREFIX ab, ...; default size is 1000, and default PREFIX is 'x'. With no INPUT, or when INPUT is -, read standard input." , &opts).as_slice()); print!("{}", getopts::usage("Output fixed-size pieces of INPUT to PREFIXaa, PREFIX ab, ...; default size is 1000, and default PREFIX is 'x'. With no INPUT, or when INPUT is -, read standard input." , &opts));
println!(""); println!("");
println!("SIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg."); println!("SIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg.");
return 0; return 0;
@ -71,7 +72,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
settings.numeric_suffix = if matches.opt_present("d") { true } else { false }; settings.numeric_suffix = if matches.opt_present("d") { true } else { false };
settings.suffix_length = match matches.opt_str("a") { settings.suffix_length = match matches.opt_str("a") {
Some(n) => match n.as_slice().parse() { Some(n) => match n.parse() {
Ok(m) => m, Ok(m) => m,
Err(e) => crash!(1, "cannot parse num: {}", e) Err(e) => crash!(1, "cannot parse num: {}", e)
}, },
@ -86,7 +87,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
for e in strategies.iter() { for e in strategies.iter() {
match matches.opt_str(*e) { match matches.opt_str(*e) {
Some(a) => { Some(a) => {
if settings.strategy.as_slice() == "l" { if settings.strategy == "l" {
settings.strategy = e.to_string(); settings.strategy = e.to_string();
settings.strategy_param = a; settings.strategy_param = a;
} else { } else {
@ -133,9 +134,10 @@ struct LineSplitter {
saved_lines_to_write: usize, saved_lines_to_write: usize,
lines_to_write: usize, lines_to_write: usize,
} }
impl LineSplitter { impl LineSplitter {
fn new(settings: &Settings) -> Box<Splitter> { fn new(settings: &Settings) -> Box<Splitter> {
let n = match settings.strategy_param.as_slice().parse() { let n = match settings.strategy_param.parse() {
Ok(a) => a, Ok(a) => a,
Err(e) => crash!(1, "invalid number of lines: {}", e) Err(e) => crash!(1, "invalid number of lines: {}", e)
}; };
@ -177,12 +179,12 @@ impl ByteSplitter {
_ => crash!(1, "invalid number of bytes") _ => crash!(1, "invalid number of bytes")
}; };
let n = if suffix.is_alphabetic() { let n = if suffix.is_alphabetic() {
match strategy_param.as_slice().iter().map(|c| *c).collect::<String>().as_slice().parse::<usize>() { match strategy_param.iter().map(|c| *c).collect::<String>().parse::<usize>() {
Ok(a) => a, Ok(a) => a,
Err(e) => crash!(1, "invalid number of bytes: {}", e) Err(e) => crash!(1, "invalid number of bytes: {}", e)
} }
} else { } else {
match settings.strategy_param.as_slice().parse::<usize>() { match settings.strategy_param.parse::<usize>() {
Ok(a) => a, Ok(a) => a,
Err(e) => crash!(1, "invalid number of bytes: {}", e) Err(e) => crash!(1, "invalid number of bytes: {}", e)
} }
@ -199,22 +201,22 @@ impl ByteSplitter {
impl Splitter for ByteSplitter { impl Splitter for ByteSplitter {
fn consume(&mut self, control: &mut SplitControl) -> String { fn consume(&mut self, control: &mut SplitControl) -> String {
let line = control.current_line.clone(); let line = control.current_line.clone();
let n = std::cmp::min(line.as_slice().chars().count(), self.bytes_to_write); let n = std::cmp::min(line.chars().count(), self.bytes_to_write);
if self.require_whole_line && n < line.as_slice().chars().count() { if self.require_whole_line && n < line.chars().count() {
self.bytes_to_write = self.saved_bytes_to_write; self.bytes_to_write = self.saved_bytes_to_write;
control.request_new_file = true; control.request_new_file = true;
self.require_whole_line = false; self.require_whole_line = false;
return line.as_slice()[0..0].to_string(); return line[0..0].to_string();
} }
self.bytes_to_write -= n; self.bytes_to_write -= n;
if n == 0 { if n == 0 {
self.bytes_to_write = self.saved_bytes_to_write; self.bytes_to_write = self.saved_bytes_to_write;
control.request_new_file = true; control.request_new_file = true;
} }
if self.break_on_line_end && n == line.as_slice().chars().count() { if self.break_on_line_end && n == line.chars().count() {
self.require_whole_line = self.break_on_line_end; self.require_whole_line = self.break_on_line_end;
} }
line.as_slice()[..n].to_string() line[..n].to_string()
} }
} }
@ -225,7 +227,7 @@ fn str_prefix(i: usize, width: usize) -> String {
let mut w = width; let mut w = width;
while w > 0 { while w > 0 {
w -= 1; w -= 1;
let div = Int::pow(26 as usize, w as u32); let div = 26usize.pow(w as u32);
let r = n / div; let r = n / div;
n -= r * div; n -= r * div;
c.push(char::from_u32((r as u32) + 97).unwrap()); c.push(char::from_u32((r as u32) + 97).unwrap());
@ -240,7 +242,7 @@ fn num_prefix(i: usize, width: usize) -> String {
let mut w = width; let mut w = width;
while w > 0 { while w > 0 {
w -= 1; w -= 1;
let div = Int::pow(10 as usize, w as u32); let div = 10usize.pow(w as u32);
let r = n / div; let r = n / div;
n -= r * div; n -= r * div;
c.push(char::from_digit(r as u32, 10).unwrap()); c.push(char::from_digit(r as u32, 10).unwrap());
@ -249,20 +251,20 @@ fn num_prefix(i: usize, width: usize) -> String {
} }
fn split(settings: &Settings) -> i32 { fn split(settings: &Settings) -> i32 {
let mut reader = io::BufferedReader::new( let mut reader = BufReader::new(
if settings.input.as_slice() == "-" { if settings.input == "-" {
Box::new(io::stdio::stdin_raw()) as Box<Reader> Box::new(stdin()) as Box<Read>
} else { } else {
let r = match io::File::open(&Path::new(settings.input.clone())) { let r = match File::open(Path::new(&settings.input)) {
Ok(a) => a, Ok(a) => a,
Err(_) => crash!(1, "cannot open '{}' for reading: No such file or directory", settings.input) Err(_) => crash!(1, "cannot open '{}' for reading: No such file or directory", settings.input)
}; };
Box::new(r) as Box<Reader> Box::new(r) as Box<Read>
} }
); );
let mut splitter: Box<Splitter> = let mut splitter: Box<Splitter> =
match settings.strategy.as_slice() { match settings.strategy.as_ref() {
"l" => LineSplitter::new(settings), "l" => LineSplitter::new(settings),
"b" | "C" => ByteSplitter::new(settings), "b" | "C" => ByteSplitter::new(settings),
a @ _ => crash!(1, "strategy {} not supported", a) a @ _ => crash!(1, "strategy {} not supported", a)
@ -273,29 +275,29 @@ fn split(settings: &Settings) -> i32 {
request_new_file: true, // Request new file request_new_file: true, // Request new file
}; };
let mut writer = io::BufferedWriter::new(Box::new(io::stdio::stdout_raw()) as Box<Writer>); let mut writer = BufWriter::new(Box::new(stdout()) as Box<Write>);
let mut fileno = 0; let mut fileno = 0;
loop { loop {
if control.current_line.as_slice().chars().count() == 0 { if control.current_line.chars().count() == 0 {
match reader.read_line() { match reader.read_line(&mut control.current_line) {
Ok(a) => { control.current_line = a; } Ok(0) | Err(_) => break,
Err(_) => { break; } _ => {}
} }
} }
if control.request_new_file { if control.request_new_file {
let mut filename = settings.prefix.to_string(); let mut filename = settings.prefix.clone();
filename.push_str(if settings.numeric_suffix { filename.push_str(if settings.numeric_suffix {
num_prefix(fileno, settings.suffix_length) num_prefix(fileno, settings.suffix_length)
} else { } else {
str_prefix(fileno, settings.suffix_length) str_prefix(fileno, settings.suffix_length)
}.as_slice()); }.as_ref());
if fileno != 0 { if fileno != 0 {
crash_if_err!(1, writer.flush()); crash_if_err!(1, writer.flush());
} }
fileno += 1; fileno += 1;
writer = io::BufferedWriter::new(Box::new(io::File::open_mode(&Path::new(filename.as_slice()), io::Open, io::Write)) as Box<Writer>); writer = BufWriter::new(Box::new(OpenOptions::new().write(true).create(true).open(Path::new(&filename)).unwrap()) as Box<Write>);
control.request_new_file = false; control.request_new_file = false;
if settings.verbose { if settings.verbose {
println!("creating file '{}'", filename); println!("creating file '{}'", filename);
@ -303,11 +305,11 @@ fn split(settings: &Settings) -> i32 {
} }
let consumed = splitter.consume(&mut control); let consumed = splitter.consume(&mut control);
crash_if_err!(1, writer.write_str(consumed.as_slice())); crash_if_err!(1, writer.write_all(consumed.as_bytes()));
let advance = consumed.as_slice().chars().count(); let advance = consumed.chars().count();
let clone = control.current_line.clone(); let clone = control.current_line.clone();
let sl = clone.as_slice(); let sl = clone;
control.current_line = sl[advance..sl.chars().count()].to_string(); control.current_line = sl[advance..sl.chars().count()].to_string();
} }
0 0