260 lines
6.9 KiB
Rust
260 lines
6.9 KiB
Rust
#[derive(Copy, Clone)]
|
|
enum HowUnits {
|
|
SeparateUnits,
|
|
BiggestUnit,
|
|
Both,
|
|
}
|
|
|
|
#[derive(Copy, Clone)]
|
|
enum HowNumberBase {
|
|
Decimal,
|
|
Hex,
|
|
Both,
|
|
}
|
|
|
|
fn hex_float(h: f64) -> String {
|
|
let neg = h.is_sign_negative();
|
|
let mut h = h.abs();
|
|
let mut e = 0;
|
|
while h.fract() != 0.0 {
|
|
h *= 16.0;
|
|
e += 1;
|
|
}
|
|
|
|
let mut h = h as usize;
|
|
let mut output = String::new();
|
|
|
|
if e == 0 {
|
|
output.push('0');
|
|
output.push('.');
|
|
}
|
|
|
|
let mut num_divides = 0;
|
|
while h > 0 {
|
|
output.push(match h % 16 {
|
|
0 => '0',
|
|
1 => '1',
|
|
2 => '2',
|
|
3 => '3',
|
|
4 => '4',
|
|
5 => '5',
|
|
6 => '6',
|
|
7 => '7',
|
|
8 => '8',
|
|
9 => '9',
|
|
10 => 'A',
|
|
11 => 'B',
|
|
12 => 'C',
|
|
13 => 'D',
|
|
14 => 'E',
|
|
15 => 'F',
|
|
_ => unreachable![],
|
|
});
|
|
h /= 16;
|
|
num_divides += 1;
|
|
if num_divides == e {
|
|
output.push('.');
|
|
}
|
|
}
|
|
|
|
if neg {
|
|
output.push('-');
|
|
}
|
|
|
|
output.chars().rev().collect()
|
|
}
|
|
|
|
#[test]
|
|
fn test_hex_float() {
|
|
assert_eq!["1.8", hex_float(1.5)];
|
|
}
|
|
|
|
fn separate_units(n: usize, how_base: HowNumberBase) -> String {
|
|
let peta = n / 1024usize.pow(5);
|
|
let n = n - peta * 1024usize.pow(5);
|
|
let tera = n / 1024usize.pow(4);
|
|
let n = n - tera * 1024usize.pow(4);
|
|
let giga = n / 1024usize.pow(3);
|
|
let n = n - giga * 1024usize.pow(3);
|
|
let mega = n / 1024usize.pow(2);
|
|
let n = n - mega * 1024usize.pow(2);
|
|
let kilo = n / 1024usize.pow(1);
|
|
let bytes = n - kilo * 1024usize.pow(1);
|
|
match how_base {
|
|
HowNumberBase::Decimal => format![
|
|
"{peta} petabytes\n{tera} terabytes\n{giga} gigabytes\n{mega} megabytes\n{kilo} kilobytes\n{bytes} bytes"
|
|
],
|
|
HowNumberBase::Hex => format![
|
|
"0x{peta:X} petabytes\n0x{tera:X} terabytes\n0x{giga:X} gigabytes\n0x{mega:X} megabytes\n0x{kilo:X} kilobytes\n0x{bytes:X} bytes"
|
|
],
|
|
HowNumberBase::Both => format![
|
|
"0x{peta:X} ({peta}) petabytes\n0x{tera:X} ({tera}) terabytes\n0x{giga:X} ({giga}) gigabytes\n0x{mega:X} ({mega}) megabytes\n0x{kilo:X} ({kilo}) kilobytes\n0x{bytes:X} ({bytes}) bytes"
|
|
],
|
|
}
|
|
}
|
|
|
|
fn biggest_unit(n: usize, how_base: HowNumberBase) -> String {
|
|
let mut biggest = 0;
|
|
let mut unit_val = 0;
|
|
for e in (0..6).rev() {
|
|
unit_val = n / 1024usize.pow(e);
|
|
if unit_val > 0 {
|
|
biggest = e;
|
|
break;
|
|
}
|
|
}
|
|
let unit = format![
|
|
"{}{}",
|
|
match biggest {
|
|
0 => "byte",
|
|
1 => "kilobyte",
|
|
2 => "megabyte",
|
|
3 => "gigabyte",
|
|
4 => "terabyte",
|
|
5 => "petabyte",
|
|
_ => unreachable!(),
|
|
},
|
|
if unit_val != 1 { "s" } else { "" }
|
|
];
|
|
match how_base {
|
|
HowNumberBase::Decimal => format!["{} {}", n as f64 / 1024.0f64.powf(biggest as f64), unit],
|
|
HowNumberBase::Hex => format![
|
|
"0x{} {}",
|
|
hex_float(n as f64 / 1024.0f64.powf(biggest as f64)),
|
|
unit
|
|
],
|
|
HowNumberBase::Both => format![
|
|
"0x{} ({}) {}",
|
|
hex_float(n as f64 / 1024.0f64.powf(biggest as f64)),
|
|
n as f64 / 1024.0f64.powf(biggest as f64),
|
|
unit
|
|
],
|
|
}
|
|
}
|
|
|
|
fn to_readable_units(n: usize, how_units: HowUnits, how_base: HowNumberBase) -> String {
|
|
match how_units {
|
|
HowUnits::SeparateUnits => separate_units(n, how_base),
|
|
HowUnits::BiggestUnit => biggest_unit(n, how_base),
|
|
HowUnits::Both => format![
|
|
"{}\n{}",
|
|
biggest_unit(n, how_base),
|
|
separate_units(n, how_base)
|
|
],
|
|
}
|
|
}
|
|
|
|
const USAGE: &str = "Usage: cntin [options]
|
|
Counts bytes in stdin.
|
|
Note: If both of a complementary set of options are specified, both are used.
|
|
options:
|
|
-d, --decimal Sets the output number base to decimal.
|
|
-h, --hex Sets the output number base to hexadecimal.
|
|
-s, --separate Displays all byte units.
|
|
-b, --biggest Displays the biggest unit.";
|
|
|
|
fn main() -> Result<(), std::io::Error> {
|
|
let args = std::env::args();
|
|
|
|
let mut how_units = HowUnits::BiggestUnit;
|
|
let mut how_base = HowNumberBase::Decimal;
|
|
|
|
let mut set_d = false;
|
|
let mut set_h = false;
|
|
let mut set_s = false;
|
|
let mut set_b = false;
|
|
for arg in args.skip(1) {
|
|
let arg = arg.trim();
|
|
if arg.starts_with('-') && !arg.starts_with("--") {
|
|
// It's a single dash option
|
|
for ch in arg.chars().skip(1) {
|
|
match ch {
|
|
'd' => {
|
|
set_d = true;
|
|
if set_h {
|
|
how_base = HowNumberBase::Both;
|
|
} else {
|
|
how_base = HowNumberBase::Decimal;
|
|
}
|
|
}
|
|
'h' => {
|
|
set_h = true;
|
|
if set_d {
|
|
how_base = HowNumberBase::Both;
|
|
} else {
|
|
how_base = HowNumberBase::Hex;
|
|
}
|
|
}
|
|
's' => {
|
|
set_s = true;
|
|
if set_b {
|
|
how_units = HowUnits::Both;
|
|
} else {
|
|
how_units = HowUnits::SeparateUnits;
|
|
}
|
|
}
|
|
'b' => {
|
|
set_b = true;
|
|
if set_s {
|
|
how_units = HowUnits::Both;
|
|
} else {
|
|
how_units = HowUnits::BiggestUnit;
|
|
}
|
|
}
|
|
_ => {
|
|
eprintln!["unknown option '{}'", ch];
|
|
eprint!["{}", USAGE];
|
|
return Ok(());
|
|
}
|
|
}
|
|
}
|
|
} else if arg == "--biggest" {
|
|
set_b = true;
|
|
if set_s {
|
|
how_units = HowUnits::Both;
|
|
} else {
|
|
how_units = HowUnits::BiggestUnit;
|
|
}
|
|
} else if arg == "--separate" {
|
|
set_s = true;
|
|
if set_b {
|
|
how_units = HowUnits::Both;
|
|
} else {
|
|
how_units = HowUnits::BiggestUnit;
|
|
}
|
|
} else if arg == "--decimal" {
|
|
set_d = true;
|
|
if set_h {
|
|
how_base = HowNumberBase::Both;
|
|
} else {
|
|
how_base = HowNumberBase::Decimal;
|
|
}
|
|
} else if arg == "--hex" {
|
|
set_h = true;
|
|
if set_d {
|
|
how_base = HowNumberBase::Both;
|
|
} else {
|
|
how_base = HowNumberBase::Decimal;
|
|
}
|
|
} else if arg == "--help" {
|
|
eprintln!["{}", USAGE];
|
|
return Ok(());
|
|
} else {
|
|
eprintln!["unknown argument: {}", arg];
|
|
eprint!["{}", USAGE];
|
|
return Ok(());
|
|
}
|
|
}
|
|
if atty::is(atty::Stream::Stdin) {
|
|
return Ok(());
|
|
}
|
|
let std_out = std::io::stdout();
|
|
let mut n = 0usize;
|
|
while let Some(Ok(byte)) = std::io::Read::bytes(std::io::stdin()).next() {
|
|
n += 1;
|
|
std::io::Write::write(&mut std_out.lock(), &[byte])?;
|
|
}
|
|
eprintln!["{}", to_readable_units(n, how_units, how_base)];
|
|
Ok(())
|
|
}
|