1
0
forked from bonsai/harakit
coreutils/src/hru.rs

110 lines
2.5 KiB
Rust
Raw Normal View History

2024-02-07 20:58:57 -07:00
/*
2024-02-07 21:42:43 -07:00
* Copyright (c) 20232024 Emma Tebibyte <emma@tebibyte.media>
2024-02-07 20:58:57 -07:00
* SPDX-License-Identifier: AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
use std::{
cmp::Ordering,
env::args,
2024-02-23 21:58:23 -07:00
io::{ stdin, stdout, Write },
process::{ ExitCode, exit },
2024-02-07 20:58:57 -07:00
};
2024-03-01 23:12:44 -07:00
extern crate strerror;
2024-02-07 20:58:57 -07:00
extern crate sysexits;
use strerror::raw_message;
2024-02-23 21:58:23 -07:00
use sysexits::{ EX_DATAERR, EX_IOERR, EX_SOFTWARE };
2024-02-07 20:58:57 -07:00
2024-02-14 00:07:06 -07:00
const LIST: [(u32, &str); 10] = [
2024-02-18 14:49:09 -07:00
(3, "k"),
2024-02-14 00:07:06 -07:00
(6, "M"),
(9, "G"),
(12, "T"),
(15, "P"),
(18, "E"),
(21, "Z"),
(24, "Y"),
(27, "R"),
(30, "Q")
];
2024-02-07 20:58:57 -07:00
2024-02-14 00:07:06 -07:00
fn convert(input: u128) -> Result<(f64, (u32, &'static str)), String> {
2024-02-13 17:32:31 -07:00
2024-02-14 00:07:06 -07:00
let mut out = (input as f64, (0_u32, ""));
if input < 1000 { return Ok(out); }
for (n, p) in LIST {
2024-02-13 23:56:01 -07:00
let c = match 10_u128.checked_pow(n) {
Some(c) => c,
None => {
2024-03-01 23:12:44 -07:00
return Err(format!("10^{}: Integer overflow", n.to_string()));
2024-02-13 23:56:01 -07:00
},
};
2024-02-13 17:32:31 -07:00
match c.cmp(&input) {
2024-02-07 20:58:57 -07:00
Ordering::Less => {
2024-02-14 00:07:06 -07:00
out = (input as f64 / c as f64, (n, p));
2024-02-07 20:58:57 -07:00
},
2024-02-13 17:32:31 -07:00
Ordering::Equal => {
2024-02-14 00:07:06 -07:00
return Ok((input as f64 / c as f64, (n, p)));
2024-02-07 20:58:57 -07:00
},
2024-02-13 17:32:31 -07:00
Ordering::Greater => {},
2024-02-07 20:58:57 -07:00
};
}
2024-02-13 23:56:01 -07:00
Ok(out)
2024-02-07 20:58:57 -07:00
}
2024-02-13 17:32:31 -07:00
fn main() -> ExitCode {
2024-02-07 20:58:57 -07:00
let argv = args().collect::<Vec<String>>();
let mut buf = String::new();
2024-02-13 17:48:25 -07:00
while let Ok(_) = stdin().read_line(&mut buf) {
if buf.is_empty() { return ExitCode::SUCCESS; }
2024-02-07 20:58:57 -07:00
2024-02-13 23:56:01 -07:00
let n: u128 = match buf.trim().parse() {
2024-02-13 17:48:25 -07:00
Ok(f) => {
buf.clear();
f
},
Err(err) => {
2024-03-01 23:12:44 -07:00
eprintln!("{}: {}", argv[0], err);
2024-02-13 17:48:25 -07:00
return ExitCode::from(EX_DATAERR as u8);
},
};
2024-02-07 20:58:57 -07:00
2024-02-13 23:56:01 -07:00
let (number, prefix) = match convert(n) {
Ok(x) => x,
Err(err) => {
2024-03-01 23:12:44 -07:00
eprintln!("{}: {}", argv[0], err);
2024-02-13 23:56:01 -07:00
return ExitCode::from(EX_SOFTWARE as u8);
},
};
2024-02-07 20:58:57 -07:00
2024-02-14 00:07:06 -07:00
let si_prefix = format!("{}B", prefix.1);
2024-02-07 20:58:57 -07:00
2024-02-13 17:48:25 -07:00
let out = ((number * 10.0).round() / 10.0).to_string();
2024-02-13 17:32:31 -07:00
2024-02-23 22:11:23 -07:00
stdout().write_all(format!("{} {}\n", out, si_prefix).as_bytes())
2024-02-23 21:58:23 -07:00
.unwrap_or_else(|e| {
eprintln!("{}: {}", argv[0], raw_message(e));
2024-02-23 21:58:23 -07:00
exit(EX_IOERR);
});
2024-02-13 17:48:25 -07:00
}
2024-02-13 17:32:31 -07:00
ExitCode::SUCCESS
2024-02-07 20:58:57 -07:00
}