coreutils/fold/fold.rs

201 lines
6.9 KiB
Rust
Raw Normal View History

2014-03-31 16:40:21 +00:00
#![crate_id(name = "fold", vers = "1.0.0", author = "Arcterus")]
2014-03-27 01:34:58 +00:00
/*
* This file is part of the uutils coreutils package.
*
* (c) Arcterus <arcterus@mail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
2014-03-31 16:40:21 +00:00
#![feature(macro_rules)]
2014-03-27 01:34:58 +00:00
extern crate getopts;
extern crate libc;
2014-03-27 01:34:58 +00:00
use std::io;
use std::io::fs::File;
use std::io::BufferedReader;
use std::os;
use std::uint;
#[path = "../common/util.rs"]
mod util;
static NAME: &'static str = "fold";
static VERSION: &'static str = "1.0.0";
#[allow(dead_code)]
fn main() { os::set_exit_status(uumain(os::args())); }
2014-05-28 11:43:37 +00:00
pub fn uumain(args: Vec<String>) -> int {
2014-03-27 01:34:58 +00:00
let (args, obs_width) = handle_obsolete(args.as_slice());
2014-05-16 08:32:58 +00:00
let program = args.get(0).clone();
2014-03-27 01:34:58 +00:00
let opts = [
getopts::optflag("b", "bytes", "count using bytes rather than columns (meaning control characters such as newline are not treated specially)"),
getopts::optflag("s", "spaces", "break lines at word boundaries rather than a hard cut-off"),
getopts::optopt("w", "width", "set WIDTH as the maximum line width rather than 80", "WIDTH"),
getopts::optflag("h", "help", "display this help and exit"),
getopts::optflag("V", "version", "output version information and exit")
];
let matches = match getopts::getopts(args.tail(), opts) {
Ok(m) => m,
2014-06-15 10:50:40 +00:00
Err(f) => crash!(1, "{}", f)
2014-03-27 01:34:58 +00:00
};
if matches.opt_present("h") {
println!("{} v{}", NAME, VERSION);
println!("");
println!("Usage:");
println!(" {} [OPTION]... [FILE]...", program);
println!("");
print!("{}", getopts::usage("Writes each file (or standard input if no files are given) to standard output whilst breaking long lines", opts));
} else if matches.opt_present("V") {
println!("{} v{}", NAME, VERSION);
} else {
let bytes = matches.opt_present("b");
let spaces = matches.opt_present("s");
let poss_width =
if matches.opt_present("w") {
matches.opt_str("w")
} else {
2014-05-17 10:32:14 +00:00
match obs_width {
2014-05-28 06:33:39 +00:00
Some(v) => Some(v.to_string()),
2014-05-17 10:32:14 +00:00
None => None,
}
2014-03-27 01:34:58 +00:00
};
let width = match poss_width {
Some(inp_width) => match uint::parse_bytes(inp_width.as_bytes(), 10) {
Some(width) => width,
None => crash!(1, "illegal width value (\"{}\")", inp_width)
},
None => 80
};
2014-05-07 23:55:53 +00:00
let files = if matches.free.is_empty() {
2014-05-28 06:33:39 +00:00
vec!("-".to_string())
2014-05-07 23:55:53 +00:00
} else {
matches.free
};
fold(files, bytes, spaces, width);
2014-03-27 01:34:58 +00:00
}
0
2014-03-27 01:34:58 +00:00
}
2014-05-25 09:20:52 +00:00
fn handle_obsolete(args: &[String]) -> (Vec<String>, Option<String>) {
let mut args = Vec::<String>::from_slice(args);
2014-03-27 01:34:58 +00:00
let mut i = 0;
while i < args.len() {
2014-05-23 12:28:40 +00:00
if args.get(i).as_slice().char_at(0) == '-' && args.get(i).len() > 1 && args.get(i).as_slice().char_at(1).is_digit() {
return (args.clone(),
2014-05-28 06:33:39 +00:00
Some(args.remove(i).unwrap().as_slice().slice_from(1).to_string()));
2014-03-27 01:34:58 +00:00
}
i += 1;
}
2014-05-23 12:28:40 +00:00
(args, None)
2014-03-27 01:34:58 +00:00
}
2014-05-25 09:20:52 +00:00
fn fold(filenames: Vec<String>, bytes: bool, spaces: bool, width: uint) {
2014-05-07 23:55:53 +00:00
for filename in filenames.iter() {
2014-05-17 10:32:14 +00:00
let filename: &str = filename.as_slice();
2014-05-07 23:55:53 +00:00
let buffer = BufferedReader::new(
2014-05-23 12:28:40 +00:00
if filename == "-" {
2014-05-09 00:12:57 +00:00
box io::stdio::stdin_raw() as Box<Reader>
2014-05-07 23:55:53 +00:00
} else {
2014-05-09 00:12:57 +00:00
box safe_unwrap!(File::open(&Path::new(filename))) as Box<Reader>
2014-05-07 23:55:53 +00:00
}
);
fold_file(buffer, bytes, spaces, width);
2014-03-27 01:34:58 +00:00
}
}
fn fold_file<T: io::Reader>(file: BufferedReader<T>, bytes: bool, spaces: bool, width: uint) {
let mut file = file;
for line in file.lines() {
let line = safe_unwrap!(line);
2014-03-27 01:34:58 +00:00
if line.len() == 1 {
println!("");
continue;
}
2014-05-23 12:28:40 +00:00
let line = line.as_slice().slice_to(line.len() - 1);
2014-03-27 01:34:58 +00:00
if bytes {
let mut i = 0;
while i < line.len() {
let width = if line.len() - i >= width { width } else { line.len() - i };
let slice = {
let slice = line.slice(i, i + width);
if spaces && i + width != line.len() {
match slice.rfind(|ch: char| ch.is_whitespace()) {
Some(m) => slice.slice_to(m + 1),
None => slice
}
} else {
slice
}
};
println!("{}", slice);
i += slice.len();
}
} else {
2014-05-25 09:20:52 +00:00
let mut output = String::new();
2014-03-27 01:34:58 +00:00
let mut count = 0;
for (i, ch) in line.chars().enumerate() {
match ch {
'\t' => {
count += 8;
if count > width {
println!("{}", output.as_slice());
output.truncate(0);
2014-03-27 01:34:58 +00:00
count = 8;
}
}
'\x08' => {
if count > 0 {
count -= 1;
let len = output.len() - 1;
output.truncate(len);
2014-03-27 01:34:58 +00:00
}
continue;
}
'\r' => {
output.truncate(0);
2014-03-27 01:34:58 +00:00
count = 0;
continue;
}
_ => count += 1
};
output.push_char(ch);
if count == width {
let (val, ncount) = {
let slice = output.as_slice();
2014-03-27 01:34:58 +00:00
let (out, val, ncount) =
if spaces && i + 1 != line.len() {
match slice.rfind(|ch: char| ch.is_whitespace()) {
2014-03-27 01:34:58 +00:00
Some(m) => {
2014-05-28 06:33:39 +00:00
let routput = slice.slice_from(m + 1).to_string();
2014-05-23 12:28:40 +00:00
let ncount = routput.as_slice().chars().fold(0, |out, ch: char| out + if ch == '\t' { 8 } else { 1 });
(slice.slice_to(m + 1), routput, ncount)
2014-03-27 01:34:58 +00:00
},
2014-05-28 06:33:39 +00:00
None => (slice, "".to_string(), 0)
2014-03-27 01:34:58 +00:00
}
} else {
2014-05-28 06:33:39 +00:00
(slice, "".to_string(), 0)
2014-03-27 01:34:58 +00:00
};
println!("{}", out);
(val, ncount)
};
2014-05-28 06:33:39 +00:00
output = val.into_string();
2014-03-27 01:34:58 +00:00
count = ncount;
}
}
if count > 0 {
println!("{}", output);
}
}
}
}