Initial commit

This commit is contained in:
Nathan Fisher 2025-01-12 18:49:06 -05:00
commit c387ea0685
4 changed files with 167 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

31
Cargo.lock generated Normal file
View file

@ -0,0 +1,31 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "b32"
version = "0.1.0"
source = "git+https://git.hitchhiker-linux.org/jeang3nie/b32_rs.git#8ceaeff9b70aec6d271ba5f1be45d2c42e2894c3"
[[package]]
name = "base32"
version = "0.1.0"
dependencies = [
"b32",
"getopts",
]
[[package]]
name = "getopts"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
dependencies = [
"unicode-width",
]
[[package]]
name = "unicode-width"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"

14
Cargo.toml Normal file
View file

@ -0,0 +1,14 @@
[package]
name = "base32"
version = "0.1.0"
edition = "2021"
[dependencies]
b32 = { git = "https://git.hitchhiker-linux.org/jeang3nie/b32_rs.git" }
getopts = "0.2"
[profile.release]
lto = true
codegen-units = 1
strip = true

121
src/main.rs Normal file
View file

@ -0,0 +1,121 @@
use {
b32::{Decoder, Encoder},
getopts::Options,
std::{
env,
error::Error,
fs::File,
io::{self, BufReader, BufWriter, Write},
os::fd::AsFd,
path::Path
}
};
#[derive(PartialEq)]
enum Operation {
Encode,
Decode,
}
enum Input {
Stdin,
Filename(String),
}
fn print_usage(program: &str, opts: Options) {
let brief = format!("Usage: {} FILE [options]", program);
print!("{}", opts.usage(&brief));
}
fn main() -> Result<(), Box<dyn Error>> {
let args = env::args().collect::<Vec<String>>();
let progname = Path::new(&args[0])
.file_name()
.map(|x| x.to_string_lossy())
.unwrap();
let mut opts = Options::new();
opts.optflag("h", "help", "print this help message");
opts.optflag("d", "decode", "decode instead of encoding");
opts.optflag("i", "ignore", "ignore whitespace when decoding");
opts.optopt("o", "output", "output to FILE instead of STDOUT", "FILE");
opts.optflag("q", "quiet", "never print headers giving file names");
opts.optflag("v", "verbose", "always print headers giving file names");
opts.optopt("w", "wrap", "wrap at columns", "COLS");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => {
panic!("{}", f.to_string())
}
};
if matches.opt_present("h") {
print_usage(&progname, opts);
return Ok(());
}
let op = if matches.opt_present("d") {
Operation::Decode
} else {
Operation::Encode
};
let ignore = matches.opt_present("i");
let wrap: usize = if let Some(w) = matches.opt_str("w") {
w.parse()?
} else {
76
};
let mut infiles = matches
.free
.iter()
.map(|x| {
if x == "-" {
Input::Stdin
} else {
Input::Filename(x.to_string())
}
})
.collect::<Vec<_>>();
if infiles.is_empty() {
infiles.push(Input::Stdin)
}
if matches.opt_present("q") && matches.opt_present("v") {
eprintln!("Error: conflicting options \"verbose\" and \"quiet\" are both present.");
print_usage(&progname, opts);
return Err("Conflicting options".into());
}
let verbose = matches.opt_present("v") || (matches.free.len() > 1 && !matches.opt_present("q"));
for f in &infiles {
let mut writer = if let Some(o) = matches.opt_str("o") {
if matches.free.len() < 2 || op == Operation::Encode {
BufWriter::new(File::open(o)?)
} else {
panic!("Attempt to decode multiple files into single file");
}
} else {
BufWriter::new(File::from(io::stdout().as_fd().try_clone_to_owned()?))
};
let reader = match f {
Input::Stdin => BufReader::new(File::from(io::stdin().as_fd().try_clone_to_owned()?)),
Input::Filename(f) => BufReader::new(File::open(f)?),
};
if verbose {
let fname = match f {
Input::Stdin => "Stdin",
Input::Filename(f) => f,
};
writer.write_fmt(format_args!("==> {fname} <==\n"))?;
}
match op {
Operation::Decode => {
let decoder = Decoder::new(reader, writer, None, ignore);
decoder.decode()?;
}
Operation::Encode => {
let mut encoder = Encoder::new(reader, writer, None, Some(wrap));
encoder.encode()?;
encoder.output().write_all(&[b'\n'])?;
}
}
}
Ok(())
}