Merge branch 'hru' (closes #33)
This commit is contained in:
		
						commit
						e6b1db3f40
					
				
							
								
								
									
										9
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								Makefile
									
									
									
									
									
								
							@ -17,7 +17,7 @@ CC=cc
 | 
				
			|||||||
RUSTC=rustc
 | 
					RUSTC=rustc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.PHONY: all
 | 
					.PHONY: all
 | 
				
			||||||
all: dj false fop intcmp rpn scrut str strcmp true
 | 
					all: dj false fop hru intcmp rpn scrut str strcmp true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
build:
 | 
					build:
 | 
				
			||||||
	# keep build/include until bindgen(1) has stdin support
 | 
						# 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 \
 | 
							--extern sysexits=build/o/libsysexits.rlib \
 | 
				
			||||||
		-o $@ src/fop.rs
 | 
							-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
 | 
					.PHONY: intcmp
 | 
				
			||||||
intcmp: build/bin/intcmp
 | 
					intcmp: build/bin/intcmp
 | 
				
			||||||
build/bin/intcmp: src/intcmp.c build
 | 
					build/bin/intcmp: src/intcmp.c build
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										57
									
								
								docs/hru.1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								docs/hru.1
									
									
									
									
									
										Normal 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 project’s 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 GNU’s 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
									
								
							
							
						
						
									
										107
									
								
								src/hru.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,107 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) 2023–2024 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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user