Merge branch 'swab' (closes #22)
This commit is contained in:
		
						commit
						05b5a4480c
					
				
							
								
								
									
										9
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								Makefile
									
									
									
									
									
								
							| @ -17,7 +17,7 @@ CC=cc | ||||
| RUSTC=rustc | ||||
| 
 | ||||
| .PHONY: all | ||||
| all: dj false fop hru intcmp rpn scrut str strcmp true | ||||
| all: dj false fop hru intcmp rpn scrut str strcmp swab true | ||||
| 
 | ||||
| build: | ||||
| 	# keep build/include until bindgen(1) has stdin support | ||||
| @ -108,6 +108,13 @@ strcmp: build/bin/strcmp | ||||
| build/bin/strcmp: src/strcmp.c build | ||||
| 	$(CC) $(CFLAGS) -o $@ src/strcmp.c | ||||
| 
 | ||||
| .PHONY: swab | ||||
| swab: build/bin/swab | ||||
| build/bin/swab: src/swab.rs build build/o/libsysexits.rlib | ||||
| 	$(RUSTC) $(RUSTFLAGS) --extern getopt=build/o/libgetopt.rlib \
 | ||||
| 		--extern sysexits=build/o/libsysexits.rlib \
 | ||||
| 		-o $@ src/swab.rs | ||||
| 
 | ||||
| .PHONY: true | ||||
| true: build/bin/true | ||||
| build/bin/true: src/true.c build | ||||
|  | ||||
							
								
								
									
										71
									
								
								docs/swab.1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								docs/swab.1
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,71 @@ | ||||
| .\" Copyright (c) 2024 DTB <trinity@trinity.moe> | ||||
| .\" | ||||
| .\" 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 swab 1 | ||||
| 
 | ||||
| .SH NAME | ||||
| 
 | ||||
| swab \(en swap bytes | ||||
| 
 | ||||
| .SH SYNOPSIS | ||||
| 
 | ||||
| swab | ||||
| .RB ( -f ) | ||||
| .RB ( -w | ||||
| .R [ | ||||
| .B word size | ||||
| .R ]) | ||||
| 
 | ||||
| .SH USAGE | ||||
| 
 | ||||
| Swab swaps the latter and former halves of a block of bytes. | ||||
| 
 | ||||
| .SH EXAMPLES | ||||
| 
 | ||||
| The following sh(1p) line: | ||||
| 
 | ||||
| .R printf 'hello world!\n' | swab | ||||
| 
 | ||||
| Produces the following output: | ||||
| 
 | ||||
| .R ehll oowlr!d | ||||
| 
 | ||||
| .SH OPTIONS | ||||
| 
 | ||||
| The | ||||
| .B -f | ||||
| option ignores system call interruptions. | ||||
| .PP | ||||
| The | ||||
| .B -w | ||||
| option configures the word size; that is, the size in bytes of the block size | ||||
| on which to operate. By default the word size is 2. The word size must be | ||||
| cleanly divisible by 2, otherwise the block of bytes being processed can't be | ||||
| halved. | ||||
| 
 | ||||
| .SH DIAGNOSTICS | ||||
| 
 | ||||
| If an error is encountered in input, output, or invocation, a diagnostic | ||||
| message will be written to standard error and swab will exit with the | ||||
| appropriate status from sysexits.h(3). | ||||
| 
 | ||||
| .SH RATIONALE | ||||
| 
 | ||||
| Swab was modeled after the | ||||
| .R conv=swab | ||||
| functionality specified in the POSIX dd utility but additionally allows the | ||||
| word size to be configured. | ||||
| .PP | ||||
| Swab is useful for fixing the endianness of binary files produced on other | ||||
| machines. | ||||
| 
 | ||||
| .SH COPYRIGHT | ||||
| 
 | ||||
| Copyright (c) 2024 DTB. License AGPLv3+: GNU AGPL version 3 or later | ||||
| <https://gnu.org/licenses/agpl.html>. | ||||
| 
 | ||||
| .SH SEE ALSO | ||||
| 
 | ||||
| dd(1p) | ||||
							
								
								
									
										90
									
								
								src/swab.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								src/swab.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,90 @@ | ||||
| /* | ||||
|  * Copyright (c) 2024 DTB <trinity@trinity.moe> | ||||
|  * 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::{ | ||||
| 	env::args, | ||||
| 	io::{ stdin, stdout, Error, ErrorKind, Read, Write }, | ||||
| 	process::ExitCode, | ||||
| 	vec::Vec | ||||
| }; | ||||
| 
 | ||||
| extern crate getopt; | ||||
| use getopt::{ Opt, Parser }; | ||||
| 
 | ||||
| extern crate sysexits; | ||||
| use sysexits::{ EX_OK, EX_OSERR, EX_USAGE }; | ||||
| 
 | ||||
| fn oserr(s: &str, e: Error) -> ExitCode { | ||||
| 	eprintln!("{}: {}", s, e); | ||||
| 	ExitCode::from(EX_OSERR as u8) | ||||
| } | ||||
| 
 | ||||
| fn usage(s: &str) -> ExitCode { | ||||
| 	eprintln!("Usage: {} (-f) (-w [wordsize])", s); | ||||
| 	ExitCode::from(EX_USAGE as u8) | ||||
| } | ||||
| 
 | ||||
| fn main() -> ExitCode { | ||||
| 	let argv = args().collect::<Vec<String>>(); | ||||
| 	let mut buf: Vec<u8> = Vec::new(); | ||||
| 	let mut input = stdin(); | ||||
| 	let mut output = stdout().lock(); | ||||
| 
 | ||||
| 	let mut opts = Parser::new(&argv, "fw:"); | ||||
| 	let mut force = false; | ||||
| 	let mut wordsize: usize = 2; | ||||
| 
 | ||||
| 	loop { | ||||
| 		match opts.next() { | ||||
| 			None => break, | ||||
| 			Some(opt) => | ||||
| 				match opt { | ||||
| 					Ok(Opt('f', None)) => force = true, | ||||
| 					Ok(Opt('w', Some(arg))) => { | ||||
| 						match arg.parse::<usize>() { | ||||
| 							Ok(w) if w % 2 == 0 => { wordsize = w; () }, | ||||
| 							_ => { return usage(&argv[0]); }, | ||||
| 						} | ||||
| 					}, | ||||
| 					_ => { return usage(&argv[0]); } | ||||
| 				} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	buf.resize(wordsize, 0); | ||||
| 
 | ||||
| 	loop { | ||||
| 		match input.read(&mut buf) { | ||||
| 			Ok(0) => break ExitCode::from(EX_OK as u8), | ||||
| 			Ok(v) if v == wordsize => { | ||||
| 				let (left, right) = buf.split_at(v/2); | ||||
| 				if let Err(e) = output.write(&right) | ||||
| 						.and_then(|_| output.write(&left)) { | ||||
| 					break oserr(&argv[0], e) | ||||
| 				} | ||||
| 			}, | ||||
| 			Ok(v) => { | ||||
| 				if let Err(e) = output.write(&buf[..v]) { | ||||
| 					break oserr(&argv[0], e) | ||||
| 				} | ||||
| 			}, | ||||
| 			Err(e) if e.kind() == ErrorKind::Interrupted && force => continue, | ||||
| 			Err(e) => break oserr(&argv[0], e) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user