mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-31 13:07:46 +00:00
commit
df27f5035c
1 changed files with 36 additions and 34 deletions
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue