From 3f0d95fe8fe87cd3b3c6ba766e1ec643d6f7faa6 Mon Sep 17 00:00:00 2001 From: DTB Date: Fri, 23 Feb 2024 20:49:24 -0700 Subject: [PATCH 1/5] swab(1): minimum viable program --- Makefile | 7 +++++++ src/swab.rs | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/swab.rs diff --git a/Makefile b/Makefile index 46fd88e..d8c0c59 100644 --- a/Makefile +++ b/Makefile @@ -101,6 +101,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 sysexits=build/o/libsysexits.rlib \ + -o $@ src/swab.rs + .PHONY: true true: build/bin/true build/bin/true: src/true.c build diff --git a/src/swab.rs b/src/swab.rs new file mode 100644 index 0000000..26104eb --- /dev/null +++ b/src/swab.rs @@ -0,0 +1,47 @@ +use std::{ + env::args, + io::{ stdin, stdout, Error, ErrorKind, Read, Write }, + process::ExitCode, + vec::Vec +}; + +extern crate sysexits; + +use sysexits::{ EX_OK, EX_OSERR }; + +fn oserr(s: &str, e: Error) -> ExitCode { + eprintln!("{}: {}", s, e); + ExitCode::from(EX_OSERR as u8) +} + +fn main() -> ExitCode { + let argv = args().collect::>(); + let mut buf: Vec = Vec::new(); + let mut input = stdin(); + let mut output = stdout().lock(); + + let wordsize: usize = 2; + let force = false; + + 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) + } + } +} From e788947fc4adfd2084b7fb1af0cf7aee7acbee0a Mon Sep 17 00:00:00 2001 From: DTB Date: Sat, 24 Feb 2024 03:04:05 -0700 Subject: [PATCH 2/5] swab(1): add argument parsing --- Makefile | 2 +- src/swab.rs | 33 +++++++++++++++++++++++++++++---- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index d8c0c59..3c4f52e 100644 --- a/Makefile +++ b/Makefile @@ -104,7 +104,7 @@ build/bin/strcmp: src/strcmp.c build .PHONY: swab swab: build/bin/swab build/bin/swab: src/swab.rs build build/o/libsysexits.rlib - $(RUSTC) $(RUSTFLAGS) \ + $(RUSTC) $(RUSTFLAGS) --extern getopt=build/o/libgetopt.rlib \ --extern sysexits=build/o/libsysexits.rlib \ -o $@ src/swab.rs diff --git a/src/swab.rs b/src/swab.rs index 26104eb..f48842c 100644 --- a/src/swab.rs +++ b/src/swab.rs @@ -5,23 +5,48 @@ use std::{ vec::Vec }; -extern crate sysexits; +extern crate getopt; +use getopt::{ Opt, Parser }; -use sysexits::{ EX_OK, EX_OSERR }; +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::>(); let mut buf: Vec = Vec::new(); let mut input = stdin(); let mut output = stdout().lock(); - let wordsize: usize = 2; - let force = false; + 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::() { + Ok(w) if w % 2 == 0 => { wordsize = w; () }, + _ => { return usage(&argv[0]); }, + } + }, + _ => { return usage(&argv[0]); } + } + } + } buf.resize(wordsize, 0); From 1e041a52a2eab165af03a157c83ce388c05bd73c Mon Sep 17 00:00:00 2001 From: DTB Date: Sat, 24 Feb 2024 03:21:20 -0700 Subject: [PATCH 3/5] swab.1: add swab(1) man page --- docs/swab.1 | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 docs/swab.1 diff --git a/docs/swab.1 b/docs/swab.1 new file mode 100644 index 0000000..a0c1be3 --- /dev/null +++ b/docs/swab.1 @@ -0,0 +1,71 @@ +.\" Copyright (c) 2024 DTB +.\" +.\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, +.\" visit . + +.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 +. + +.SH SEE ALSO + +dd(1p) From bbac85daf8439c5b1ea9aebb6fe018066817cc12 Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 26 Feb 2024 08:42:06 -0700 Subject: [PATCH 4/5] swab(1): add copyright notice --- src/swab.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/swab.rs b/src/swab.rs index f48842c..ca944d9 100644 --- a/src/swab.rs +++ b/src/swab.rs @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2024 DTB + * 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 }, From f14877118dd2206ab3d7d0914ba3a8a41c73a3cc Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 26 Feb 2024 08:43:03 -0700 Subject: [PATCH 5/5] Makefile: add swab(1) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3c4f52e..a630e09 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 intcmp rpn scrut str strcmp swab true build: # keep build/include until bindgen(1) has stdin support