13 Commits

Author SHA1 Message Date
e6b1db3f40 Merge branch 'hru' (closes #33) 2024-02-23 22:15:43 -07:00
ef1643660b hru(1): fixed lack of newline 2024-02-23 22:11:23 -07:00
bd08ef479c hru(1): error handling tweaks 2024-02-23 21:58:23 -07:00
ee3877b607 hru.1: update manpage to be more clear 2024-02-18 14:59:12 -07:00
0801d89128 hru(1): fixed kilo prefix 2024-02-18 14:49:09 -07:00
413ee49af4 hru.1: updated manpage with correct SI reference 2024-02-16 21:36:16 -07:00
361f0ddb8b hru.1: added manpage for hru(1) 2024-02-14 23:31:54 -07:00
e3a0069180 hru(1): improved SI prefix logic 2024-02-14 00:07:06 -07:00
1299aefc39 hru(1): fixed overflow 2024-02-13 23:56:01 -07:00
d0205b71da hru(1): read stdin until EOF 2024-02-13 17:48:25 -07:00
1ee668aed6 hru(1): made it actually work 2024-02-13 17:32:31 -07:00
fa686eefb9 hru(1): updated copyright year 2024-02-07 21:42:43 -07:00
be89e72c45 Makefile, hru(1): add hru(1) 2024-02-07 20:58:57 -07:00
3 changed files with 172 additions and 1 deletions

View File

@@ -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

57
docs/hru.1 Normal file
View File

@@ -0,0 +1,57 @@
.\" Copyright (c) 2024 Emma Tebibyte <emma@tebibyte.media>
.\"
.\" This work is licensed under CC BY-SA 4.0. To see a copy of this license,
.\" visit <http://creativecommons.org/licenses/by-sa/4.0/>.
.TH rpn 1
.SH NAME
hru \(en human readable units
.SH SYNOPSIS
hru
.SH DESCRIPTION
Hru reads byte counts in the form of whole numbers from the standard input and
writes to the standard output the same number converted one of the units of data
defined by the International System of Units.
The program will convert the byte count to the highest unit possible where the
value is greater than one.
.SH DIAGNOSTICS
If encountering non-integer characters in the standard input, hru will exit with
the appropriate error code as defined by sysexits.h(3) and print an error
message.
.SH RATIONALE
The GNU projects ls(1) implementation contains a human-readable option (-h)
that, when specified, makes the tool print size information in a format more
immediately readable. This functionality is useful not only in the context of
ls(1) so the decision was made to split it into a new tool. The original
functionality in GNUs ls(1) can be emulated with fop(1) combined with this
program.
.SH STANDARDS
Hru follows the standard unit prefixes as specified by the Bureau International
des Poids et Mesures (BIPM) in the ninth edition of The International System of
Units (SI).
.SH AUTHOR
Written by Emma Tebibyte <emma@tebibyte.media>.
.SH COPYRIGHT
Copyright (c) 2024 Emma Tebibyte. License AGPLv3+: GNU AGPL version 3 or later
<https://gnu.org/licenses/agpl.html>.
.SH SEE ALSO
GNU ls(1), The International System of Units (SI) 9th Edition

107
src/hru.rs Normal file
View File

@@ -0,0 +1,107 @@
/*
* Copyright (c) 20232024 Emma Tebibyte <emma@tebibyte.media>
* 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, stdout, Write },
process::{ ExitCode, exit },
};
extern crate sysexits;
use sysexits::{ EX_DATAERR, EX_IOERR, EX_SOFTWARE };
const LIST: [(u32, &str); 10] = [
(3, "k"),
(6, "M"),
(9, "G"),
(12, "T"),
(15, "P"),
(18, "E"),
(21, "Z"),
(24, "Y"),
(27, "R"),
(30, "Q")
];
fn convert(input: u128) -> Result<(f64, (u32, &'static str)), String> {
let mut out = (input as f64, (0_u32, ""));
if input < 1000 { return Ok(out); }
for (n, p) in LIST {
let c = match 10_u128.checked_pow(n) {
Some(c) => c,
None => {
return Err(format!("10^{}: Integer overflow.", n.to_string()));
},
};
match c.cmp(&input) {
Ordering::Less => {
out = (input as f64 / c as f64, (n, p));
},
Ordering::Equal => {
return Ok((input as f64 / c as f64, (n, p)));
},
Ordering::Greater => {},
};
}
Ok(out)
}
fn main() -> ExitCode {
let argv = args().collect::<Vec<String>>();
let mut buf = String::new();
while let Ok(_) = stdin().read_line(&mut buf) {
if buf.is_empty() { return ExitCode::SUCCESS; }
let n: u128 = match buf.trim().parse() {
Ok(f) => {
buf.clear();
f
},
Err(err) => {
eprintln!("{}: {}.", argv[0], err);
return ExitCode::from(EX_DATAERR as u8);
},
};
let (number, prefix) = match convert(n) {
Ok(x) => x,
Err(err) => {
eprintln!("{}: {}.", argv[0], err);
return ExitCode::from(EX_SOFTWARE as u8);
},
};
let si_prefix = format!("{}B", prefix.1);
let out = ((number * 10.0).round() / 10.0).to_string();
stdout().write_all(format!("{} {}\n", out, si_prefix).as_bytes())
.unwrap_or_else(|e| {
eprintln!("{}: {}.", argv[0], e);
exit(EX_IOERR);
});
}
ExitCode::SUCCESS
}