diff --git a/Makefile b/Makefile index 0f269f7..a21b126 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ CC=cc RUSTC=rustc .PHONY: all -all: dj false fop intcmp rpn scrut str strcmp true +all: dj false fop hru intcmp rpn scrut str strcmp true build: # keep build/include until bindgen(1) has stdin support @@ -74,6 +74,13 @@ build/bin/fop: src/fop.rs build build/o/libgetopt.rlib build/o/libsysexits.rlib --extern sysexits=build/o/libsysexits.rlib \ -o $@ src/fop.rs +.PHONY: hru +hru: build/bin/hru +build/bin/hru: src/hru.rs build build/o/libgetopt.rlib build/o/libsysexits.rlib + $(RUSTC) $(RUSTFLAGS) --extern getopt=build/o/libgetopt.rlib \ + --extern sysexits=build/o/libsysexits.rlib \ + -o $@ src/hru.rs + .PHONY: intcmp intcmp: build/bin/intcmp build/bin/intcmp: src/intcmp.c build diff --git a/src/hru.rs b/src/hru.rs new file mode 100644 index 0000000..c7b88af --- /dev/null +++ b/src/hru.rs @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2023 Emma Tebibyte + * 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, + io::stdin, + process::exit, +}; + +extern crate sysexits; + +use sysexits::EX_SOFTWARE; + +fn auto_c(input: u64) -> (u64, u32) { + let mut number = input; + let mut remainder = 0; + let mut exp: u32 = 0; + + if number % 10 > 0 { } + else { + while remainder == 0 { + number /= 10; + remainder = number % 10; + exp += 1; + } + } + + let list: Vec = vec![3, 6, 9, 12, 15, 18, 21, 24, 27, 30]; + let mut exps = list.iter().peekable(); + + while let Some(i) = exps.next() { + match exp.cmp(i) { + Ordering::Less => { + number = input; + break; + }, + Ordering::Equal => break, + Ordering::Greater => { + if let Some(p) = exps.peek() { + match exp.cmp(p) { + Ordering::Less => { + let exp_e = 10_u64.checked_pow(exp) + .unwrap_or_else(|| { exit(EX_SOFTWARE); }); + + let index_e = 10_u64.checked_pow(i.to_owned()) + .unwrap_or_else(|| { exit(EX_SOFTWARE); }); + + number *= exp_e / index_e; + exp = *i; + break; + }, + Ordering::Greater => continue, + _ => break, + }; + } + }, + }; + } + + (number, exp) +} + + +fn main() { + let argv = args().collect::>(); + let mut buf = String::new(); + let _ = stdin().read_line(&mut buf); + + let n: u64 = match buf.trim().parse() { + Ok(f) => f, + Err(err) => { + eprintln!("{}: {}", argv[0], err); + exit(1); + }, + }; + + let (number, prefix) = auto_c(n); + + let si_prefix = format!("{}B", match prefix { + 3 => "K", + 6 => "M", + 9 => "G", + 12 => "T", + 15 => "P", + 18 => "E", + 21 => "Z", + 24 => "Y", + 27 => "R", + 30 => "Q", + _ => "", + }); + + println!("{} {}", number.to_string(), si_prefix); +}