This commit is contained in:
Mike Cugini 2021-03-16 00:25:29 -04:00
parent 84c926b8fa
commit 107e692081

View File

@ -15,19 +15,17 @@
use std::error::Error; use std::error::Error;
use std::fs::File; use std::fs::File;
use std::io::{self, BufReader};
use std::io::prelude::*; use std::io::prelude::*;
use std::io::{self, BufReader};
use argh::FromArgs; use argh::FromArgs;
#[derive(FromArgs)] #[derive(FromArgs)]
#[argh( #[argh(description = "\
description = "\
chop off bits of file\n\n\ chop off bits of file\n\n\
chop will take produce --count files of --lines lines from the beginning of a\n\ chop will take produce --count files of --lines lines from the beginning of a\n\
file or stdin. Any remaining lines will be written to a final catchall file.")] file or stdin. Any remaining lines will be written to a final catchall file.")]
struct Options { struct Options {
/// number of lines in each chunk /// number of lines in each chunk
#[argh(option, short = 'n')] #[argh(option, short = 'n')]
lines: usize, lines: usize,
@ -40,19 +38,17 @@ struct Options {
#[argh(option, short = 'p', default = "String::from(\"\")")] #[argh(option, short = 'p', default = "String::from(\"\")")]
prefix: String, prefix: String,
/// use numeric suffixes starting with 0, not alphabetic /// use numeric suffixes starting with 0, not alphabetic
#[argh(switch, short = 'd')] #[argh(switch, short = 'd')]
numeric: bool, numeric: bool,
/// use numeric suffixes starting with 0, not alphabetic /// use numeric suffixes starting with 0, not alphabetic
#[argh(option, long = "numeric-start", default = "0")] #[argh(option, long = "numeric-start", default = "0")]
numeric_start: usize, numeric_start: usize,
/// filename to read from, or "-" for stdin (default "-") /// filename to read from, or "-" for stdin (default "-")
#[argh(positional, default = "String::from(\"-\")")] #[argh(positional, default = "String::from(\"-\")")]
filename: String, filename: String,
} }
struct AlphabeticSuffixGenerator { struct AlphabeticSuffixGenerator {
@ -63,12 +59,15 @@ struct AlphabeticSuffixGenerator {
impl AlphabeticSuffixGenerator { impl AlphabeticSuffixGenerator {
fn new(count: usize) -> AlphabeticSuffixGenerator { fn new(count: usize) -> AlphabeticSuffixGenerator {
// given 27 letters, minimum number of digits is floor( Log 27 (count) + 1 ) // given 27 letters, minimum number of digits is floor( Log 27 (count) + 1 )
let suffix_length = ((count as f64).log(27f64) + 1.0).floor() as usize; let suffix_length = ((count as f64).log(27f64) + 1.0).floor() as usize;
let mut suffix = vec![b'a'; suffix_length]; let mut suffix = vec![b'a'; suffix_length];
suffix[suffix_length-1] -= 1; suffix[suffix_length - 1] -= 1;
AlphabeticSuffixGenerator{suffix, remaining: count} AlphabeticSuffixGenerator {
suffix,
remaining: count,
}
} }
} }
@ -77,12 +76,12 @@ impl Iterator for AlphabeticSuffixGenerator {
fn next(&mut self) -> Option<String> { fn next(&mut self) -> Option<String> {
if self.remaining == 0 { if self.remaining == 0 {
return None return None;
} }
for idx in (0..self.suffix.len()).rev() { for idx in (0..self.suffix.len()).rev() {
if self.suffix[idx] < b'z' { if self.suffix[idx] < b'z' {
self.suffix[idx] += 1; self.suffix[idx] += 1;
break break;
} else { } else {
self.suffix[idx] = b'a'; self.suffix[idx] = b'a';
} }
@ -92,27 +91,26 @@ impl Iterator for AlphabeticSuffixGenerator {
} }
} }
fn try_main() -> Result<(), Box<dyn Error>> { fn try_main() -> Result<(), Box<dyn Error>> {
let opts: Options = argh::from_env(); let opts: Options = argh::from_env();
let input: Box<dyn Read> = match opts.filename.as_str() { let input: Box<dyn Read> = match opts.filename.as_str() {
"-" => Box::new(io::stdin()), "-" => Box::new(io::stdin()),
path => { path => match File::open(path) {
match File::open(path) { Err(why) => panic!("failed to open {}: {}", path, why),
Err(why) => panic!("failed to open {}: {}", path, why), Ok(file) => Box::new(file),
Ok(file) => Box::new(file), },
}
},
}; };
let prefix = match opts.prefix.as_str() { let prefix = match opts.prefix.as_str() {
"" => String::from(""), "" => String::from(""),
_ => opts.prefix + "_", _ => opts.prefix + "_",
}; };
let suffix_gen: Box<dyn Iterator<Item = String>> = if opts.numeric { let suffix_gen: Box<dyn Iterator<Item = String>> = if opts.numeric {
Box::new((opts.numeric_start..(opts.numeric_start + opts.count)).map(|num| format!("{}", num))) Box::new(
(opts.numeric_start..(opts.numeric_start + opts.count)).map(|num| format!("{}", num)),
)
} else { } else {
Box::new(AlphabeticSuffixGenerator::new(opts.count)) Box::new(AlphabeticSuffixGenerator::new(opts.count))
}; };
@ -126,8 +124,8 @@ fn try_main() -> Result<(), Box<dyn Error>> {
match reader.read_line(&mut line)? { match reader.read_line(&mut line)? {
0 => { 0 => {
eof = true; eof = true;
break break;
}, }
_ => { _ => {
out_file.write_all(line.as_bytes())?; out_file.write_all(line.as_bytes())?;
line.clear(); line.clear();
@ -140,10 +138,10 @@ fn try_main() -> Result<(), Box<dyn Error>> {
let mut out_file = File::create(format!("{}rest", prefix))?; let mut out_file = File::create(format!("{}rest", prefix))?;
for result in reader.lines() { for result in reader.lines() {
// lines() strips newline characters, so add one // lines() strips newline characters, so add one
out_file.write_all((result?+"\n").as_bytes())?; out_file.write_all((result? + "\n").as_bytes())?;
}; }
} }
Ok(()) Ok(())
} }