Merge branch 'hru' (closes #33)
This commit is contained in:
		
						commit
						e6b1db3f40
					
				
							
								
								
									
										9
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								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 | ||||
|  | ||||
							
								
								
									
										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