From cabe08bca4a8aeaaf155b7863e85cb8c6cbc6036 Mon Sep 17 00:00:00 2001 From: DTB Date: Thu, 29 Feb 2024 20:33:09 -0700 Subject: [PATCH 001/343] TESTING: start testing document/script --- TESTING | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100755 TESTING diff --git a/TESTING b/TESTING new file mode 100755 index 0000000..2f92ece --- /dev/null +++ b/TESTING @@ -0,0 +1,74 @@ +#!/bin/sh + +### Overview +# +# Testing is conducted with this script, in the source tree root, using the +# tests in tests/. +# +# Basically, tests follow the format: +# +# - tests/[utility].[number].test +# Test #[number]. This is an executable file (typically a script). +# - tests/[utility].[number].expected +# This is the expected standard output of test #[number]. +# +# This script runs the executable [utility].[number].test and the following +# file is written during testing: +# +# - tests/[utility].[number].output +# The actual standard output from test #[number]. +# +# If the actual standard output from the test differs from the expected +# standard output, the testing ends, showing the difference. + +set -e + +alias emit="printf '%s: %s\n' '$0' \"\$1\"" + +export PATH="$PATH:./build/bin/" + +if strcmp '' "$1"; then + printf 'Usage: %s [utilities...]\n' "$0" >&2 + exit 64 # sysexits.h(3) EX_USAGE +fi + +### Details + +while ! strcmp '' "$1"; do # $1 refers to the given utility + +# Tests are called [utility].[number].test. Tests are numbered from 1 with no +# leading zeroes in the numbers, so (for example) scrut(1)'s first three tests +# are scrut.1.test, scrut.2.test, and scrut.3.test. Tests are run sequentially +# in the numbered order. + + i=1 + while scrut -e "$1.$i.test"; do # $i refers to the test number + emit "$1.$i.test: Running test..." + +# A test is an executable file. This runs each test for given utilities +# and writes the standard output from the test to [utility].[number].output, +# then uses diff(1p) (with the "-u" option) to highlight differences between +# the actual output and the expected output, which is located at +# [utility].[number].expected. If there are no differences none are shown and +# testing continues. + + # $1.$i.test is the same as [utility].[number].test + ./"$1.$i.test" \ + | mm -o "$1.$i.output" -o - \ + | diff -u - "$1.$i.expected" \ + || emit '$1.$i.test: Test passed.\n' + # "set -e" terminates on an unsuccessful exit + +# The ideal output of this script is no output at all and each +# [utility].[number].output written matching its associated +# [utility].[number].expected. + + i=$(rpn 1 "$i" +) + done + + shift +done + +# -- +# This work © 2024 by DTB is licensed under CC BY-SA 4.0. To view a copy of +# this license, visit From f7a74dc430347ae6bec43a1b08f1ad563670a001 Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 11 Mar 2024 21:01:29 -0600 Subject: [PATCH 002/343] Testfile --- Makefile | 2 ++ TESTING | 74 ----------------------------------------------------- Testfile | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 74 deletions(-) delete mode 100755 TESTING create mode 100755 Testfile diff --git a/Makefile b/Makefile index f181e20..494f0f7 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,7 @@ PREFIX=/usr/local CC=cc +MAKE=make RUSTC=rustc .PHONY: all @@ -42,6 +43,7 @@ install: dist test: build tests/posix-compat.sh $(RUSTC) --test src/getopt-rs/lib.rs -o build/test/getopt + $(MAKE) -f Testfile build/o/libsysexits.rlib: build # bandage solution until bindgen(1) gets stdin support diff --git a/TESTING b/TESTING deleted file mode 100755 index 2f92ece..0000000 --- a/TESTING +++ /dev/null @@ -1,74 +0,0 @@ -#!/bin/sh - -### Overview -# -# Testing is conducted with this script, in the source tree root, using the -# tests in tests/. -# -# Basically, tests follow the format: -# -# - tests/[utility].[number].test -# Test #[number]. This is an executable file (typically a script). -# - tests/[utility].[number].expected -# This is the expected standard output of test #[number]. -# -# This script runs the executable [utility].[number].test and the following -# file is written during testing: -# -# - tests/[utility].[number].output -# The actual standard output from test #[number]. -# -# If the actual standard output from the test differs from the expected -# standard output, the testing ends, showing the difference. - -set -e - -alias emit="printf '%s: %s\n' '$0' \"\$1\"" - -export PATH="$PATH:./build/bin/" - -if strcmp '' "$1"; then - printf 'Usage: %s [utilities...]\n' "$0" >&2 - exit 64 # sysexits.h(3) EX_USAGE -fi - -### Details - -while ! strcmp '' "$1"; do # $1 refers to the given utility - -# Tests are called [utility].[number].test. Tests are numbered from 1 with no -# leading zeroes in the numbers, so (for example) scrut(1)'s first three tests -# are scrut.1.test, scrut.2.test, and scrut.3.test. Tests are run sequentially -# in the numbered order. - - i=1 - while scrut -e "$1.$i.test"; do # $i refers to the test number - emit "$1.$i.test: Running test..." - -# A test is an executable file. This runs each test for given utilities -# and writes the standard output from the test to [utility].[number].output, -# then uses diff(1p) (with the "-u" option) to highlight differences between -# the actual output and the expected output, which is located at -# [utility].[number].expected. If there are no differences none are shown and -# testing continues. - - # $1.$i.test is the same as [utility].[number].test - ./"$1.$i.test" \ - | mm -o "$1.$i.output" -o - \ - | diff -u - "$1.$i.expected" \ - || emit '$1.$i.test: Test passed.\n' - # "set -e" terminates on an unsuccessful exit - -# The ideal output of this script is no output at all and each -# [utility].[number].output written matching its associated -# [utility].[number].expected. - - i=$(rpn 1 "$i" +) - done - - shift -done - -# -- -# This work © 2024 by DTB is licensed under CC BY-SA 4.0. To view a copy of -# this license, visit diff --git a/Testfile b/Testfile new file mode 100755 index 0000000..6b0ed42 --- /dev/null +++ b/Testfile @@ -0,0 +1,77 @@ +# Copyright (c) 2024 DTB +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +BIN = build/bin +MAKE = make -B + +DEFENDANTS = dj false intcmp strcmp true +.PHONY: all $(DEFENDANTS) +all: $(DEFENDANTS) + +$(BIN)/dj: + $(MAKE) dj + +$(BIN)/false: + $(MAKE) false + +$(BIN)/intcmp: + $(MAKE) intcmp + +$(BIN)/strcmp + $(MAKE) strcmp + +$(BIN)/true: + $(MAKE) true + +dj: $(BIN)/dj $(BIN)/strcmp + sh -c "! $(BIN)/dj -h" + # This test is theoretically Linux-dependent; write(2) should return -1 on + # error. + # Right now dj(1) interprets the return value of write(2) as the amount of + # bytes written. This can decrement the stored quantity of bytes written, + # which is an int, so doesn't underflow but goes negative. dj(1) tries to + # again to write(2) if an error occurs in which no bytes are written, so in + # total two write(2)s are attempted and so the written byte quantity is -2. + # This is a bug and will change, but for now is at least documented. + sh -ec "\ + $(BIN)/dj -Hi /dev/zero -o /dev/full \ + | xargs -I out $(BIN)/strcmp '1+0 > 0+0; 1024 > -2' out" + # Read nothing from /dev/null, write nothing to /dev/null. + sh -ec "\ + $(BIN)/dj -Hi /dev/null -o /dev/null \ + | xargs -I out $(BIN)/strcmp '0+0 > 0+0; 0 > 0' out" + +false: $(BIN)/false + sh -c "! $(BIN)/false" + sh -c "! $(BIN)/false -h" + +intcmp: $(BIN)/intcmp + intcmp -e 3 3 3 + intcmp -g 3 2 1 + intcmp -l 1 2 3 + intcmp -ge 3 3 1 + intcmp -le 1 3 3 + intcmp -gl 1 2 3 + intcmp -egl 3 1 1 2 + sh -c "! intcmp -e 1 2 3" + sh -c "! intcmp -g 1 3 3" + sh -c "! intcmp -l 3 3 1" + sh -c "! intcmp -ge 1 2 3" + sh -c "! intcmp -le 3 2 1" + sh -c "! intcmp -gl 3 3 3" + sh -c "! intcmp -egl foo" + +strcmp: $(BIN)/strcmp + $(BIN)/strcmp equals equals + sh -c "! $(BIN)/strcmp inequals equals" + $(BIN)/strcmp - - + sh -c "! $(BIN)/strcmp -h" + sh -c "! $(BIN)/strcmp nocmp" + +true: + $(BIN)/true + $(BIN)/true -h From 417d7ca40555b67f3051bde9e06b653df305eb58 Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 11 Mar 2024 21:03:53 -0600 Subject: [PATCH 003/343] Testfile: fix syntax --- Testfile | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Testfile b/Testfile index 6b0ed42..d921451 100755 --- a/Testfile +++ b/Testfile @@ -21,7 +21,7 @@ $(BIN)/false: $(BIN)/intcmp: $(MAKE) intcmp -$(BIN)/strcmp +$(BIN)/strcmp: $(MAKE) strcmp $(BIN)/true: @@ -50,20 +50,20 @@ false: $(BIN)/false sh -c "! $(BIN)/false -h" intcmp: $(BIN)/intcmp - intcmp -e 3 3 3 - intcmp -g 3 2 1 - intcmp -l 1 2 3 - intcmp -ge 3 3 1 - intcmp -le 1 3 3 - intcmp -gl 1 2 3 - intcmp -egl 3 1 1 2 - sh -c "! intcmp -e 1 2 3" - sh -c "! intcmp -g 1 3 3" - sh -c "! intcmp -l 3 3 1" - sh -c "! intcmp -ge 1 2 3" - sh -c "! intcmp -le 3 2 1" - sh -c "! intcmp -gl 3 3 3" - sh -c "! intcmp -egl foo" + $(BIN)/intcmp -e 3 3 3 + $(BIN)/intcmp -g 3 2 1 + $(BIN)/intcmp -l 1 2 3 + $(BIN)/intcmp -ge 3 3 1 + $(BIN)/intcmp -le 1 3 3 + $(BIN)/intcmp -gl 1 2 3 + $(BIN)/intcmp -egl 3 1 1 2 + sh -c "! $(BIN)/intcmp -e 1 2 3" + sh -c "! $(BIN)/intcmp -g 1 3 3" + sh -c "! $(BIN)/intcmp -l 3 3 1" + sh -c "! $(BIN)/intcmp -ge 1 2 3" + sh -c "! $(BIN)/intcmp -le 3 2 1" + sh -c "! $(BIN)/intcmp -gl 3 3 3" + sh -c "! $(BIN)/intcmp -egl foo" strcmp: $(BIN)/strcmp $(BIN)/strcmp equals equals From e7021e127ce1ea456de46a259d9cceed58f684ef Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 13 Mar 2024 18:20:30 -0600 Subject: [PATCH 004/343] Testfile: make non-executable --- Testfile | 1 + 1 file changed, 1 insertion(+) mode change 100755 => 100644 Testfile diff --git a/Testfile b/Testfile old mode 100755 new mode 100644 index d921451..e2cc294 --- a/Testfile +++ b/Testfile @@ -1,3 +1,4 @@ +#!/usr/bin/env make # Copyright (c) 2024 DTB # SPDX-License-Identifier: FSFAP # From a6fd1108c606f782e707de31d24e5d84214809c6 Mon Sep 17 00:00:00 2001 From: emma Date: Tue, 26 Mar 2024 18:26:51 -0600 Subject: [PATCH 005/343] docs: fixed formatting of many manpages --- docs/dj.1 | 156 ++++++++++++++++++++++++++++++-------------------- docs/intcmp.1 | 49 ++++++++++------ docs/npc.1 | 31 +++++----- docs/scrut.1 | 107 +++++++++++++++++++++------------- docs/str.1 | 8 +-- docs/strcmp.1 | 2 +- 6 files changed, 218 insertions(+), 135 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 1e286f5..c94845e 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -1,4 +1,5 @@ .\" Copyright (c) 2024 DTB +.\" Copyright (c) 2024 Emma Tebibyte .\" .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . @@ -46,84 +47,117 @@ dj .SH USAGE -The -.B -i -option takes a path as an argument to open and use in place of standard input. -The -.B -o -option does the same in place of standard output. Dj does not truncate output -files and instead writes over the bytes in the existing file. -.PP -The -.B -b -option takes a numeric argument as the size in bytes of the input buffer and -the +.B -A +.RS +Takes no arguments and pads with nuls. +.RE + .B -B -option does the same for the output buffer, the default for both being 1024 -bytes, or one kibibyte (KiB). -.PP -The -.B -s -option takes a numeric argument as the number of bytes to skip into the input -before starting to read, and the +.RS +Does the same as +.B -b +but for the output buffer. +.RE + +.B -H +.RS +Prints diagnostics messages in an alternate manner as described in the +DIAGNOSTICS section below. +.RE + .B -S -option skips a number of bytes through the output before starting to write from +.RS +Skips a number of bytes through the output before starting to write from the input. If the input is a stream the bytes are read and discarded. If the output is a stream, nul characters are printed. -.PP -The +.RE + .B -a -option takes one argument of one byte in length and pads the input buffer with -that byte in the event that a read doesn't fill the input buffer, and the -.B -A -option takes no arguments and pads with nuls. -The +.RS +Takes one argument of one byte in length and pads the input buffer with +that byte in the event that a read doesn’t fill the input buffer, and the +.RE + +.B -b +.RS +Takes a numeric argument as the size in bytes of the input buffer, with the +default being 1024 bytes or one kibibyte (KiB). +.RE + .B -c -option specifies an amount of reads to make, and if 0 (the default) dj will +.RS +Specifies an amount of reads to make, and if 0 (the default) dj will continue reading until a partial or empty read. -.PP +.RE + +.B -d +.RS +Prints all debug information, user-specified or otherwise, before program +execution. +.RE + +.B -i +.RS +Takes a path as an argument to open and use in place of standard input. +.RE + +.B -n +.RS +Causes dj to exit on two consecutive empty reads instead of one. +.RE + +.B -o +.RS +Does the same as +.B -i +but in place of standard output. Dj does not truncate output +files and instead writes over the bytes in the existing file. +.RE + +.B -s +.RS +Takes a numeric argument as the number of bytes to skip into the input +before starting to read. +.RE + +.B -q +.RS +Suppresses error messages which print when a read or write is partial or +empty. When +.B -q +is specified twice suppresses diagnostic output entirely. +.RE + +.SH DIAGNOSTICS + On a partial or empty read, dj prints a diagnostic message (unless the .B -q option is specified) and exits (unless the .B -n -option is specified, in which case only two consecutive empty reads will cause -dj to exit). -At exit, usage statistics are printed unless the option -.B -q -is specified a second time. The -.B -H -option will make these diagnostics human-readable. +option is specified. -.SH DIAGNOSTICS +By default statistics are printed for input and output to the standard error in +the following format: -The -.B -d -option prints all information, user-specified or otherwise, before program -execution. -.PP -When dj exits, by default statistics are printed for input and output to -standard error in the following format: -.PP +.RS .R {records read} {ASCII unit separator} {partial records read} .R {ASCII record separator} {records written} {ASCII unit separator} .R {partial records written} {ASCII group separator} {bytes read} .R {ASCII record separator} {bytes written} {ASCII file separator} -.PP +.RE + If the .B -H -option is specified dj instead uses this following format: -.PP +option is specified, dj instead uses the following format: + +.RS .R {records read} '+' {partial records read} '>' {records written} .R '+' {partial records written} ';' {bytes read} '>' {bytes written} .R {ASCII line feed} -.PP -The -.B -q -option suppresses error messages which print when a read or write is partial or -empty and when used twice suppresses diagnostic output entirely. -.PP -In non-recoverable errors that don't pertain to dj's read-write cycle, a -diagnostic message is printed and dj exits with the appropriate sysexits(3) +.RE + +In non-recoverable errors that don’t pertain to dj’s read-write cycle, a +diagnostic message is printed and dj exits with the appropriate sysexits.h(3) status. .SH BUGS @@ -136,7 +170,7 @@ expected (the product of the count multiplied by the input block size). If the or .B -A options are used this could make data written nonsensical. -.PP + Many lowercase options have capitalized variants and vice-versa which can be confusing. Capitalized options tend to affect output or are more intense versions of lowercase options. @@ -146,15 +180,15 @@ versions of lowercase options. Dj was modeled after the dd utility specified in POSIX but adds additional features: typical option formatting, allowing seeks to be specified in bytes rather than in blocks, allowing arbitrary bytes as padding, and printing in a -format that's easy to parse for machines. It also neglects character -conversion, which may be dd's original intent but is irrelevant to its modern +format that’s easy to parse for machines. It also neglects character +conversion, which may be dd’s original intent but is irrelevant to its modern use. .SH COPYRIGHT -Copyright (C) 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later +Copyright © 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later . .SH SEE ALSO -dd(1) +dd(1p) diff --git a/docs/intcmp.1 b/docs/intcmp.1 index f370755..e3c0bcc 100644 --- a/docs/intcmp.1 +++ b/docs/intcmp.1 @@ -1,5 +1,5 @@ .\" Copyright (c) 2023–2024 DTB -.\" Copyright (c) 2023 Emma Tebibyte +.\" Copyright (c) 2023–2024 Emma Tebibyte .\" .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . @@ -13,7 +13,7 @@ intcmp \(en compare integers .SH SYNOPSIS intcmp -.RB ( -eghl ) +.RB ( -egl ) .RB [ integer ] .RB [ integer... ] @@ -23,35 +23,52 @@ Intcmp compares integers. .SH USAGE -The -e option permits given integers to be equal to each other. If combined -with -g or -l, only adjacent integers in the argument sequence can be equal. -.PP -The -g option permits a given integer to be greater than the following integer. -.PP -The -l option permits a given integer to be less than the following integer. -.PP +.B -e +.RS +Permits given integers to be equal to each other. If combined with +.B -g +or +.B -l +, only adjacent integers in the argument sequence can be equal. +.RE + +.B -g +.RS +Permits a given integer to be greater than the following integer. +.RE + +.B -l +.RS +Permits a given integer to be less than the following integer. +.RE + +.SH EXAMPLES + It may help to think of the -e, -g, and -l options as equivalent to the infix algebraic “=”, “>”, and “<” operators respectively, with each option -putting its symbol between every given integer. For example, +putting its symbol between every given integer. The following example is +equivalent to evaluating “1 < 2 < 3”: + +.RS .R intcmp -l 1 2 3 -is equivalent to evaluating "1 < 2 < 3". +.RE .SH DIAGNOSTICS Intcmp exits 0 for a valid expression and 1 for an invalid expression. -.PP -Intcmp prints a debug message and exits with the appropriate sysexits(3) error + +Intcmp prints a debug message and exits with the appropriate sysexits.h(3) error code in the event of an error. .SH BUGS There are multiple ways to express compound comparisons; “less than or equal to” can be -le or -el, for example. -.PP + The inequality comparison is -gl or -lg for “less than or greater than”; this is elegant but unintuitive. -.PP --egl, "equal to or less than or greater than", exits 0 no matter what for valid + +-egl, “equal to or less than or greater than”, exits 0 no matter what for valid program usage and may be abused to function as an integer validator. Use str(1) instead. diff --git a/docs/npc.1 b/docs/npc.1 index 7f66c3d..e524f29 100644 --- a/docs/npc.1 +++ b/docs/npc.1 @@ -1,5 +1,5 @@ .\" Copyright (c) 2023–2024 DTB -.\" Copyright (c) 2023 Emma Tebibyte +.\" Copyright (c) 2023–2024 Emma Tebibyte .\" .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . @@ -13,29 +13,31 @@ npc \(en show non-printing characters .SH SYNOPSIS npc -.RB ( -eht ) +.RB ( -et ) .SH DESCRIPTION Npc reads from standard input and writes to standard output, replacing non- printing characters with printable equivalents. Control characters print as a -carat ('^') followed by the character '@' through '_' corresponding to the -character replaced (e.g. control-X becomes "^X"). The delete character (0x7F) -becomes "^?". Characters with the high bit set (>127) are printed as "M-" +carat (“^”) followed by the character “@” through “_” corresponding to the +character replaced (e.g. control-X becomes “^X”). The delete character (0x7F) +becomes “^?”. Characters with the high bit set (>127) are printed as “M-” followed by the graphical representation for the same character without the high bit set. -.PP -The + .B -e -option prints a currency sign ('$') before each line ending. -.PP -The +.RS +Prints a currency sign (“$”) before each line ending. +.RE + .B -t -option prints tab characters as "^I" rather than a literal horizontal tab. +.RS +Prints tab characters as “^I” rather than a literal horizontal tab. +.RE .SH DIAGNOSTICS -Npc prints a debug message and exits with the appropriate sysexits(3) error +Npc prints a debug message and exits with the appropriate sysexits.h(3) error code in the event of an error, otherwise it exits successfully. .SH BUGS @@ -45,8 +47,9 @@ Npc operates in single-byte chunks regardless of intended encoding. .SH RATIONALE POSIX currently lacks a way to display non-printing characters in the terminal -using a standard tool. A popular extension to cat(1p), the -v option, is the -bandage solution GNU and other software suites use. +using a standard tool. A popular extension to cat(1p), the +.B -v +option, is the bandage solution GNU and other software suites use. This functionality should be a separate tool because its usefulness extends beyond that of cat(1p). diff --git a/docs/scrut.1 b/docs/scrut.1 index 7a5107a..2f0955b 100644 --- a/docs/scrut.1 +++ b/docs/scrut.1 @@ -1,4 +1,5 @@ .\" Copyright (c) 2024 DTB +.\" Copyright (c) 2024 Emma Tebibyte .\" .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . @@ -21,47 +22,75 @@ Scrut determines if given files comply with the opted requirements. .SH OPTIONS -.B -b -requires the given files to exist and be block special files. -.PP -.B -c -requires the given files to exist and be character special files. -.PP -.B -d -requires the given files to exist and be directories. -.PP -.B -e -requires the given files to exist, and is redundant to any other option. -.PP -.B -e -requires the given files to exist and be regular files. -.PP -.B -g -requires the given files to exist and have their set group ID flags set. -.PP -.B -k -requires the given files to exist and have their sticky bit set. -.PP -.B -p -requires the given files to exist and be named pipes. -.PP -.B -r -requires the given files to exist and be readable. -.PP -.B -u -requires the given files to exist and have their set user ID flags set. -.PP -.B -w -requires the given files to exist and be writable. -.PP -.B -x -requires the given files to exist and be executable. -.PP .B -L -requires the given files to exist and be symbolic links. -.PP +.RS +Requires the given files to exist and be symbolic links. +.RE + .B -S -requires the given files to exist and be sockets. +.RS +Requires the given files to exist and be sockets. +.RE + +.B -b +.RS +Requires the given files to exist and be block special files. +.RE + +.B -c +.RS +Requires the given files to exist and be character special files. +.RE + +.B -d +.RS +Requires the given files to exist and be directories. +.RE + +.B -e +.RS +Requires the given files to exist, and is redundant to any other option. +.RE + +.B -e +.RS +Requires the given files to exist and be regular files. +.RE + +.B -g +.RS +Requires the given files to exist and have their set group ID flags set. +.RE + +.B -k +.RS +Requires the given files to exist and have their sticky bit set. +.RE + +.B -p +.RS +Requires the given files to exist and be named pipes. +.RE + +.B -r +.RS +Requires the given files to exist and be readable. +.RE + +.B -u +.RS +Requires the given files to exist and have their set user ID flags set. +.RE + +.B -w +.RS +Requires the given files to exist and be writable. +.RE + +.B -x +.RS +Requires the given files to exist and be executable. +.RE .SH EXIT STATUS diff --git a/docs/str.1 b/docs/str.1 index ecf71ee..08137fb 100644 --- a/docs/str.1 +++ b/docs/str.1 @@ -1,5 +1,5 @@ .\" Copyright (c) 2023–2024 DTB -.\" Copyright (c) 2023 Emma Tebibyte +.\" Copyright (c) 2023–2024 Emma Tebibyte .\" .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . @@ -24,10 +24,10 @@ the function of the same name within ctype(3). .SH DIAGNOSTICS Str exits successfully if all tests pass and unsuccessfully if a test failed. -.PP + Str will exit unsuccessfully if a string is empty, as none of its contents passed the test. -.PP + Str will print a message to standard error and exit unsuccessfully if used improperly. @@ -41,7 +41,7 @@ removed in favor of using strcmp(1) to compare strings against the empty string There's no way of knowing which argument failed the test without re-testing arguments individually. -.PP + If a character in a string isn't valid ASCII str will exit unsuccessfully. .SH AUTHOR diff --git a/docs/strcmp.1 b/docs/strcmp.1 index 14c0d0d..56e2ec9 100644 --- a/docs/strcmp.1 +++ b/docs/strcmp.1 @@ -1,5 +1,5 @@ .\" Copyright (c) 2023–2024 DTB -.\" Copyright (c) 2023 Emma Tebibyte +.\" Copyright (c) 2023–2024 Emma Tebibyte .\" .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . From cf76fa94e6574ca5b7ab7ec456d98543171bb6cd Mon Sep 17 00:00:00 2001 From: emma Date: Tue, 26 Mar 2024 18:44:05 -0600 Subject: [PATCH 006/343] mm.1: updated man page --- docs/mm.1 | 61 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/docs/mm.1 b/docs/mm.1 index 2244588..c8cc5dc 100644 --- a/docs/mm.1 +++ b/docs/mm.1 @@ -20,51 +20,60 @@ mm .SH DESCRIPTION -Mm catenates input files and writes them to the start of each output file. +Catenate input files and write them to the start of each output file or stream. .SH OPTIONS -Mm, upon receiving the .B -a -option, will open subsequent outputs for appending rather than updating. -.PP -The -.B -i -option opens a path as an input. Without any inputs specified mm will use -standard input. Standard input itself can be specified by giving the path '-'. -.PP -The -.B -o -option opens a path as an output. Without any outputs specified mm will use -standard output. Standard output itself can be specified by giving the -path '-'. Standard error itself can be specified with the +.RS +Opens subsequent outputs for appending rather than updating. +.RE + .B -e -option. -.PP -The +.RS +Set the output to the standard error. +.RE + +.B -i +.RS +Opens a path as an input. Without any inputs specified mm will use the +standard input. +.RE + +.B -o +.RS +Opens a path as an output. Without any outputs specified mm will use the +standard output. +.RE + .B -u -option ensures neither input or output will be buffered. -.PP -The +.RS +Ensures neither input or output will be buffered. +.RE + .B -n -option tells mm to ignore SIGINT signals. +.RS +Causes SIGINT signals to be ignored. +.RE .SH DIAGNOSTICS If an output can no longer be written mm prints a diagnostic message, ceases writing to that particular output, and if there are more outputs specified, continues, eventually exiting unsuccessfully. -.PP -On error mm prints a diagnostic message and exits with the appropriate -sysexits.h(3) status. + +When an error is encountered, diagnostic message is printed and the program +exits with the appropriate sysexits.h(3) status. .SH BUGS -Mm does not truncate existing files, which may lead to unexpected results. +Existing files are not truncated, which may lead to unexpected results. .SH RATIONALE -Mm was modeled after the cat and tee utilities specified in POSIX. +The cat(1p) and tee(1p) programs specified in POSIX provide equivalent +functionality. The separation of the two sets of functionality into separate +APIs seemed unncessary. .SH COPYRIGHT From 63a0c683f9803fe8b5023e07ceac1fc0bd922e51 Mon Sep 17 00:00:00 2001 From: emma Date: Tue, 26 Mar 2024 19:22:30 -0600 Subject: [PATCH 007/343] docs: remove unnecessary references to the name of each program --- docs/dj.1 | 21 +++++++++++---------- docs/false.1 | 11 +++++------ docs/hru.1 | 22 ++++++++++++---------- docs/intcmp.1 | 11 ++++++----- docs/npc.1 | 20 ++++++++++++-------- docs/rpn.1 | 23 ++++++++++++++--------- docs/scrut.1 | 14 ++++++++------ docs/str.1 | 25 ++++++++++++++----------- docs/strcmp.1 | 25 +++++++++++++------------ docs/swab.1 | 52 ++++++++++++++++++++++++++++----------------------- docs/true.1 | 11 +++++------ 11 files changed, 129 insertions(+), 106 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index c94845e..3c57155 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -148,7 +148,7 @@ the following format: If the .B -H -option is specified, dj instead uses the following format: +option is specified, the following format is used instead: .RS .R {records read} '+' {partial records read} '>' {records written} @@ -156,9 +156,9 @@ option is specified, dj instead uses the following format: .R {ASCII line feed} .RE -In non-recoverable errors that don’t pertain to dj’s read-write cycle, a -diagnostic message is printed and dj exits with the appropriate sysexits.h(3) -status. +In non-recoverable errors that don’t pertain to the read-write cycle, a +diagnostic message is printed and the program exits with the appropriate +sysexits.h(3) status. .SH BUGS @@ -177,12 +177,13 @@ versions of lowercase options. .SH RATIONALE -Dj was modeled after the dd utility specified in POSIX but adds additional -features: typical option formatting, allowing seeks to be specified in bytes -rather than in blocks, allowing arbitrary bytes as padding, and printing in a -format that’s easy to parse for machines. It also neglects character -conversion, which may be dd’s original intent but is irrelevant to its modern -use. +The dd(1p) utility specified in POSIX was the basis of this program. + +It includes additional features: typical option formatting, allowing seeks to be +specified in bytes rather than in blocks, allowing arbitrary bytes as padding, +and printing in a format that’s easy to parse for machines. It also neglects +character conversion. This may have been the original intent of dd(1p) but it is +irrelevant to its modern use as a disk utility. .SH COPYRIGHT diff --git a/docs/false.1 b/docs/false.1 index 6883802..b8463ae 100644 --- a/docs/false.1 +++ b/docs/false.1 @@ -1,5 +1,5 @@ .\" Copyright (c) 2022, 2024 DTB -.\" Copyright (c) 2023 Emma Tebibyte +.\" Copyright (c) 2023–2024 Emma Tebibyte .\" .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . @@ -12,14 +12,13 @@ false \(en do nothing, unsuccessfully .SH DESCRIPTION -False does nothing regardless of operands or standard input. -False will always return an exit code of 1. +Do nothing regardless of operands or standard input. +An exit code of 1 will always be returned. .SH RATIONALE -False exists for the construction of control flow and loops based on a failure. - -False functions as described in POSIX.1-2017. +In POSIX.1-2017, false(1p) exists for the construction of control flow and loops +based on a failure. This implementation functions as described in that standard. .SH AUTHOR diff --git a/docs/hru.1 b/docs/hru.1 index c75cb73..1ffc00e 100644 --- a/docs/hru.1 +++ b/docs/hru.1 @@ -3,7 +3,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . -.TH rpn 1 +.TH hru 1 .SH NAME @@ -15,18 +15,20 @@ 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. +Convert counts to higher units. + +The program will read byte counts in the form of whole numbers from the standard +input and write to the standard output the same number converted to a higher +unit of data as 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. +If encountering non-integer characters in the standard input, the program will +exit with the appropriate error code as defined by sysexits.h(3) and print an +error message. .SH RATIONALE @@ -39,9 +41,9 @@ 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). +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) are utilized for the ouput of conversions. .SH AUTHOR diff --git a/docs/intcmp.1 b/docs/intcmp.1 index e3c0bcc..209b2d8 100644 --- a/docs/intcmp.1 +++ b/docs/intcmp.1 @@ -19,7 +19,7 @@ intcmp .SH DESCRIPTION -Intcmp compares integers. +Compare integers. .SH USAGE @@ -55,10 +55,11 @@ equivalent to evaluating “1 < 2 < 3”: .SH DIAGNOSTICS -Intcmp exits 0 for a valid expression and 1 for an invalid expression. +The program will exit with a status code of 0 for a valid expression and with a +code of 1 for an invalid expression. -Intcmp prints a debug message and exits with the appropriate sysexits.h(3) error -code in the event of an error. +In the event of an error, a debug message will be printed and the program will +exit with the appropriate sysexits.h(3) error code. .SH BUGS @@ -78,7 +79,7 @@ The traditional tool for integer comparisons in POSIX and other Unix shells has been test(1). This tool also handles string comparisons and file scrutiny. These parts of its functionality have been broken out into multiple utilities. -Strcmp’s functionality may be performed on a POSIX-compliant system with +This program’s functionality may be performed on a POSIX-compliant system with test(1p). .SH AUTHOR diff --git a/docs/npc.1 b/docs/npc.1 index e524f29..daad9f1 100644 --- a/docs/npc.1 +++ b/docs/npc.1 @@ -17,14 +17,18 @@ npc .SH DESCRIPTION -Npc reads from standard input and writes to standard output, replacing non- -printing characters with printable equivalents. Control characters print as a -carat (“^”) followed by the character “@” through “_” corresponding to the +Print normally non-printing characters. + +The program reads from standard input and writes to standard output, replacing +non-printing characters with printable equivalents. Control characters print as +a carat (“^”) followed by the character “@” through “_” corresponding to the character replaced (e.g. control-X becomes “^X”). The delete character (0x7F) becomes “^?”. Characters with the high bit set (>127) are printed as “M-” followed by the graphical representation for the same character without the high bit set. +.SH USAGE + .B -e .RS Prints a currency sign (“$”) before each line ending. @@ -37,12 +41,12 @@ Prints tab characters as “^I” rather than a literal horizontal tab. .SH DIAGNOSTICS -Npc prints a debug message and exits with the appropriate sysexits.h(3) error -code in the event of an error, otherwise it exits successfully. +In the event of an error, a debug message will be printed and the program will +exit with the appropriate sysexits.h(3) error code. .SH BUGS -Npc operates in single-byte chunks regardless of intended encoding. +The program operates in single-byte chunks regardless of intended encoding. .SH RATIONALE @@ -51,8 +55,8 @@ using a standard tool. A popular extension to cat(1p), the .B -v option, is the bandage solution GNU and other software suites use. -This functionality should be a separate tool because its usefulness extends -beyond that of cat(1p). +This functionality is a separate tool because its usefulness extends beyond that +of cat(1p). .SH AUTHOR diff --git a/docs/rpn.1 b/docs/rpn.1 index 2197fbe..0b6b264 100644 --- a/docs/rpn.1 +++ b/docs/rpn.1 @@ -17,10 +17,13 @@ rpn .SH DESCRIPTION -Rpn evaluates reverse polish notation expressions either read from the standard -input or parsed from provided arguments. See the STANDARD INPUT section. +Evaluate reverse polish notation. -Upon evaluation, rpn will print the resulting number on the stack to the +The program evaluates reverse polish notation expressions either read from the +standard input or parsed from provided arguments. See the STANDARD INPUT +section. + +Upon evaluation, the program will print the resulting number on the stack to the standard output. Any further specified numbers will be placed at the end of the stack. @@ -28,14 +31,16 @@ For information on for reverse polish notation syntax, see rpn(7). .SH STANDARD INPUT -If arguments are passed to rpn, it interprets them as an expression to be -evaluated. Otherwise, it reads whitespace-delimited numbers and operations from -the standard input. +If arguments are passed , they are interpreted as an expression to be evaluated. +Otherwise, it reads whitespace-delimited numbers and operations from the +standard input. .SH DIAGNOSTICS -If encountering a syntax error, rpn will exit with the appropriate error code -as defined by sysexits.h(3) and print an error message. +In the event of a syntax error, the program will print an + +In the event of an error, a debug message will be printed and the program will +exit with the appropriate sysexits.h(3) error code. .SH CAVEATS @@ -44,7 +49,7 @@ with the IEEE Standard for Floating Point Arithmetic (IEEE 754), floating-point arithmetic has rounding errors. This is somewhat curbed by using the machine epsilon as provided by the Rust standard library to which to round numbers. Because of this, variation is expected in the number of decimal places -rpn can handle based on the platform and hardware of any given machine. +the program can handle based on the platform and hardware of any given machine. .SH RATIONALE diff --git a/docs/scrut.1 b/docs/scrut.1 index 2f0955b..4c0b75b 100644 --- a/docs/scrut.1 +++ b/docs/scrut.1 @@ -18,7 +18,7 @@ scrut .SH DESCRIPTION -Scrut determines if given files comply with the opted requirements. +Determine if files comply with requirements. .SH OPTIONS @@ -94,14 +94,16 @@ Requires the given files to exist and be executable. .SH EXIT STATUS -Scrut prints a debug message and exits unsuccessfully with the appropriate -sysexits.h(3) error code if invoked incorrectly. Scrut exits successfully if -the given files comply with their requirements and unsuccessfully otherwise. +If the given files comply with the specified requirements, the program will exit +successfully. If not, it exits unsuccessfully. + +When invoked incorrectly, a debug message will be printed and the program will +exit with the appropriate sysexits.h(3) error code. .SH STANDARDS -Scrut is nearly compatible with POSIX's test utility though it is narrower in -scope. Notably, the +The test(1p) utility contains functionality that was broken out into separate +programs. Thus, the scope of this program is narrower than it. Notably, the .B -h option is now invalid and therefore shows usage information instead of being an alias to the modern diff --git a/docs/str.1 b/docs/str.1 index 08137fb..e671ecd 100644 --- a/docs/str.1 +++ b/docs/str.1 @@ -18,28 +18,31 @@ str .SH DESCRIPTION -Str tests each character in an arbitrary quantity of string arguments against -the function of the same name within ctype(3). +Test string arguments against each other. + +The tests in this program are equivalent to the functions with the same names in +ctype.h(0p) and are the methods by which string arguments are tested. .SH DIAGNOSTICS -Str exits successfully if all tests pass and unsuccessfully if a test failed. +If all tests pass, the program will exit with an exit code of 0. If any of the +tests fail, the program will exit unsuccessfully with an error code of 1. -Str will exit unsuccessfully if a string is empty, as none of its contents -passed the test. +An empty string will cause an unsuccessful exit as none of its contents pass any +tests. -Str will print a message to standard error and exit unsuccessfully if used -improperly. +When invoked incorrectly, a debug message will be printed and the program will +exit with the appropriate sysexits.h(3) error code. .SH DEPRECATED FEATURES -Str used to have an "isvalue" type as an extension to ctype(3). This was -removed in favor of using strcmp(1) to compare strings against the empty string -(''). +Originally, there was an isvalue type as an extension to ctype.h(3), but it +was removed in favor of using strcmp(1) to compare strings against the empty +string (''). .SH BUGS -There's no way of knowing which argument failed the test without re-testing +There’s no way of knowing which argument failed the test without re-testing arguments individually. If a character in a string isn't valid ASCII str will exit unsuccessfully. diff --git a/docs/strcmp.1 b/docs/strcmp.1 index 56e2ec9..c2103dd 100644 --- a/docs/strcmp.1 +++ b/docs/strcmp.1 @@ -18,26 +18,27 @@ strcmp .SH DESCRIPTION -Strcmp checks whether the given strings are the same. -Strcmp exits successfully if the strings are identical. Otherwise, strcmp exits -with the value 1 if an earlier string has a greater byte value than a later -string (e.g. +Check whether string arguments are the same. + +.SH DIAGNOSTICS + +The program will exit successfully if the strings are identical. Otherwise, it +exits with the value 1 if an earlier string has a greater byte value than a +later string (e.g. .R strcmp b a ) and 255 if an earlier string has a lesser byte value (e.g. .R strcmp a b ). -.SH DIAGNOSTICS - -Strcmp will print an error message and exit unsuccessfully with a status -described in sysexits(3) if used incorrectly (given less than two operands). +When invoked incorrectly, a debug message will be printed and the program will +exit with the appropriate sysexits.h(3) error code. .SH UNICODE -Strcmp will exit unsuccessfully if the given strings are not identical; -Unicode strings may need to be normalized if the intent is to check visual -similarity and not byte similarity. +The program will exit unsuccessfully if the given strings are not identical; +therefore, unicode strings may need to be normalized if the intent is to check +visual similarity and not byte similarity. .SH RATIONALE @@ -45,7 +46,7 @@ The traditional tool for string comparisons in POSIX and other Unix shells has been test(1). This tool also handles integer comparisons and file scrutiny. These parts of its functionality have been broken out into multiple utilities. -Strcmp’s functionality may be performed on a POSIX-compliant system with +This program’s functionality may be performed on a POSIX-compliant system with test(1p). .SH AUTHOR diff --git a/docs/swab.1 b/docs/swab.1 index a0c1be3..f7e10b0 100644 --- a/docs/swab.1 +++ b/docs/swab.1 @@ -1,4 +1,5 @@ .\" Copyright (c) 2024 DTB +.\" Copyright (c) 2024 Emma Tebibyte .\" .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . @@ -20,46 +21,51 @@ swab .SH USAGE -Swab swaps the latter and former halves of a block of bytes. +Swap the latter and former halves of a block of bytes. + +.SH OPTIONS + +.B -f +.RS +Ignore system call interruptions. +.RE + +.B -w +.RS +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. +.RE .SH EXAMPLES The following sh(1p) line: +.RS .R printf 'hello world!\n' | swab +.RE Produces the following output: +.RS .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. +.RE .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). +In the event of an error, a debug message will be printed and the program will +exit with the appropriate sysexits.h(3) error code. .SH RATIONALE -Swab was modeled after the +This program was modeled and named 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. +functionality specified in the dd(1p) utility. It additionally allows the word +size to be configured. + +This functionality is useful for fixing the endianness of binary files produced +on other machines. .SH COPYRIGHT diff --git a/docs/true.1 b/docs/true.1 index 3c292d8..9b02fdd 100644 --- a/docs/true.1 +++ b/docs/true.1 @@ -1,5 +1,5 @@ .\" Copyright (c) 2022, 2024 DTB -.\" Copyright (c) 2023 Emma Tebibyte +.\" Copyright (c) 2023–2024 Emma Tebibyte .\" .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . @@ -12,14 +12,13 @@ true \(en do nothing, successfully .SH DESCRIPTION -True does nothing regardless of operands or standard input. -True will always return an exit code of 0. +Do nothing regardless of operands or standard input. +An exit code of 0 will always be returned. .SH RATIONALE -True exists for the construction of control flow and loops based on a success. - -True functions as described in POSIX.1-2017. +In POSIX.1-2017, true(1p) exists for the construction of control flow and loops +based on a success. This implementation functions as described in that standard. .SH AUTHOR From a1902df50351218bbad093cbdee9e27aa1054611 Mon Sep 17 00:00:00 2001 From: emma Date: Tue, 26 Mar 2024 23:50:16 -0600 Subject: [PATCH 008/343] strcmp.1: Unicode is a proper noun --- docs/strcmp.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/strcmp.1 b/docs/strcmp.1 index c2103dd..48681c6 100644 --- a/docs/strcmp.1 +++ b/docs/strcmp.1 @@ -37,7 +37,7 @@ exit with the appropriate sysexits.h(3) error code. .SH UNICODE The program will exit unsuccessfully if the given strings are not identical; -therefore, unicode strings may need to be normalized if the intent is to check +therefore, Unicode strings may need to be normalized if the intent is to check visual similarity and not byte similarity. .SH RATIONALE From f565f0530b041c45d82e27a5045349107a32d0b5 Mon Sep 17 00:00:00 2001 From: emma Date: Tue, 26 Mar 2024 23:53:10 -0600 Subject: [PATCH 009/343] dj.1: dd(1p) is not a disk utility --- docs/dj.1 | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 3c57155..c1bb81d 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -177,13 +177,12 @@ versions of lowercase options. .SH RATIONALE -The dd(1p) utility specified in POSIX was the basis of this program. - -It includes additional features: typical option formatting, allowing seeks to be -specified in bytes rather than in blocks, allowing arbitrary bytes as padding, -and printing in a format that’s easy to parse for machines. It also neglects -character conversion. This may have been the original intent of dd(1p) but it is -irrelevant to its modern use as a disk utility. +This program was based on the dd(1p) utility as specified in POSIX. While +character conversion may have been the original intent of dd(1p), it is +irrelevant to its modern use. Because of this, it eschews character conversion +and adds typical option formatting, allowing seeks to be specified in bytes +rather than in blocks, allowing arbitrary bytes as padding, and printing in a +format that’s easy to parse for machines. .SH COPYRIGHT From bb43533a374bd95dc844e1d9854777e0ccd99277 Mon Sep 17 00:00:00 2001 From: emma Date: Tue, 26 Mar 2024 23:58:00 -0600 Subject: [PATCH 010/343] dj.1: -A and -a: fix descriptions --- docs/dj.1 | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index c1bb81d..a787544 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -45,11 +45,13 @@ dj .B output offset .R ]) -.SH USAGE +.SH OPTIONS .B -A .RS -Takes no arguments and pads with nuls. +If the output is a stream, nul bytes are printed. In other words, it does what +.B -a +does but with null bytes instead. .RE .B -B @@ -74,8 +76,8 @@ output is a stream, nul characters are printed. .B -a .RS -Takes one argument of one byte in length and pads the input buffer with -that byte in the event that a read doesn’t fill the input buffer, and the +Takes one argument of one byte in length and pads the input buffer with it in +the event of an incomplete read from the input file. .RE .B -b From 49e2022e521e7530bd4201a365f48d586ba037e9 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 27 Mar 2024 00:08:43 -0600 Subject: [PATCH 011/343] dj.1: -d, -i, -o, fixed descriptions --- docs/dj.1 | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index a787544..41c4f3e 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -95,41 +95,42 @@ continue reading until a partial or empty read. .B -d .RS Prints all debug information, user-specified or otherwise, before program -execution. +execution. Each invocation increments the debug level of the program. .RE .B -i .RS -Takes a path as an argument to open and use in place of standard input. +Takes a file path as an argument to open and use as an input. .RE .B -n .RS -Causes dj to exit on two consecutive empty reads instead of one. +Retries failed reads once more before exiting. .RE .B -o .RS -Does the same as -.B -i -but in place of standard output. Dj does not truncate output -files and instead writes over the bytes in the existing file. +Takes a file path as an argument to open and use as an output. .RE .B -s .RS Takes a numeric argument as the number of bytes to skip into the input -before starting to read. +before starting to read. If the standard input is used, bytes read to this point +are discarded. .RE .B -q .RS Suppresses error messages which print when a read or write is partial or -empty. When -.B -q -is specified twice suppresses diagnostic output entirely. +empty. Each invocation decrements the debug level of the program. .RE +.SH STANDARD INPUT + +The standard input shall be used as an input if one or more of the input files +is “-”. + .SH DIAGNOSTICS On a partial or empty read, dj prints a diagnostic message (unless the @@ -177,6 +178,10 @@ Many lowercase options have capitalized variants and vice-versa which can be confusing. Capitalized options tend to affect output or are more intense versions of lowercase options. +.SH CAVEATS + +Output files are not truncated on ouput and are instead overwritten. + .SH RATIONALE This program was based on the dd(1p) utility as specified in POSIX. While From a2188dc674eb8d8b9801f6060dd31a44f9e378d6 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 27 Mar 2024 00:09:17 -0600 Subject: [PATCH 012/343] dj.1: fix -H description --- docs/dj.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dj.1 b/docs/dj.1 index 41c4f3e..c38a05d 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -63,7 +63,7 @@ but for the output buffer. .B -H .RS -Prints diagnostics messages in an alternate manner as described in the +Prints diagnostics messages in a human-readable manner as described in the DIAGNOSTICS section below. .RE From 6158a39a4ae58c195763777cd7a39d285248cb90 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 27 Mar 2024 00:14:02 -0600 Subject: [PATCH 013/343] dj.1: consistency with mm.1 --- docs/dj.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dj.1 b/docs/dj.1 index c38a05d..7e4b40b 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -180,7 +180,7 @@ versions of lowercase options. .SH CAVEATS -Output files are not truncated on ouput and are instead overwritten. +Existing files are not truncated on ouput and are instead overwritten. .SH RATIONALE From 3cb37d830a84710fc5493a953cc1a3b853e21f82 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 27 Mar 2024 00:14:34 -0600 Subject: [PATCH 014/343] mm.1: wording, consistency with dj.1 --- docs/mm.1 | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/docs/mm.1 b/docs/mm.1 index c8cc5dc..42a3e74 100644 --- a/docs/mm.1 +++ b/docs/mm.1 @@ -26,12 +26,12 @@ Catenate input files and write them to the start of each output file or stream. .B -a .RS -Opens subsequent outputs for appending rather than updating. +Opens outputs for appending rather than updating. .RE .B -e .RS -Set the output to the standard error. +Use the standard error as an output. .RE .B -i @@ -56,6 +56,11 @@ Ensures neither input or output will be buffered. Causes SIGINT signals to be ignored. .RE +.SH STANDARD INPUT + +The standard input shall be used as an input if one or more of the input files +is “-”. + .SH DIAGNOSTICS If an output can no longer be written mm prints a diagnostic message, ceases @@ -65,15 +70,15 @@ continues, eventually exiting unsuccessfully. When an error is encountered, diagnostic message is printed and the program exits with the appropriate sysexits.h(3) status. -.SH BUGS +.SH CAVEATS -Existing files are not truncated, which may lead to unexpected results. +Existing files are not truncated on ouput and are instead overwritten. .SH RATIONALE -The cat(1p) and tee(1p) programs specified in POSIX provide equivalent -functionality. The separation of the two sets of functionality into separate -APIs seemed unncessary. +The cat(1p) and tee(1p) programs specified in POSIX together provide nearly +equivalent functionality. The separation of the two sets of functionality into +separate APIs seemed unncessary. .SH COPYRIGHT From d3bfc7b1f540e1b131deb36e2343fda9281b7686 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 27 Mar 2024 00:16:15 -0600 Subject: [PATCH 015/343] npc.1: ASCII bytes --- docs/npc.1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/npc.1 b/docs/npc.1 index daad9f1..f3b7d0c 100644 --- a/docs/npc.1 +++ b/docs/npc.1 @@ -21,9 +21,9 @@ Print normally non-printing characters. The program reads from standard input and writes to standard output, replacing non-printing characters with printable equivalents. Control characters print as -a carat (“^”) followed by the character “@” through “_” corresponding to the -character replaced (e.g. control-X becomes “^X”). The delete character (0x7F) -becomes “^?”. Characters with the high bit set (>127) are printed as “M-” +a carat ('^') followed by the character '@' through '_' corresponding to the +character replaced (e.g. control-X becomes '^X'). The delete character (0x7F) +becomes '^?'. Characters with the high bit set (>127) are printed as 'M-' followed by the graphical representation for the same character without the high bit set. @@ -31,12 +31,12 @@ high bit set. .B -e .RS -Prints a currency sign (“$”) before each line ending. +Prints a currency sign ('$') before each line ending. .RE .B -t .RS -Prints tab characters as “^I” rather than a literal horizontal tab. +Prints tab characters as '^I' rather than a literal horizontal tab. .RE .SH DIAGNOSTICS From cdd8e79b01092a307d381d52baa01b6826c8dae0 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 27 Mar 2024 00:16:51 -0600 Subject: [PATCH 016/343] str.1: strings are not tested against each other --- docs/str.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/str.1 b/docs/str.1 index e671ecd..666f0b1 100644 --- a/docs/str.1 +++ b/docs/str.1 @@ -18,7 +18,7 @@ str .SH DESCRIPTION -Test string arguments against each other. +Test string arguments. The tests in this program are equivalent to the functions with the same names in ctype.h(0p) and are the methods by which string arguments are tested. From 603d8ee1d88a84c311ef6af19c7af14d0986eef4 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 27 Mar 2024 00:17:33 -0600 Subject: [PATCH 017/343] str.1: remove extraneous former implementation information --- docs/str.1 | 6 ------ 1 file changed, 6 deletions(-) diff --git a/docs/str.1 b/docs/str.1 index 666f0b1..ef86861 100644 --- a/docs/str.1 +++ b/docs/str.1 @@ -34,12 +34,6 @@ tests. When invoked incorrectly, a debug message will be printed and the program will exit with the appropriate sysexits.h(3) error code. -.SH DEPRECATED FEATURES - -Originally, there was an isvalue type as an extension to ctype.h(3), but it -was removed in favor of using strcmp(1) to compare strings against the empty -string (''). - .SH BUGS There’s no way of knowing which argument failed the test without re-testing From 70b0c2f9243385cb79d912aaf26372cbe4d88784 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 29 Mar 2024 16:14:27 -0600 Subject: [PATCH 018/343] dj.1: fixed -d description --- docs/dj.1 | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 7e4b40b..631fa7b 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -94,8 +94,9 @@ continue reading until a partial or empty read. .B -d .RS -Prints all debug information, user-specified or otherwise, before program -execution. Each invocation increments the debug level of the program. +Prints invocation information before program execution as described in the +DIAGNOSTICS section below. Each invocation increments the debug level of the +program. .RE .B -i @@ -133,9 +134,9 @@ is “-”. .SH DIAGNOSTICS -On a partial or empty read, dj prints a diagnostic message (unless the +On a partial or empty read, a diagnostic message is printed (unless the .B -q -option is specified) and exits (unless the +option is specified) and the program exits (unless the .B -n option is specified. @@ -159,6 +160,20 @@ option is specified, the following format is used instead: .R {ASCII line feed} .RE +If the +.B -d +option is specified, debug output will be printed at the beginning of execution. +This debug information contains information regarding how the program was +invoked. The following example is the result of running the program with +.B -d +as the only argument: + +.RS +.R argv0=dj +.R in= ibs=1024 skip=0 align=ff count=0 +.R out= obs=1024 seek=0 debug= 3 noerror=0 +.RE + In non-recoverable errors that don’t pertain to the read-write cycle, a diagnostic message is printed and the program exits with the appropriate sysexits.h(3) status. From 4e33f945ae632ff79090fe5be0c5a01583a4d7e0 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 29 Mar 2024 16:17:48 -0600 Subject: [PATCH 019/343] dj.1: null bytes --- docs/dj.1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 631fa7b..d309678 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -49,7 +49,7 @@ dj .B -A .RS -If the output is a stream, nul bytes are printed. In other words, it does what +If the output is a stream, null bytes are printed. In other words, it does what .B -a does but with null bytes instead. .RE @@ -71,7 +71,7 @@ DIAGNOSTICS section below. .RS Skips a number of bytes through the output before starting to write from the input. If the input is a stream the bytes are read and discarded. If the -output is a stream, nul characters are printed. +output is a stream, null characters are printed. .RE .B -a From 9ea57a27b7e68d49e01191324de7be724046cd2a Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 29 Mar 2024 16:21:02 -0600 Subject: [PATCH 020/343] dj.1: stdin by default --- docs/dj.1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index d309678..0e882dd 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -129,8 +129,8 @@ empty. Each invocation decrements the debug level of the program. .SH STANDARD INPUT -The standard input shall be used as an input if one or more of the input files -is “-”. +The standard input shall be used as an input if no inputs are specified one or +more of the input files is “-”. .SH DIAGNOSTICS From 63c8ff8093564e3a88d1b4021790fb9afef36dd9 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 29 Mar 2024 16:22:56 -0600 Subject: [PATCH 021/343] intcmp.1: compares integers to each other --- docs/intcmp.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/intcmp.1 b/docs/intcmp.1 index 209b2d8..6087d0e 100644 --- a/docs/intcmp.1 +++ b/docs/intcmp.1 @@ -19,7 +19,7 @@ intcmp .SH DESCRIPTION -Compare integers. +Compare integers to each other. .SH USAGE From abc599148da8ab93e7eb41604dcc04bbfa342be1 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 29 Mar 2024 16:26:41 -0600 Subject: [PATCH 022/343] mm.1: subsequent outputs are opened for appending --- docs/mm.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/mm.1 b/docs/mm.1 index 42a3e74..01790fd 100644 --- a/docs/mm.1 +++ b/docs/mm.1 @@ -26,7 +26,7 @@ Catenate input files and write them to the start of each output file or stream. .B -a .RS -Opens outputs for appending rather than updating. +Opens subsequent outputs for appending rather than updating. .RE .B -e From ce5a4dc4bd043febdf02e33c22f309e3a77f0e19 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 29 Mar 2024 16:29:27 -0600 Subject: [PATCH 023/343] mm.1: removed STANDARD INPUT section --- docs/mm.1 | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/docs/mm.1 b/docs/mm.1 index 01790fd..6a1f664 100644 --- a/docs/mm.1 +++ b/docs/mm.1 @@ -37,13 +37,16 @@ Use the standard error as an output. .B -i .RS Opens a path as an input. Without any inputs specified mm will use the -standard input. +standard input. The standard input shall be used as an input if one or more of +the input files is “-”. .RE .B -o .RS Opens a path as an output. Without any outputs specified mm will use the -standard output. +standard output. The standard output shall be used as an output if one or more +of the output files is “-”. + .RE .B -u @@ -56,11 +59,6 @@ Ensures neither input or output will be buffered. Causes SIGINT signals to be ignored. .RE -.SH STANDARD INPUT - -The standard input shall be used as an input if one or more of the input files -is “-”. - .SH DIAGNOSTICS If an output can no longer be written mm prints a diagnostic message, ceases From 5db09a5ca19aca7b8d2e39b18bb5ac61927ff0fd Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 29 Mar 2024 16:30:06 -0600 Subject: [PATCH 024/343] mm.1: cat(1p) and tee(1p) provide similar functionality --- docs/mm.1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/mm.1 b/docs/mm.1 index 6a1f664..5315c8c 100644 --- a/docs/mm.1 +++ b/docs/mm.1 @@ -74,9 +74,9 @@ Existing files are not truncated on ouput and are instead overwritten. .SH RATIONALE -The cat(1p) and tee(1p) programs specified in POSIX together provide nearly -equivalent functionality. The separation of the two sets of functionality into -separate APIs seemed unncessary. +The cat(1p) and tee(1p) programs specified in POSIX together provide similar +functionality. The separation of the two sets of functionality into separate +APIs seemed unncessary. .SH COPYRIGHT From 13ee16173e46c09ba97fd35e6000a3455aaac174 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 29 Mar 2024 16:47:00 -0600 Subject: [PATCH 025/343] fop.1: initial commit --- docs/fop.1 | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 docs/fop.1 diff --git a/docs/fop.1 b/docs/fop.1 new file mode 100644 index 0000000..aa71b50 --- /dev/null +++ b/docs/fop.1 @@ -0,0 +1,60 @@ +.\" Copyright (c) 2024 DTB +.\" Copyright (c) 2024 Emma Tebibyte +.\" +.\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, +.\" visit . + +.TH fop 1 + +.SH NAME + +fop \(en field operator + +.SH SYNOPSIS + +fop +.RB ( -d ) +.RB [ delimiter ] +.RB index +.RB program... + +.SH DESCRIPTION + +Performs operations on specified fields in input data. + +.SH OPTIONS + +.B -d +.RS +Sets a delimiter by which the input data will be split into fields. The default +is an ASCII record separator (␞). +.RE + +.SH STANDARD INPUT + +Data will be read from the standard input. + +.SH CAVEATS + +Field indices are zero-indexed, which may be unexpected behavior for some users. + +.SH RATIONALE + +With the assumption that tools will output data separated with ASCII field +separators, there is + +The idea for this utility originated in the fact that GNU ls(1) utility contains +a +.B -h +option which enables human-readable units in file size outputs. This +functionality was broken out into hru(1), but there was no easy way to modify +the field in the ouput of ls(1p) without a new tool. + +.SH COPYRIGHT + +Copyright © 2024 Emma Tebibyte. License AGPLv3+: GNU AGPL version 3 or later +. + +.SH SEE ALSO + +sed(1p) From 320a70bc56c3e6527bad325e0756ba010ffe17fa Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 1 Apr 2024 20:37:35 -0600 Subject: [PATCH 026/343] getopt.rs(3): initial commit --- COPYING.LESSER | 165 ++++++++++++++++ Makefile | 4 +- src/getopt-rs/error.rs | 95 --------- src/getopt-rs/errorkind.rs | 61 ------ src/getopt-rs/lib.rs | 72 ------- src/getopt-rs/opt.rs | 89 --------- src/getopt-rs/parser.rs | 382 ------------------------------------- src/getopt-rs/result.rs | 59 ------ src/getopt-rs/tests.rs | 228 ---------------------- src/getopt.rs | 115 +++++++++++ 10 files changed, 282 insertions(+), 988 deletions(-) create mode 100644 COPYING.LESSER delete mode 100644 src/getopt-rs/error.rs delete mode 100644 src/getopt-rs/errorkind.rs delete mode 100644 src/getopt-rs/lib.rs delete mode 100644 src/getopt-rs/opt.rs delete mode 100644 src/getopt-rs/parser.rs delete mode 100644 src/getopt-rs/result.rs delete mode 100644 src/getopt-rs/tests.rs create mode 100644 src/getopt.rs diff --git a/COPYING.LESSER b/COPYING.LESSER new file mode 100644 index 0000000..0a04128 --- /dev/null +++ b/COPYING.LESSER @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/Makefile b/Makefile index 68efd20..7f5c36f 100644 --- a/Makefile +++ b/Makefile @@ -57,9 +57,9 @@ test: build rustlibs: build/o/libsysexits.rlib build/o/libgetopt.rlib \ build/o/libstrerror.rlib -build/o/libgetopt.rlib: build src/getopt-rs/lib.rs +build/o/libgetopt.rlib: build src/getopt.rs $(RUSTC) $(RUSTFLAGS) --crate-type=lib --crate-name=getopt \ - -o $@ src/getopt-rs/lib.rs + -o $@ src/getopt.rs build/o/libstrerror.rlib: build src/strerror.rs $(RUSTC) $(RUSTFLAGS) --crate-type=lib -o $@ \ diff --git a/src/getopt-rs/error.rs b/src/getopt-rs/error.rs deleted file mode 100644 index 322af02..0000000 --- a/src/getopt-rs/error.rs +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2023 Emma Tebibyte - * 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/. - * - * This file incorporates work covered by the following copyright and permission - * notice: - * The Clear BSD License - * - * Copyright © 2017-2023 David Wildasin - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted (subject to the limitations in the disclaimer - * below) provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions, and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED - * BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -use std::{ error, fmt }; - -use crate::ErrorKind::{ self, * }; - -/// A basic error type for [`Parser`](struct.Parser.html) -#[derive(Debug, Eq, PartialEq)] -pub struct Error { - culprit: char, - kind: ErrorKind, -} - -impl Error { - /// Creates a new error using a known kind and the character that caused the - /// issue. - pub fn new(kind: ErrorKind, culprit: char) -> Self { - Self { culprit, kind } - } - - /// Returns the [`ErrorKind`](enum.ErrorKind.html) for this error. - pub fn kind(self) -> ErrorKind { - self.kind - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.kind { - MissingArgument => write!( - f, - "option requires an argument -- {:?}", - self.culprit, - ), - UnknownOption => write!(f, "unknown option -- {:?}", self.culprit), - } - } -} - -impl error::Error for Error { - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - None - } -} diff --git a/src/getopt-rs/errorkind.rs b/src/getopt-rs/errorkind.rs deleted file mode 100644 index 5475d8e..0000000 --- a/src/getopt-rs/errorkind.rs +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2023 Emma Tebibyte - * 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/. - * - * This file incorporates work covered by the following copyright and permission - * notice: - * The Clear BSD License - * - * Copyright © 2017-2023 David Wildasin - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted (subject to the limitations in the disclaimer - * below) provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions, and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED - * BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/// What kinds of errors [`Parser`](struct.Parser.html) can return. -#[derive(Debug, Eq, PartialEq)] -pub enum ErrorKind { - /// An argument was not found for an option that was expecting one. - MissingArgument, - /// An unknown option character was encountered. - UnknownOption, -} diff --git a/src/getopt-rs/lib.rs b/src/getopt-rs/lib.rs deleted file mode 100644 index 62f0e0d..0000000 --- a/src/getopt-rs/lib.rs +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2023 Emma Tebibyte - * 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/. - * - * This file incorporates work covered by the following copyright and permission - * notice: - * The Clear BSD License - * - * Copyright © 2017-2023 David Wildasin - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted (subject to the limitations in the disclaimer - * below) provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions, and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED - * BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -//! # getopt -//! -//! `getopt` provides a minimal, (essentially) POSIX-compliant option parser. - -pub use crate::{ - error::Error, - errorkind::ErrorKind, - opt::Opt, - parser::Parser, - result::Result -}; - -mod error; -mod errorkind; -mod opt; -mod parser; -mod result; -#[cfg(test)] -mod tests; diff --git a/src/getopt-rs/opt.rs b/src/getopt-rs/opt.rs deleted file mode 100644 index 05b51e6..0000000 --- a/src/getopt-rs/opt.rs +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2023 Emma Tebibyte - * 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/. - * - * This file incorporates work covered by the following copyright and permission - * notice: - * The Clear BSD License - * - * Copyright © 2017-2023 David Wildasin - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted (subject to the limitations in the disclaimer - * below) provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions, and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED - * BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -use std::fmt; - -/// A single option. -/// -/// For `Opt(x, y)`: -/// - `x` is the character representing the option. -/// - `y` is `Some` string, or `None` if no argument was expected. -/// -/// # Example -/// -/// ``` -/// # fn main() -> Result<(), Box> { -/// use getopt::Opt; -/// -/// // args = ["program", "-abc", "foo"]; -/// # let args: Vec = vec!["program", "-abc", "foo"] -/// # .into_iter() -/// # .map(String::from) -/// # .collect(); -/// let optstring = "ab:c"; -/// let mut opts = getopt::Parser::new(&args, optstring); -/// -/// assert_eq!(Opt('a', None), opts.next().transpose()?.unwrap()); -/// assert_eq!(Opt('b', Some("c".to_string())), opts.next().transpose()?.unwrap()); -/// assert_eq!(None, opts.next().transpose()?); -/// # Ok(()) -/// # } -/// ``` -#[derive(Debug, Eq, Ord, PartialEq, PartialOrd)] -pub struct Opt(pub char, pub Option); - -impl fmt::Display for Opt { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Opt({:?}, {:?})", self.0, self.1) - } -} diff --git a/src/getopt-rs/parser.rs b/src/getopt-rs/parser.rs deleted file mode 100644 index 6f06cc3..0000000 --- a/src/getopt-rs/parser.rs +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Copyright (c) 2023 Emma Tebibyte - * 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/. - * - * This file incorporates work covered by the following copyright and permission - * notice: - * The Clear BSD License - * - * Copyright © 2017-2023 David Wildasin - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted (subject to the limitations in the disclaimer - * below) provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions, and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED - * BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -use std::collections::HashMap; - -use crate::{ error::Error, errorkind::ErrorKind, opt::Opt, result::Result }; - -/// The core of the `getopt` crate. -/// -/// `Parser` is implemented as an iterator over the options present in the given -/// argument vector. -/// -/// The method [`next`](#method.next) does the heavy lifting. -/// -/// # Examples -/// -/// ## Simplified usage: -/// ``` -/// # fn main() -> Result<(), Box> { -/// use getopt::Opt; -/// -/// // args = ["program", "-abc", "foo"]; -/// # let args: Vec = vec!["program", "-abc", "foo"] -/// # .into_iter() -/// # .map(String::from) -/// # .collect(); -/// let mut opts = getopt::Parser::new(&args, "ab:c"); -/// -/// assert_eq!(Some(Opt('a', None)), opts.next().transpose()?); -/// assert_eq!(1, opts.index()); -/// assert_eq!(Some(Opt('b', Some("c".to_string()))), opts.next().transpose()?); -/// assert_eq!(2, opts.index()); -/// assert_eq!(None, opts.next()); -/// assert_eq!(2, opts.index()); -/// assert_eq!("foo", args[opts.index()]); -/// # Ok(()) -/// # } -/// ``` -/// -/// ## A more idiomatic example: -/// ``` -/// # fn main() -> Result<(), Box> { -/// use getopt::Opt; -/// -/// // args = ["program", "-abc", "-d", "foo", "-e", "bar"]; -/// # let mut args: Vec = vec!["program", "-abc", "-d", "foo", "-e", "bar"] -/// # .into_iter() -/// # .map(String::from) -/// # .collect(); -/// let mut opts = getopt::Parser::new(&args, "ab:cd:e"); -/// -/// let mut a_flag = false; -/// let mut b_flag = String::new(); -/// let mut c_flag = false; -/// let mut d_flag = String::new(); -/// let mut e_flag = false; -/// -/// loop { -/// match opts.next().transpose()? { -/// None => break, -/// Some(opt) => match opt { -/// Opt('a', None) => a_flag = true, -/// Opt('b', Some(arg)) => b_flag = arg.clone(), -/// Opt('c', None) => c_flag = true, -/// Opt('d', Some(arg)) => d_flag = arg.clone(), -/// Opt('e', None) => e_flag = true, -/// _ => unreachable!(), -/// }, -/// } -/// } -/// -/// let new_args = args.split_off(opts.index()); -/// -/// assert_eq!(true, a_flag); -/// assert_eq!("c", b_flag); -/// assert_eq!(false, c_flag); -/// assert_eq!("foo", d_flag); -/// assert_eq!(true, e_flag); -/// -/// assert_eq!(1, new_args.len()); -/// assert_eq!("bar", new_args.first().unwrap()); -/// # Ok(()) -/// # } -/// ``` -#[derive(Debug, Eq, PartialEq)] -pub struct Parser { - opts: HashMap, - args: Vec>, - index: usize, - point: usize, -} - -impl Parser { - /// Create a new `Parser`, which will process the arguments in `args` - /// according to the options specified in `optstring`. - /// - /// For compatibility with - /// [`std::env::args`](https://doc.rust-lang.org/std/env/fn.args.html), - /// valid options are expected to begin at the second element of `args`, and - /// `index` is - /// initialised to `1`. - /// If `args` is structured differently, be sure to call - /// [`set_index`](#method.set_index) before the first invocation of - /// [`next`](#method.next). - /// - /// `optstring` is a string of recognised option characters; if a character - /// is followed by a colon (`:`), that option takes an argument. - /// - /// # Note: - /// Transforming the OS-specific argument strings into a vector of `String`s - /// is the sole responsibility of the calling program, as it involves some - /// level of potential information loss (which this crate does not presume - /// to handle unilaterally) and error handling (which would complicate the - /// interface). - pub fn new(args: &[String], optstring: &str) -> Self { - let optstring: Vec = optstring.chars().collect(); - let mut opts = HashMap::new(); - let mut i = 0; - let len = optstring.len(); - - while i < len { - let j = i + 1; - - if j < len && optstring[j] == ':' { - opts.insert(optstring[i], true); - i += 1; - } else { - opts.insert(optstring[i], false); - } - i += 1; - } - - Self { - opts, - // "explode" the args into a vector of character vectors, to allow - // indexing - args: args.iter().map(|e| e.chars().collect()).collect(), - index: 1, - point: 0, - } - } - - /// Return the current `index` of the parser. - /// - /// `args[index]` will always point to the the next element of `args`; when - /// the parser is - /// finished with an element, it will increment `index`. - /// - /// After the last option has been parsed (and [`next`](#method.next) is - /// returning `None`), - /// `index` will point to the first non-option argument. - pub fn index(&self) -> usize { - self.index - } - - // `point` must be reset to 0 whenever `index` is changed - - /// Modify the current `index` of the parser. - pub fn set_index(&mut self, value: usize) { - self.index = value; - self.point = 0; - } - - /// Increment the current `index` of the parser. - /// - /// This use case is common enough to warrant its own optimised method. - pub fn incr_index(&mut self) { - self.index += 1; - self.point = 0; - } -} - -impl Iterator for Parser { - type Item = Result; - - /// Returns the next option, if any. - /// - /// Returns an [`Error`](struct.Error.html) if an unexpected option is - /// encountered or if an - /// expected argument is not found. - /// - /// Parsing stops at the first non-hyphenated argument; or at the first - /// argument matching "-"; - /// or after the first argument matching "--". - /// - /// When no more options are available, `next` returns `None`. - /// - /// # Examples - /// - /// ## "-" - /// ``` - /// use getopt::Parser; - /// - /// // args = ["program", "-", "-a"]; - /// # let args: Vec = vec!["program", "-", "-a"] - /// # .into_iter() - /// # .map(String::from) - /// # .collect(); - /// let mut opts = Parser::new(&args, "a"); - /// - /// assert_eq!(None, opts.next()); - /// assert_eq!("-", args[opts.index()]); - /// ``` - /// - /// ## "--" - /// ``` - /// use getopt::Parser; - /// - /// // args = ["program", "--", "-a"]; - /// # let args: Vec = vec!["program", "--", "-a"] - /// # .into_iter() - /// # .map(String::from) - /// # .collect(); - /// let mut opts = Parser::new(&args, "a"); - /// - /// assert_eq!(None, opts.next()); - /// assert_eq!("-a", args[opts.index()]); - /// ``` - /// - /// ## Unexpected option: - /// ``` - /// use getopt::Parser; - /// - /// // args = ["program", "-b"]; - /// # let args: Vec = vec!["program", "-b"] - /// # .into_iter() - /// # .map(String::from) - /// # .collect(); - /// let mut opts = Parser::new(&args, "a"); - /// - /// assert_eq!( - /// "unknown option -- 'b'".to_string(), - /// opts.next().unwrap().unwrap_err().to_string() - /// ); - /// ``` - /// - /// ## Missing argument: - /// ``` - /// use getopt::Parser; - /// - /// // args = ["program", "-a"]; - /// # let args: Vec = vec!["program", "-a"] - /// # .into_iter() - /// # .map(String::from) - /// # .collect(); - /// let mut opts = Parser::new(&args, "a:"); - /// - /// assert_eq!( - /// "option requires an argument -- 'a'".to_string(), - /// opts.next().unwrap().unwrap_err().to_string() - /// ); - /// ``` - fn next(&mut self) -> Option> { - if self.point == 0 { - /* - * Rationale excerpts below taken verbatim from "The Open Group Base - * Specifications Issue 7, 2018 edition", IEEE Std 1003.1-2017 - * (Revision of IEEE Std 1003.1-2008). - * Copyright © 2001-2018 IEEE and The Open Group. - */ - - /* - * If, when getopt() is called: - * argv[optind] is a null pointer - * *argv[optind] is not the character '-' - * argv[optind] points to the string "-" - * getopt() shall return -1 without changing optind. - */ - if self.index >= self.args.len() - || self.args[self.index].is_empty() - || self.args[self.index][0] != '-' - || self.args[self.index].len() == 1 - { - return None; - } - - /* - * If: - * argv[optind] points to the string "--" - * getopt() shall return -1 after incrementing index. - */ - if self.args[self.index][1] == '-' && self.args[self.index].len() == 2 { - self.incr_index(); - return None; - } - - // move past the starting '-' - self.point += 1; - } - - let opt = self.args[self.index][self.point]; - self.point += 1; - - match self.opts.get(&opt) { - None => { - if self.point >= self.args[self.index].len() { - self.incr_index(); - } - Some(Err(Error::new(ErrorKind::UnknownOption, opt))) - } - Some(false) => { - if self.point >= self.args[self.index].len() { - self.incr_index(); - } - - Some(Ok(Opt(opt, None))) - } - Some(true) => { - let arg: String = if self.point >= self.args[self.index].len() { - self.incr_index(); - if self.index >= self.args.len() { - return Some(Err(Error::new( - ErrorKind::MissingArgument, - opt, - ))); - } - self.args[self.index].iter().collect() - } else { - self.args[self.index] - .clone() - .split_off(self.point) - .iter() - .collect() - }; - - self.incr_index(); - - Some(Ok(Opt(opt, Some(arg)))) - } - } - } -} diff --git a/src/getopt-rs/result.rs b/src/getopt-rs/result.rs deleted file mode 100644 index 015a402..0000000 --- a/src/getopt-rs/result.rs +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2023 Emma Tebibyte - * 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/. - * - * This file incorporates work covered by the following copyright and permission - * notice: - * The Clear BSD License - * - * Copyright © 2017-2023 David Wildasin - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted (subject to the limitations in the disclaimer - * below) provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions, and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED - * BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -use std::result; - -use crate::error::Error; - -/// A specialized `Result` type for use with [`Parser`](struct.Parser.html) -pub type Result = result::Result; diff --git a/src/getopt-rs/tests.rs b/src/getopt-rs/tests.rs deleted file mode 100644 index c53d517..0000000 --- a/src/getopt-rs/tests.rs +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (c) 2023 Emma Tebibyte - * 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/. - * - * This file incorporates work covered by the following copyright and permission - * notice: - * The Clear BSD License - * - * Copyright © 2017-2023 David Wildasin - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted (subject to the limitations in the disclaimer - * below) provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions, and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED - * BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -use crate::{Opt, Parser}; - -macro_rules! basic_test { - ($name:ident, $expect:expr, $next:expr, [$($arg:expr),+], $optstr:expr) => ( - #[test] - fn $name() -> Result<(), String> { - let expect: Option = $expect; - let args: Vec = vec![$($arg),+] - .into_iter() - .map(String::from) - .collect(); - let next: Option = $next; - let mut opts = Parser::new(&args, $optstr); - - match opts.next().transpose() { - Err(error) => { - return Err(format!("next() returned {:?}", error)) - }, - Ok(actual) => if actual != expect { - return Err( - format!("expected {:?}; got {:?}", expect, actual) - ) - }, - }; - - match next { - None => if opts.index() < args.len() { - return Err(format!( - "expected end of args; got {:?}", args[opts.index()] - )) - }, - Some(n) => if args[opts.index()] != n { - return Err(format!( - "next arg: expected {:?}; got {:?}", - n, - args[opts.index()] - )) - }, - }; - - Ok(()) - } - ) -} - -#[rustfmt::skip] basic_test!( - blank_arg, None, Some(String::new()), ["x", ""], "a" -); -#[rustfmt::skip] basic_test!( - double_dash, None, Some("-a".to_string()), ["x", "--", "-a", "foo"], "a" -); -#[rustfmt::skip] basic_test!(no_opts_1, None, None, ["x"], "a"); -#[rustfmt::skip] basic_test!( - no_opts_2, None, Some("foo".to_string()), ["x", "foo"], "a" -); -#[rustfmt::skip] basic_test!( - no_opts_3, None, Some("foo".to_string()), ["x", "foo", "-a"], "a" -); -#[rustfmt::skip] basic_test!( - single_dash, None, Some("-".to_string()), ["x", "-", "-a", "foo"], "a" -); -#[rustfmt::skip] basic_test!( - single_opt, - Some(Opt('a', None)), - Some("foo".to_string()), - ["x", "-a", "foo"], - "a" -); -#[rustfmt::skip] basic_test!( - single_optarg, - Some(Opt('a', Some("foo".to_string()))), - None, - ["x", "-a", "foo"], - "a:" -); - -macro_rules! error_test { - ($name:ident, $expect:expr, [$($arg:expr),+], $optstr:expr) => ( - #[test] - fn $name() -> Result<(), String> { - let expect: String = $expect.to_string(); - let args: Vec = vec![$($arg),+] - .into_iter() - .map(String::from) - .collect(); - let mut opts = Parser::new(&args, $optstr); - - match opts.next() { - None => { - return Err(format!( - "unexpected successful response: end of options" - )) - }, - Some(Err(actual)) => { - let actual = actual.to_string(); - - if actual != expect { - return Err( - format!("expected {:?}; got {:?}", expect, actual) - ); - } - }, - Some(Ok(opt)) => { - return Err( - format!("unexpected successful response: {:?}", opt) - ) - }, - }; - - Ok(()) - } - ) -} - -#[rustfmt::skip] error_test!( - bad_opt, - "unknown option -- 'b'", - ["x", "-b"], - "a" -); - -#[rustfmt::skip] error_test!( - missing_optarg, - "option requires an argument -- 'a'", - ["x", "-a"], - "a:" -); - -#[test] -fn multiple() -> Result<(), String> { - let args: Vec = vec!["x", "-abc", "-d", "foo", "-e", "bar"] - .into_iter() - .map(String::from) - .collect(); - let optstring = "ab:d:e".to_string(); - let mut opts = Parser::new(&args, &optstring); - - macro_rules! check_result { - ($expect:expr) => { - let expect: Option = $expect; - match opts.next().transpose() { - Err(error) => { - return Err(format!("next() returned {:?}", error)); - }, - Ok(actual) => { - if actual != expect { - return Err( - format!("expected {:?}; got {:?}", expect, actual) - ); - } - } - }; - }; - } - - check_result!(Some(Opt('a', None))); - check_result!(Some(Opt('b', Some("c".to_string())))); - check_result!(Some(Opt('d', Some("foo".to_string())))); - check_result!(Some(Opt('e', None))); - check_result!(None); - - Ok(()) -} - -#[test] -fn continue_after_error() { - let args: Vec = vec!["x", "-z", "-abc"] - .into_iter() - .map(String::from) - .collect(); - let optstring = "ab:d:e".to_string(); - for _opt in Parser::new(&args, &optstring) { - // do nothing, should not panic - } -} diff --git a/src/getopt.rs b/src/getopt.rs new file mode 100644 index 0000000..f7668c6 --- /dev/null +++ b/src/getopt.rs @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2024 Emma Tebibyte + * SPDX-License-Identifier: LGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser 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 Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ + +use std::ffi::{ c_int, c_char, CString }; + +pub struct Opt { + pub arg: Option, + pub ind: i32, + pub opt: i32, +} + +pub enum OptError { + MissingArg, + UnknownOpt, +} + +// Function signature +pub trait GetOpt { + fn getopt( + argv: Vec, + optstring: &str + ) -> Option>; +} + +impl GetOpt for Vec { + fn getopt( + argv: Vec, + optstring: &str + ) -> Option> { + unsafe { + let args = argv + .iter() + .cloned() + .map(CString::new) + .map(Result::unwrap) + .map(|x| x.as_ptr() as c_char) + .collect::>() + .as_ptr() as *const *mut c_char; + + let len = argv.len() as c_int; + let opts = CString::new(optstring).unwrap().into_raw(); + + let a = match getopt(len, args, opts) { + /* From getopt(3p): + * + * The getopt() function shall return the next option character + * specified on the command line. + * + * A (':') shall be returned if getopt() detects a + * missing argument and the first character of optstring was a + * (':'). + * + * A ('?') shall be returned if getopt() + * encounters an option character not in optstring or detects a + * missing argument and the first character of optstring was not + * a (':'). + * + * Otherwise, getopt() shall return -1 when all command line + * options are parsed. */ + 58 => { // ASCII value for ':' + return Some(Err(OptError::MissingArg)); + }, + 63 => { // ASCII value for '?' + return Some(Err(OptError::UnknownOpt)); + }, + /* From getopt(3p): + * + * If, when getopt() is called: + * + * argv[optind] is a null pointer + * *argv[optind] is not the character - + * argv[optind] points to the string "-" + * + * getopt() shall return -1 without changing optind. If: + * + * argv[optind] points to the string "--" + * + * getopt() shall return -1 after incrementing optind. */ + -1 => return None, + a => a.to_string(), + }; + + Some(Ok(Opt { arg: Some(a), ind: optind, opt: optopt })) + } + } +} + +/* binding to getopt(3p) */ +extern "C" { + static mut _optarg: *mut c_char; + static mut _opterr: c_int; + static mut optind: c_int; + static mut optopt: c_int; + + fn getopt( + ___argc: c_int, + ___argv: *const *mut c_char, + __shortopts: *const c_char, + ) -> c_int; +} From 0164b681c03604f2532d97f52ba0061ef23beaf4 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 1 Apr 2024 20:41:07 -0600 Subject: [PATCH 027/343] Makefile: remove unneeded test --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index 7f5c36f..7736a78 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,6 @@ install: dist .PHONY: test test: build tests/posix-compat.sh - $(RUSTC) --test src/getopt-rs/lib.rs -o build/test/getopt .PHONY: rustlibs rustlibs: build/o/libsysexits.rlib build/o/libgetopt.rlib \ From 88b0d5544001d326496b335bf626562c68481c1c Mon Sep 17 00:00:00 2001 From: emma Date: Thu, 11 Apr 2024 20:21:01 -0600 Subject: [PATCH 028/343] getopt.rs(3): refactor to remove as much as possible from unsafe --- src/getopt.rs | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/src/getopt.rs b/src/getopt.rs index f7668c6..b95108c 100644 --- a/src/getopt.rs +++ b/src/getopt.rs @@ -31,31 +31,24 @@ pub enum OptError { // Function signature pub trait GetOpt { - fn getopt( - argv: Vec, - optstring: &str - ) -> Option>; + fn getopt(&self, optstring: &str) -> Option>; } impl GetOpt for Vec { - fn getopt( - argv: Vec, - optstring: &str - ) -> Option> { + fn getopt(&self, optstring: &str) -> Option> { + let argv = self + .iter() + .cloned() + .map(CString::new) + .map(Result::unwrap) + .map(|x| x.as_ptr() as c_char) + .collect::>() + .as_ptr() as *const *mut c_char; + let opts = CString::new(optstring).unwrap().into_raw(); + let len = self.len() as c_int; + unsafe { - let args = argv - .iter() - .cloned() - .map(CString::new) - .map(Result::unwrap) - .map(|x| x.as_ptr() as c_char) - .collect::>() - .as_ptr() as *const *mut c_char; - - let len = argv.len() as c_int; - let opts = CString::new(optstring).unwrap().into_raw(); - - let a = match getopt(len, args, opts) { + let a = match getopt(len, argv, opts) { /* From getopt(3p): * * The getopt() function shall return the next option character From bb2c63bfafc19cd468b7fb9ebbdb3dd4e411d2b4 Mon Sep 17 00:00:00 2001 From: emma Date: Thu, 11 Apr 2024 20:33:42 -0600 Subject: [PATCH 029/343] getopt.rs(3): fixed pointer shenanigans --- src/getopt.rs | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/getopt.rs b/src/getopt.rs index b95108c..81c146d 100644 --- a/src/getopt.rs +++ b/src/getopt.rs @@ -16,7 +16,7 @@ * along with this program. If not, see https://www.gnu.org/licenses/. */ -use std::ffi::{ c_int, c_char, CString }; +use std::ffi::{ c_int, c_char, CString, CStr }; pub struct Opt { pub arg: Option, @@ -35,20 +35,22 @@ pub trait GetOpt { } impl GetOpt for Vec { - fn getopt(&self, optstring: &str) -> Option> { - let argv = self + fn getopt(&self, optstring: &str) -> Option> { + let c_strings: Vec<_> = self .iter() .cloned() .map(CString::new) .map(Result::unwrap) - .map(|x| x.as_ptr() as c_char) - .collect::>() - .as_ptr() as *const *mut c_char; - let opts = CString::new(optstring).unwrap().into_raw(); - let len = self.len() as c_int; + .collect(); - unsafe { - let a = match getopt(len, argv, opts) { + let argv: Vec<_> = c_strings.iter().map(|x| x.as_ptr()).collect(); + let argv_ptr = argv.as_ptr() as *const *mut c_char; + let optstring_c = CString::new(optstring).unwrap(); + let opts = optstring_c.into_raw(); + let len = self.len() as c_int; + + unsafe { + let a = match getopt(len, argv_ptr, opts) { /* From getopt(3p): * * The getopt() function shall return the next option character @@ -65,11 +67,11 @@ impl GetOpt for Vec { * * Otherwise, getopt() shall return -1 when all command line * options are parsed. */ - 58 => { // ASCII value for ':' + 58 => { /* ASCII value for ':' */ return Some(Err(OptError::MissingArg)); }, - 63 => { // ASCII value for '?' - return Some(Err(OptError::UnknownOpt)); + 63 => { /* ASCII value for '?' */ + return Some(Err(OptError::UnknownOpt)) }, /* From getopt(3p): * @@ -84,18 +86,17 @@ impl GetOpt for Vec { * argv[optind] points to the string "--" * * getopt() shall return -1 after incrementing optind. */ - -1 => return None, - a => a.to_string(), - }; + -1 => return None, + _ => CStr::from_ptr(optarg).to_string_lossy().into_owned(), + }; - Some(Ok(Opt { arg: Some(a), ind: optind, opt: optopt })) - } - } + Some(Ok(Opt { arg: Some(a), ind: optind, opt: optopt })) + } + } } - /* binding to getopt(3p) */ extern "C" { - static mut _optarg: *mut c_char; + static mut optarg: *mut c_char; static mut _opterr: c_int; static mut optind: c_int; static mut optopt: c_int; From ad92fe27d4eb2a6731182844918713ee93acc292 Mon Sep 17 00:00:00 2001 From: emma Date: Thu, 11 Apr 2024 23:37:04 -0600 Subject: [PATCH 030/343] fop(1): switch to getopt.rs(3) --- src/fop.rs | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/fop.rs b/src/fop.rs index b829602..a56a0a6 100644 --- a/src/fop.rs +++ b/src/fop.rs @@ -26,33 +26,43 @@ extern crate getopt; extern crate strerror; extern crate sysexits; -use getopt::{ Opt, Parser }; +use getopt::GetOpt; use strerror::StrError; use sysexits::{ EX_DATAERR, EX_IOERR, EX_UNAVAILABLE, EX_USAGE }; fn main() { let argv = args().collect::>(); let mut d = '␞'; - let mut arg_parser = Parser::new(&argv, "d:"); + let usage = format!( + "Usage: {} [-d delimiter] index command [args...]", + argv[0], + ); + let mut index_arg = 0; - while let Some(opt) = arg_parser.next() { + while let Some(opt) = argv.getopt("d:") { match opt { - Ok(Opt('d', Some(arg))) => { + Ok(o) => { + /* unwrap because Err(OptError::MissingArg) will be returned if + * o.arg is None */ + let arg = o.arg.unwrap(); let arg_char = arg.chars().collect::>(); if arg_char.len() > 1 { eprintln!("{}: {}: Not a character.", argv[0], arg); exit(EX_USAGE); } else { d = arg_char[0]; } + index_arg = o.ind as usize; }, - _ => {}, + Err(_) => { + eprintln!("{}", usage); + exit(EX_USAGE); + } }; } - let index_arg = arg_parser.index(); - let command_arg = arg_parser.index() + 1; + let command_arg = index_arg as usize + 1; argv.get(command_arg).unwrap_or_else(|| { - eprintln!("Usage: {} [-d delimiter] index command [args...]", argv[0]); + eprintln!("{}", usage); exit(EX_USAGE); }); From 95927ba8c5125893dbc5a92d2022ed710df7211e Mon Sep 17 00:00:00 2001 From: emma Date: Thu, 11 Apr 2024 23:51:52 -0600 Subject: [PATCH 031/343] getopt.rs(3): formatting --- src/getopt.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/getopt.rs b/src/getopt.rs index 81c146d..70ee801 100644 --- a/src/getopt.rs +++ b/src/getopt.rs @@ -29,7 +29,7 @@ pub enum OptError { UnknownOpt, } -// Function signature +/* function signature */ pub trait GetOpt { fn getopt(&self, optstring: &str) -> Option>; } @@ -43,10 +43,11 @@ impl GetOpt for Vec { .map(Result::unwrap) .collect(); + /* these operations must be separated out into separate operations so + * the CStrings can live long enough */ let argv: Vec<_> = c_strings.iter().map(|x| x.as_ptr()).collect(); let argv_ptr = argv.as_ptr() as *const *mut c_char; - let optstring_c = CString::new(optstring).unwrap(); - let opts = optstring_c.into_raw(); + let opts = CString::new(optstring).unwrap().into_raw(); let len = self.len() as c_int; unsafe { @@ -67,10 +68,10 @@ impl GetOpt for Vec { * * Otherwise, getopt() shall return -1 when all command line * options are parsed. */ - 58 => { /* ASCII value for ':' */ + 58 => { /* numerical ASCII value for ':' */ return Some(Err(OptError::MissingArg)); }, - 63 => { /* ASCII value for '?' */ + 63 => { /* numerical ASCII value for '?' */ return Some(Err(OptError::UnknownOpt)) }, /* From getopt(3p): From 8c255e61fc4d35ed250b36f4ecf2a8e17edef5d7 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 12 Apr 2024 00:12:37 -0600 Subject: [PATCH 032/343] COPYING.GPL: initial commit --- COPYING.GPL | 674 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 674 insertions(+) create mode 100644 COPYING.GPL diff --git a/COPYING.GPL b/COPYING.GPL new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/COPYING.GPL @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. From d1b77d652b18980f45e6a5a19d9a00e5b3b85f2b Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 13 Apr 2024 17:11:04 -0600 Subject: [PATCH 033/343] getopt.rs(3): returns last parsed option --- src/getopt.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/getopt.rs b/src/getopt.rs index 70ee801..c4f88ab 100644 --- a/src/getopt.rs +++ b/src/getopt.rs @@ -21,12 +21,13 @@ use std::ffi::{ c_int, c_char, CString, CStr }; pub struct Opt { pub arg: Option, pub ind: i32, - pub opt: i32, + /* opt is set to either the current option or the one that cause an error */ + pub opt: String, } pub enum OptError { - MissingArg, - UnknownOpt, + MissingArg(String), + UnknownOpt(String), } /* function signature */ @@ -51,7 +52,7 @@ impl GetOpt for Vec { let len = self.len() as c_int; unsafe { - let a = match getopt(len, argv_ptr, opts) { + match getopt(len, argv_ptr, opts) { /* From getopt(3p): * * The getopt() function shall return the next option character @@ -69,10 +70,10 @@ impl GetOpt for Vec { * Otherwise, getopt() shall return -1 when all command line * options are parsed. */ 58 => { /* numerical ASCII value for ':' */ - return Some(Err(OptError::MissingArg)); + Some(Err(OptError::MissingArg(optopt.to_string()))) }, 63 => { /* numerical ASCII value for '?' */ - return Some(Err(OptError::UnknownOpt)) + Some(Err(OptError::UnknownOpt(optopt.to_string()))) }, /* From getopt(3p): * @@ -88,10 +89,18 @@ impl GetOpt for Vec { * * getopt() shall return -1 after incrementing optind. */ -1 => return None, - _ => CStr::from_ptr(optarg).to_string_lossy().into_owned(), - }; + opt => { + let arg = CStr::from_ptr(optarg) + .to_string_lossy() + .into_owned(); - Some(Ok(Opt { arg: Some(a), ind: optind, opt: optopt })) + Some(Ok(Opt { + arg: Some(arg), + ind: optind, + opt: opt.to_string(), + })) + }, + } } } } From 78eacd660a3af310bae8c23b1693e20e56d49896 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 13 Apr 2024 23:42:11 -0600 Subject: [PATCH 034/343] getopt.rs(3): better Opt return --- src/getopt.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/getopt.rs b/src/getopt.rs index c4f88ab..b146400 100644 --- a/src/getopt.rs +++ b/src/getopt.rs @@ -21,7 +21,6 @@ use std::ffi::{ c_int, c_char, CString, CStr }; pub struct Opt { pub arg: Option, pub ind: i32, - /* opt is set to either the current option or the one that cause an error */ pub opt: String, } @@ -51,8 +50,8 @@ impl GetOpt for Vec { let opts = CString::new(optstring).unwrap().into_raw(); let len = self.len() as c_int; - unsafe { - match getopt(len, argv_ptr, opts) { + unsafe { // TODO: enable optind modification + match getopt(len, argv_ptr, opts) { /* From getopt(3p): * * The getopt() function shall return the next option character @@ -95,9 +94,9 @@ impl GetOpt for Vec { .into_owned(); Some(Ok(Opt { - arg: Some(arg), - ind: optind, - opt: opt.to_string(), + arg: Some(arg), /* opt argument */ + ind: optind, /* opt index */ + opt: opt.to_string(), /* option itself */ })) }, } From df16707b0e2c74217d7ea4aaaab0f45b6f0cff97 Mon Sep 17 00:00:00 2001 From: emma Date: Thu, 18 Apr 2024 08:36:01 -0600 Subject: [PATCH 035/343] intcmp.1: -e permits adjacent integers to be equal to each other --- docs/intcmp.1 | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/docs/intcmp.1 b/docs/intcmp.1 index 6087d0e..b15f4c1 100644 --- a/docs/intcmp.1 +++ b/docs/intcmp.1 @@ -25,11 +25,7 @@ Compare integers to each other. .B -e .RS -Permits given integers to be equal to each other. If combined with -.B -g -or -.B -l -, only adjacent integers in the argument sequence can be equal. +Permits given integers to be equal to each other. .RE .B -g From 3cdade71e2019d754d85b53a680eef27b2fa2939 Mon Sep 17 00:00:00 2001 From: emma Date: Thu, 18 Apr 2024 08:38:48 -0600 Subject: [PATCH 036/343] dj.1: -S whether or not the input is a stream is irrelevant --- docs/dj.1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 0e882dd..e70c666 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -70,8 +70,7 @@ DIAGNOSTICS section below. .B -S .RS Skips a number of bytes through the output before starting to write from -the input. If the input is a stream the bytes are read and discarded. If the -output is a stream, null characters are printed. +the input. If the output is a stream, null characters are printed. .RE .B -a From ed284b9949eb9cc5a4fc2796e315d1c430fcce29 Mon Sep 17 00:00:00 2001 From: emma Date: Thu, 18 Apr 2024 08:40:29 -0600 Subject: [PATCH 037/343] dj.1: -a: More specific wording --- docs/dj.1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index e70c666..41e3112 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -75,8 +75,8 @@ the input. If the output is a stream, null characters are printed. .B -a .RS -Takes one argument of one byte in length and pads the input buffer with it in -the event of an incomplete read from the input file. +Accepts a single literal byte with which input buffer is padded in the event +of an incomplete read from the input file. .RE .B -b From b41af1b578a912df0bd4484be2f2a7604e8e9312 Mon Sep 17 00:00:00 2001 From: emma Date: Thu, 18 Apr 2024 08:41:55 -0600 Subject: [PATCH 038/343] dj.1: -c: grammar --- docs/dj.1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 41e3112..9bc2d82 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -87,8 +87,8 @@ default being 1024 bytes or one kibibyte (KiB). .B -c .RS -Specifies an amount of reads to make, and if 0 (the default) dj will -continue reading until a partial or empty read. +Specifies a number of reads to make. If set to zero (the default), reading will +continue until a partial or empty read is encountered. .RE .B -d From 187d9486b762006cbb1efb12a7d8a49ae54ed14a Mon Sep 17 00:00:00 2001 From: emma Date: Thu, 18 Apr 2024 08:44:44 -0600 Subject: [PATCH 039/343] dj.1: debug output clarification --- docs/dj.1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 9bc2d82..175a32c 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -149,9 +149,10 @@ the following format: .R {ASCII record separator} {bytes written} {ASCII file separator} .RE -If the +This format for diagnostic output is designed to be machine-parseable for +convenience. For a more human-readable format, the .B -H -option is specified, the following format is used instead: +option may be specified. In this event, the following format is used instead: .RS .R {records read} '+' {partial records read} '>' {records written} From 057f5571d6708a964e2b6cc60e10ff76d132cf92 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 24 Apr 2024 14:58:35 -0600 Subject: [PATCH 040/343] moved tests into test directory --- Makefile | 5 +- Testfile | 78 ------------------------------ tests/bonsai/dj.sh | 25 ++++++++++ tests/bonsai/false.sh | 11 +++++ tests/bonsai/intcmp.sh | 23 +++++++++ tests/bonsai/strcmp.sh | 14 ++++++ tests/bonsai/true.sh | 11 +++++ tests/posix/false.sh | 13 +++++ tests/posix/true.sh | 13 +++++ tests/{posix-compat.sh => test.sh} | 23 ++++++++- 10 files changed, 134 insertions(+), 82 deletions(-) delete mode 100644 Testfile create mode 100755 tests/bonsai/dj.sh create mode 100755 tests/bonsai/false.sh create mode 100755 tests/bonsai/intcmp.sh create mode 100755 tests/bonsai/strcmp.sh create mode 100755 tests/bonsai/true.sh create mode 100755 tests/posix/false.sh create mode 100755 tests/posix/true.sh rename tests/{posix-compat.sh => test.sh} (55%) diff --git a/Makefile b/Makefile index 494f0f7..03f68fd 100644 --- a/Makefile +++ b/Makefile @@ -40,10 +40,9 @@ install: dist cp -r dist/* $(PREFIX)/ .PHONY: test -test: build - tests/posix-compat.sh +test: all + tests/test.sh $(RUSTC) --test src/getopt-rs/lib.rs -o build/test/getopt - $(MAKE) -f Testfile build/o/libsysexits.rlib: build # bandage solution until bindgen(1) gets stdin support diff --git a/Testfile b/Testfile deleted file mode 100644 index e2cc294..0000000 --- a/Testfile +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env make -# Copyright (c) 2024 DTB -# SPDX-License-Identifier: FSFAP -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice and this -# notice are preserved. This file is offered as-is, without any warranty. - -BIN = build/bin -MAKE = make -B - -DEFENDANTS = dj false intcmp strcmp true -.PHONY: all $(DEFENDANTS) -all: $(DEFENDANTS) - -$(BIN)/dj: - $(MAKE) dj - -$(BIN)/false: - $(MAKE) false - -$(BIN)/intcmp: - $(MAKE) intcmp - -$(BIN)/strcmp: - $(MAKE) strcmp - -$(BIN)/true: - $(MAKE) true - -dj: $(BIN)/dj $(BIN)/strcmp - sh -c "! $(BIN)/dj -h" - # This test is theoretically Linux-dependent; write(2) should return -1 on - # error. - # Right now dj(1) interprets the return value of write(2) as the amount of - # bytes written. This can decrement the stored quantity of bytes written, - # which is an int, so doesn't underflow but goes negative. dj(1) tries to - # again to write(2) if an error occurs in which no bytes are written, so in - # total two write(2)s are attempted and so the written byte quantity is -2. - # This is a bug and will change, but for now is at least documented. - sh -ec "\ - $(BIN)/dj -Hi /dev/zero -o /dev/full \ - | xargs -I out $(BIN)/strcmp '1+0 > 0+0; 1024 > -2' out" - # Read nothing from /dev/null, write nothing to /dev/null. - sh -ec "\ - $(BIN)/dj -Hi /dev/null -o /dev/null \ - | xargs -I out $(BIN)/strcmp '0+0 > 0+0; 0 > 0' out" - -false: $(BIN)/false - sh -c "! $(BIN)/false" - sh -c "! $(BIN)/false -h" - -intcmp: $(BIN)/intcmp - $(BIN)/intcmp -e 3 3 3 - $(BIN)/intcmp -g 3 2 1 - $(BIN)/intcmp -l 1 2 3 - $(BIN)/intcmp -ge 3 3 1 - $(BIN)/intcmp -le 1 3 3 - $(BIN)/intcmp -gl 1 2 3 - $(BIN)/intcmp -egl 3 1 1 2 - sh -c "! $(BIN)/intcmp -e 1 2 3" - sh -c "! $(BIN)/intcmp -g 1 3 3" - sh -c "! $(BIN)/intcmp -l 3 3 1" - sh -c "! $(BIN)/intcmp -ge 1 2 3" - sh -c "! $(BIN)/intcmp -le 3 2 1" - sh -c "! $(BIN)/intcmp -gl 3 3 3" - sh -c "! $(BIN)/intcmp -egl foo" - -strcmp: $(BIN)/strcmp - $(BIN)/strcmp equals equals - sh -c "! $(BIN)/strcmp inequals equals" - $(BIN)/strcmp - - - sh -c "! $(BIN)/strcmp -h" - sh -c "! $(BIN)/strcmp nocmp" - -true: - $(BIN)/true - $(BIN)/true -h diff --git a/tests/bonsai/dj.sh b/tests/bonsai/dj.sh new file mode 100755 index 0000000..be5ca49 --- /dev/null +++ b/tests/bonsai/dj.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# Copyright (c) 2024 DTB +# Copyright (c) 2024 Emma Tebibyte +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +! dj -h + +# This test is theoretically Linux-dependent; write(2) should return -1 on +# error. +# Right now dj(1) interprets the return value of write(2) as the amount of +# bytes written. This can decrement the stored quantity of bytes written, +# which is an int, so doesn't underflow but goes negative. dj(1) tries to +# again to write(2) if an error occurs in which no bytes are written, so in +# total two write(2)s are attempted and so the written byte quantity is -2. +# This is a bug and will change, but for now is at least documented. +dj -Hi /dev/zero -o /dev/full \ + | xargs -I out "$BIN/strcmp" '1+0 > 0+0; 1024 > -2' out + +# Read nothing from /dev/null, write nothing to /dev/null. +dj -Hi /dev/null -o /dev/null \ + | xargs -I out "$BIN/strcmp" '0+0 > 0+0; 0 > 0' out diff --git a/tests/bonsai/false.sh b/tests/bonsai/false.sh new file mode 100755 index 0000000..670feba --- /dev/null +++ b/tests/bonsai/false.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# Copyright (c) 2024 DTB +# Copyright (c) 2024 Emma Tebibyte +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +! false +! false -h diff --git a/tests/bonsai/intcmp.sh b/tests/bonsai/intcmp.sh new file mode 100755 index 0000000..7acb28a --- /dev/null +++ b/tests/bonsai/intcmp.sh @@ -0,0 +1,23 @@ +#!/bin/sh +# Copyright (c) 2024 DTB +# Copyright (c) 2024 Emma Tebibyte +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +intcmp -e 3 3 3 +intcmp -g 3 2 1 +intcmp -l 1 2 3 +intcmp -ge 3 3 1 +intcmp -le 1 3 3 +intcmp -gl 1 2 3 +intcmp -egl 3 1 1 2 +! intcmp -e 1 2 3 +! intcmp -g 1 3 3 +! intcmp -l 3 3 1 +! intcmp -ge 1 2 3 +! intcmp -le 3 2 1 +! intcmp -gl 3 3 3 +! intcmp -egl foo diff --git a/tests/bonsai/strcmp.sh b/tests/bonsai/strcmp.sh new file mode 100755 index 0000000..82f2781 --- /dev/null +++ b/tests/bonsai/strcmp.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# Copyright (c) 2024 DTB +# Copyright (c) 2024 Emma Tebibyte +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +strcmp equals equals +! strcmp inequals equals +strcmp - - +strcmp -h +! strcmp nocmp diff --git a/tests/bonsai/true.sh b/tests/bonsai/true.sh new file mode 100755 index 0000000..e8ed913 --- /dev/null +++ b/tests/bonsai/true.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# Copyright (c) 2024 DTB +# Copyright (c) 2024 Emma Tebibyte +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +true +true -h diff --git a/tests/posix/false.sh b/tests/posix/false.sh new file mode 100755 index 0000000..100b6c1 --- /dev/null +++ b/tests/posix/false.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# Copyright (c) 2024 DTB +# Copyright (c) 2024 Emma Tebibyte +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +alias false="$BIN/false" + +! false +! false -h diff --git a/tests/posix/true.sh b/tests/posix/true.sh new file mode 100755 index 0000000..a7872fb --- /dev/null +++ b/tests/posix/true.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# Copyright (c) 2024 DTB +# Copyright (c) 2024 Emma Tebibyte +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +alias true="$BIN/true" + +true +true -h diff --git a/tests/posix-compat.sh b/tests/test.sh similarity index 55% rename from tests/posix-compat.sh rename to tests/test.sh index 1e98d7b..faaae5e 100755 --- a/tests/posix-compat.sh +++ b/tests/test.sh @@ -9,13 +9,34 @@ set -e +export BIN=build/bin + if ! ls Makefile >/dev/null 2>&1 then printf '%s: Run this script in the root of the project.\n' "$0" 1>&2 exit 1 fi -printf "Starting POSIX compatibility testing.\n" +printf "Starting Bonsai testing.\n\n" + +for script in tests/bonsai/*.sh; do + export UTIL="$(printf '%s\n' "$script" \ + | sed -e 's/\.sh//g' -e 's;tests\/bonsai\/;;g')" + + alias "$UTIL"="$BIN/$UTIL" + + printf '%s: %s: Testing utility.\n' "$0" "$UTIL" + "$script" + printf '\n' +done + +if ! ls Makefile >/dev/null 2>&1 +then + printf '%s: Run this script in the root of the project.\n' "$0" 1>&2 + exit 1 +fi + +printf "Starting POSIX compatibility testing.\n\n" for utility in tests/posix/*; do printf '%s: %s: Testing utility.\n' "$0" "$utility" From aefa87d9e5d3d4daf4544dddb6dfc16796c953d5 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 24 Apr 2024 15:22:07 -0600 Subject: [PATCH 041/343] tests: fixed aliasing and created mm.sh --- tests/bonsai/aliases | 3 +++ tests/bonsai/dj.sh | 2 ++ tests/bonsai/false.sh | 2 ++ tests/bonsai/intcmp.sh | 2 ++ tests/bonsai/mm.sh | 20 ++++++++++++++++++++ tests/bonsai/strcmp.sh | 2 ++ tests/bonsai/true.sh | 2 ++ tests/test.sh | 2 -- 8 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 tests/bonsai/aliases create mode 100755 tests/bonsai/mm.sh diff --git a/tests/bonsai/aliases b/tests/bonsai/aliases new file mode 100644 index 0000000..f7dfb28 --- /dev/null +++ b/tests/bonsai/aliases @@ -0,0 +1,3 @@ +#!/bin/sh + +alias "$UTIL=$BIN/$UTIL" diff --git a/tests/bonsai/dj.sh b/tests/bonsai/dj.sh index be5ca49..eaefaa9 100755 --- a/tests/bonsai/dj.sh +++ b/tests/bonsai/dj.sh @@ -7,6 +7,8 @@ # permitted in any medium without royalty provided the copyright notice and this # notice are preserved. This file is offered as-is, without any warranty. +. tests/bonsai/aliases + ! dj -h # This test is theoretically Linux-dependent; write(2) should return -1 on diff --git a/tests/bonsai/false.sh b/tests/bonsai/false.sh index 670feba..6098b4f 100755 --- a/tests/bonsai/false.sh +++ b/tests/bonsai/false.sh @@ -7,5 +7,7 @@ # permitted in any medium without royalty provided the copyright notice and this # notice are preserved. This file is offered as-is, without any warranty. +. tests/bonsai/aliases + ! false ! false -h diff --git a/tests/bonsai/intcmp.sh b/tests/bonsai/intcmp.sh index 7acb28a..c566877 100755 --- a/tests/bonsai/intcmp.sh +++ b/tests/bonsai/intcmp.sh @@ -7,6 +7,8 @@ # permitted in any medium without royalty provided the copyright notice and this # notice are preserved. This file is offered as-is, without any warranty. +. tests/bonsai/aliases + intcmp -e 3 3 3 intcmp -g 3 2 1 intcmp -l 1 2 3 diff --git a/tests/bonsai/mm.sh b/tests/bonsai/mm.sh new file mode 100755 index 0000000..3ef1f99 --- /dev/null +++ b/tests/bonsai/mm.sh @@ -0,0 +1,20 @@ +#!/bin/sh +# Copyright (c) 2024 DTB +# Copyright (c) 2024 Emma Tebibyte +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +. tests/bonsai/aliases + +exec 3>&1 + +! mm -h + +# mm(1) will error if positional arguments are given without -i or -o +! mm argument + +# check if stderr is empty upon specifying -e +! "$BIN/strcmp" "$(printf 'test\n' | mm -i - -e 2>&1 1>&3)" '' diff --git a/tests/bonsai/strcmp.sh b/tests/bonsai/strcmp.sh index 82f2781..9c7ceb0 100755 --- a/tests/bonsai/strcmp.sh +++ b/tests/bonsai/strcmp.sh @@ -7,6 +7,8 @@ # permitted in any medium without royalty provided the copyright notice and this # notice are preserved. This file is offered as-is, without any warranty. +. tests/bonsai/aliases + strcmp equals equals ! strcmp inequals equals strcmp - - diff --git a/tests/bonsai/true.sh b/tests/bonsai/true.sh index e8ed913..39d3d53 100755 --- a/tests/bonsai/true.sh +++ b/tests/bonsai/true.sh @@ -7,5 +7,7 @@ # permitted in any medium without royalty provided the copyright notice and this # notice are preserved. This file is offered as-is, without any warranty. +. tests/bonsai/aliases + true true -h diff --git a/tests/test.sh b/tests/test.sh index faaae5e..b439464 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -23,8 +23,6 @@ for script in tests/bonsai/*.sh; do export UTIL="$(printf '%s\n' "$script" \ | sed -e 's/\.sh//g' -e 's;tests\/bonsai\/;;g')" - alias "$UTIL"="$BIN/$UTIL" - printf '%s: %s: Testing utility.\n' "$0" "$UTIL" "$script" printf '\n' From 28f2d44e2fdd1def42dfaed25660452340451b5c Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 24 Apr 2024 15:24:35 -0600 Subject: [PATCH 042/343] CONTRIBUTING: updated to include docs and tests requirement --- CONTRIBUTING | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING b/CONTRIBUTING index d7fdc8e..b7ad7a8 100644 --- a/CONTRIBUTING +++ b/CONTRIBUTING @@ -97,9 +97,10 @@ their editor or terminal. For usage text and help messages, do not implement a -h option. Instead, print usage information when any erroneous option is specified. Follow the NetBSD -style guide for the usage text’s output format [1]. +style guide for the usage text’s output format [0]. -[1] +If committing a new utility, please include tests and documentation (see +tests/ and docs/) for the new tool. If committing a new source file, format the commit message following these guidelines: @@ -128,6 +129,7 @@ $ git commit -m 'tool(1): fix #42 & add feature x' Commit messages should be written in the present tense. +[0] -- This work © 2023–2024 by Emma Tebibyte is licensed under CC BY-SA 4.0. To view a copy of this license, visit From 3398fc372cfaa930dc22d0ac179733c47ae289f4 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 24 Apr 2024 15:33:17 -0600 Subject: [PATCH 043/343] tests: bonsai: mm.sh: fixed copyright --- tests/bonsai/mm.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/bonsai/mm.sh b/tests/bonsai/mm.sh index 3ef1f99..686ad1a 100755 --- a/tests/bonsai/mm.sh +++ b/tests/bonsai/mm.sh @@ -1,5 +1,4 @@ #!/bin/sh -# Copyright (c) 2024 DTB # Copyright (c) 2024 Emma Tebibyte # SPDX-License-Identifier: FSFAP # From c6f30c419581b06099950b952b31d3480b146e52 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 24 Apr 2024 19:25:55 -0600 Subject: [PATCH 044/343] tests: bonsai: fop.sh: added test --- tests/bonsai/fop.sh | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100755 tests/bonsai/fop.sh diff --git a/tests/bonsai/fop.sh b/tests/bonsai/fop.sh new file mode 100755 index 0000000..2a4e4a9 --- /dev/null +++ b/tests/bonsai/fop.sh @@ -0,0 +1,21 @@ +#!/bin/sh +# Copyright (c) 2024 Emma Tebibyte +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +. tests/bonsai/aliases + +! fop -h + +"$BIN/strcmp" "$(printf 'test0␞test1␞test2\n' | fop 1 sed 's/1/4/g')" \ + 'test0␞test4␞test2' + +"$BIN/strcmp" "$(printf 'test0 test1 test2\n' | fop -d' ' 2 sed 's/2/4/g')" \ + 'test0 test1 test4' + +! printf 'test\n' | fop 1 cat +! printf 'test\n' | fop 'test' cat +! printf 'test\n' | fop -d'test' cat From 1aa2b596d0003f00b0ea7a7b7c31a2f473696429 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 24 Apr 2024 19:28:33 -0600 Subject: [PATCH 045/343] tests: aliases: added set -x --- tests/bonsai/aliases | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/bonsai/aliases b/tests/bonsai/aliases index f7dfb28..a3d07ca 100644 --- a/tests/bonsai/aliases +++ b/tests/bonsai/aliases @@ -1,3 +1,5 @@ #!/bin/sh +set -x + alias "$UTIL=$BIN/$UTIL" From f6aac60aee89eafcb088337d7f820766a657d5c1 Mon Sep 17 00:00:00 2001 From: emma Date: Thu, 25 Apr 2024 12:40:20 -0600 Subject: [PATCH 046/343] Makefile: fixed manpage install location --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 68efd20..e0068dc 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,8 @@ DESTDIR ?= dist PREFIX ?= /usr/local +MANDIR != [ $(PREFIX) = / ] && printf '/usr/share/man\n' \ + || printf '/share/man\n' SYSEXITS != printf '\043include \n' | cpp -M - | sed 's/ /\n/g' \ | sed -n 's/sysexits\.h//p' || printf 'include\n' @@ -42,7 +44,7 @@ clean: dist: all mkdir -p $(DESTDIR)/$(PREFIX)/bin $(DESTDIR)/$(PREFIX)/share/man/man1 cp build/bin/* $(DESTDIR)/$(PREFIX)/bin - cp docs/*.1 $(DESTDIR)/$(PREFIX)/share/man/man1 + cp docs/*.1 $(DESTDIR)/$(PREFIX)/$(MANDIR)/man1 .PHONY: install install: dist From d8b54fdbf5b1e19810c28a341c59d0ec4fec01ec Mon Sep 17 00:00:00 2001 From: emma Date: Thu, 25 Apr 2024 12:43:31 -0600 Subject: [PATCH 047/343] Makefile: fixes erroneous whitespace --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index e0068dc..1952a25 100644 --- a/Makefile +++ b/Makefile @@ -104,7 +104,6 @@ mm: build/bin/mm build/bin/mm: src/mm.c build $(CC) $(CFLAGS) -o $@ src/mm.c - .PHONY: npc npc: build/bin/npc build/bin/npc: src/npc.c build From 0113cf793de13298f6ec7986b43cb6a639289e18 Mon Sep 17 00:00:00 2001 From: emma Date: Thu, 25 Apr 2024 17:20:55 -0600 Subject: [PATCH 048/343] tests: bonsai: hru.sh: adds test --- tests/bonsai/hru.sh | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100755 tests/bonsai/hru.sh diff --git a/tests/bonsai/hru.sh b/tests/bonsai/hru.sh new file mode 100755 index 0000000..fd59e69 --- /dev/null +++ b/tests/bonsai/hru.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# Copyright (c) 2024 Emma Tebibyte +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +. tests/bonsai/aliases + +alias strcmp="$BIN/strcmp" +alias rpn="$BIN/rpn" + +strcmp "$(printf '1234\n' | hru)" '1.2 kB' +strcmp "$(printf '0\n' | hru)" '0 B' + +# doesn’t currently work but would be useful for testing for regressions +#n=1 +#while "$BIN/true"; do +# n="$(rpn "$n" 10 ×)" +# +# printf '%s\n' "$n" | hru || break +#done +#printf 'integer limit: ~%s\n' "$(rpn "$n" 10 ÷)" + +! printf '%s\n' '-1' | hru From 4ad9e0da92cc43f0663dbb36230c06dec8cb8f52 Mon Sep 17 00:00:00 2001 From: emma Date: Thu, 25 Apr 2024 18:57:05 -0600 Subject: [PATCH 049/343] tests: bonsai: rename aliases sourced script to test_env --- tests/bonsai/dj.sh | 2 +- tests/bonsai/false.sh | 2 +- tests/bonsai/fop.sh | 2 +- tests/bonsai/hru.sh | 2 +- tests/bonsai/intcmp.sh | 2 +- tests/bonsai/mm.sh | 2 +- tests/bonsai/strcmp.sh | 2 +- tests/bonsai/{aliases => test_env} | 0 tests/bonsai/true.sh | 2 +- 9 files changed, 8 insertions(+), 8 deletions(-) rename tests/bonsai/{aliases => test_env} (100%) diff --git a/tests/bonsai/dj.sh b/tests/bonsai/dj.sh index eaefaa9..8016ec3 100755 --- a/tests/bonsai/dj.sh +++ b/tests/bonsai/dj.sh @@ -7,7 +7,7 @@ # permitted in any medium without royalty provided the copyright notice and this # notice are preserved. This file is offered as-is, without any warranty. -. tests/bonsai/aliases +. tests/bonsai/test_env ! dj -h diff --git a/tests/bonsai/false.sh b/tests/bonsai/false.sh index 6098b4f..3ad0e94 100755 --- a/tests/bonsai/false.sh +++ b/tests/bonsai/false.sh @@ -7,7 +7,7 @@ # permitted in any medium without royalty provided the copyright notice and this # notice are preserved. This file is offered as-is, without any warranty. -. tests/bonsai/aliases +. tests/bonsai/test_env ! false ! false -h diff --git a/tests/bonsai/fop.sh b/tests/bonsai/fop.sh index 2a4e4a9..2cb2533 100755 --- a/tests/bonsai/fop.sh +++ b/tests/bonsai/fop.sh @@ -6,7 +6,7 @@ # permitted in any medium without royalty provided the copyright notice and this # notice are preserved. This file is offered as-is, without any warranty. -. tests/bonsai/aliases +. tests/bonsai/test_env ! fop -h diff --git a/tests/bonsai/hru.sh b/tests/bonsai/hru.sh index fd59e69..51bf7c1 100755 --- a/tests/bonsai/hru.sh +++ b/tests/bonsai/hru.sh @@ -6,7 +6,7 @@ # permitted in any medium without royalty provided the copyright notice and this # notice are preserved. This file is offered as-is, without any warranty. -. tests/bonsai/aliases +. tests/bonsai/test_env alias strcmp="$BIN/strcmp" alias rpn="$BIN/rpn" diff --git a/tests/bonsai/intcmp.sh b/tests/bonsai/intcmp.sh index c566877..e3cdcb7 100755 --- a/tests/bonsai/intcmp.sh +++ b/tests/bonsai/intcmp.sh @@ -7,7 +7,7 @@ # permitted in any medium without royalty provided the copyright notice and this # notice are preserved. This file is offered as-is, without any warranty. -. tests/bonsai/aliases +. tests/bonsai/test_env intcmp -e 3 3 3 intcmp -g 3 2 1 diff --git a/tests/bonsai/mm.sh b/tests/bonsai/mm.sh index 686ad1a..43f3a1c 100755 --- a/tests/bonsai/mm.sh +++ b/tests/bonsai/mm.sh @@ -6,7 +6,7 @@ # permitted in any medium without royalty provided the copyright notice and this # notice are preserved. This file is offered as-is, without any warranty. -. tests/bonsai/aliases +. tests/bonsai/test_env exec 3>&1 diff --git a/tests/bonsai/strcmp.sh b/tests/bonsai/strcmp.sh index 9c7ceb0..018cee2 100755 --- a/tests/bonsai/strcmp.sh +++ b/tests/bonsai/strcmp.sh @@ -7,7 +7,7 @@ # permitted in any medium without royalty provided the copyright notice and this # notice are preserved. This file is offered as-is, without any warranty. -. tests/bonsai/aliases +. tests/bonsai/test_env strcmp equals equals ! strcmp inequals equals diff --git a/tests/bonsai/aliases b/tests/bonsai/test_env similarity index 100% rename from tests/bonsai/aliases rename to tests/bonsai/test_env diff --git a/tests/bonsai/true.sh b/tests/bonsai/true.sh index 39d3d53..413d758 100755 --- a/tests/bonsai/true.sh +++ b/tests/bonsai/true.sh @@ -7,7 +7,7 @@ # permitted in any medium without royalty provided the copyright notice and this # notice are preserved. This file is offered as-is, without any warranty. -. tests/bonsai/aliases +. tests/bonsai/test_env true true -h From e278307dafe4b2cabf37b4b325037acbd8e46afd Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 26 Apr 2024 20:55:16 -0600 Subject: [PATCH 050/343] tests: bonsai: removed redundant code --- tests/test.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/test.sh b/tests/test.sh index b439464..de03aa6 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -28,12 +28,6 @@ for script in tests/bonsai/*.sh; do printf '\n' done -if ! ls Makefile >/dev/null 2>&1 -then - printf '%s: Run this script in the root of the project.\n' "$0" 1>&2 - exit 1 -fi - printf "Starting POSIX compatibility testing.\n\n" for utility in tests/posix/*; do From f022121436164d6ac4ea7f9f2c75dc39c63914cd Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 27 Apr 2024 15:16:52 -0600 Subject: [PATCH 051/343] tests: posix: cat(1p): added POSIX-compliant cat --- tests/posix/bin/cat | 22 ++++++++++++++++++++++ tests/posix/{true.sh => bin/false} | 5 ++--- tests/posix/{false.sh => bin/true} | 6 ++---- tests/test.sh | 5 +++-- 4 files changed, 29 insertions(+), 9 deletions(-) create mode 100755 tests/posix/bin/cat rename tests/posix/{true.sh => bin/false} (83%) rename tests/posix/{false.sh => bin/true} (83%) diff --git a/tests/posix/bin/cat b/tests/posix/bin/cat new file mode 100755 index 0000000..e123d7c --- /dev/null +++ b/tests/posix/bin/cat @@ -0,0 +1,22 @@ +#!/bin/sh +# Copyright (c) 2024 Emma Tebibyte +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +# Strictly POSIX-compliant cat(1) implementation. See cat(1p) + +for arg in "$@"; do + case "$arg" in + -u) args="$(printf '%s %s\n' "$args" "$arg")" ;; + *) args="$(printf -- '%s -i %s\n' "$args" "$arg")" ;; + esac +done + +# See IEEE Std 1003.1-2017 3.282 +# https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_282 +IFS=' ' + +mm $args diff --git a/tests/posix/true.sh b/tests/posix/bin/false similarity index 83% rename from tests/posix/true.sh rename to tests/posix/bin/false index a7872fb..62a10c9 100755 --- a/tests/posix/true.sh +++ b/tests/posix/bin/false @@ -7,7 +7,6 @@ # permitted in any medium without royalty provided the copyright notice and this # notice are preserved. This file is offered as-is, without any warranty. -alias true="$BIN/true" +# Strictly POSIX-compliant false(1) implementation. See false(1p) -true -true -h +false "$@" diff --git a/tests/posix/false.sh b/tests/posix/bin/true similarity index 83% rename from tests/posix/false.sh rename to tests/posix/bin/true index 100b6c1..aed1b86 100755 --- a/tests/posix/false.sh +++ b/tests/posix/bin/true @@ -7,7 +7,5 @@ # permitted in any medium without royalty provided the copyright notice and this # notice are preserved. This file is offered as-is, without any warranty. -alias false="$BIN/false" - -! false -! false -h +# Strictly POSIX-compliant true(1) implementation. See true(1p) +true "$@" diff --git a/tests/test.sh b/tests/test.sh index de03aa6..7db6d61 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -30,8 +30,9 @@ done printf "Starting POSIX compatibility testing.\n\n" -for utility in tests/posix/*; do - printf '%s: %s: Testing utility.\n' "$0" "$utility" +for test in tests/posix/*.sh; do + export PATH="build/bin:$PATH" + printf '%s: %s: Testing utility.\n' "$0" "$test" "$utility" printf '\n' done From e02884482539cee25d7f2b071f4a1bb2d534f5a6 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 27 Apr 2024 15:18:09 -0600 Subject: [PATCH 052/343] tests: test.sh: utilize $BIN --- tests/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test.sh b/tests/test.sh index 7db6d61..bec71ff 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -31,7 +31,7 @@ done printf "Starting POSIX compatibility testing.\n\n" for test in tests/posix/*.sh; do - export PATH="build/bin:$PATH" + export PATH="$BIN:$PATH" printf '%s: %s: Testing utility.\n' "$0" "$test" "$utility" printf '\n' From 432b19818ed625d6673c24e527a8502ffec5b689 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 28 Apr 2024 20:42:44 -0600 Subject: [PATCH 053/343] made dj options no longer alphabetized --- docs/dj.1 | 61 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 175a32c..429b7fc 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -47,11 +47,27 @@ dj .SH OPTIONS -.B -A +.B -i .RS -If the output is a stream, null bytes are printed. In other words, it does what -.B -a -does but with null bytes instead. +Takes a file path as an argument to open and use as an input. +.RE + +.B -b +.RS +Takes a numeric argument as the size in bytes of the input buffer, with the +default being 1024 bytes or one kibibyte (KiB). +.RE + +.B -s +.RS +Takes a numeric argument as the number of bytes to skip into the input +before starting to read. If the standard input is used, bytes read to this point +are discarded. +.RE + +.B -o +.RS +Takes a file path as an argument to open and use as an output. .RE .B -B @@ -61,12 +77,6 @@ Does the same as but for the output buffer. .RE -.B -H -.RS -Prints diagnostics messages in a human-readable manner as described in the -DIAGNOSTICS section below. -.RE - .B -S .RS Skips a number of bytes through the output before starting to write from @@ -79,18 +89,20 @@ Accepts a single literal byte with which input buffer is padded in the event of an incomplete read from the input file. .RE -.B -b -.RS -Takes a numeric argument as the size in bytes of the input buffer, with the -default being 1024 bytes or one kibibyte (KiB). -.RE - .B -c .RS Specifies a number of reads to make. If set to zero (the default), reading will continue until a partial or empty read is encountered. .RE +.B -A +.RS +If the output is a stream, null bytes are printed. This option is equivalent to +specifying +.B -a +with a null byte instead of a character. +.RE + .B -d .RS Prints invocation information before program execution as described in the @@ -98,9 +110,10 @@ DIAGNOSTICS section below. Each invocation increments the debug level of the program. .RE -.B -i +.B -H .RS -Takes a file path as an argument to open and use as an input. +Prints diagnostics messages in a human-readable manner as described in the +DIAGNOSTICS section below. .RE .B -n @@ -108,18 +121,6 @@ Takes a file path as an argument to open and use as an input. Retries failed reads once more before exiting. .RE -.B -o -.RS -Takes a file path as an argument to open and use as an output. -.RE - -.B -s -.RS -Takes a numeric argument as the number of bytes to skip into the input -before starting to read. If the standard input is used, bytes read to this point -are discarded. -.RE - .B -q .RS Suppresses error messages which print when a read or write is partial or From c53f3fa617d1bf628ac2b1874f043d769fdcc87a Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 24 May 2024 09:53:54 -0600 Subject: [PATCH 054/343] dj.1: remove mention of KiB --- docs/dj.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dj.1 b/docs/dj.1 index 429b7fc..1ebda2e 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -55,7 +55,7 @@ Takes a file path as an argument to open and use as an input. .B -b .RS Takes a numeric argument as the size in bytes of the input buffer, with the -default being 1024 bytes or one kibibyte (KiB). +default being 1024. .RE .B -s From d87f4b20a32f5b2ce49ce697b843eb749ca2d0bb Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 24 May 2024 09:56:44 -0600 Subject: [PATCH 055/343] dj.1: -A: better description --- docs/dj.1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 1ebda2e..1473455 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -97,10 +97,10 @@ continue until a partial or empty read is encountered. .B -A .RS -If the output is a stream, null bytes are printed. This option is equivalent to -specifying +Specifying this option pads the input buffer with null bytes in the event of an +incomplete read. Equivalent to specifying .B -a -with a null byte instead of a character. +with a null byte instead of a character. .RE .B -d From 2137b0bf4342c5d63514f8946d15a395c08e29da Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 24 May 2024 10:03:52 -0600 Subject: [PATCH 056/343] dj.1: -i: better description --- docs/dj.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dj.1 b/docs/dj.1 index 1473455..1fd7a63 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -49,7 +49,7 @@ dj .B -i .RS -Takes a file path as an argument to open and use as an input. +Takes a file path as an argument and opens it for use as an input. .RE .B -b From b4173a23276ead1c1965a656c3bc06c58bd61f2c Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 24 May 2024 10:06:15 -0600 Subject: [PATCH 057/343] dj.1: -o: better description --- docs/dj.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dj.1 b/docs/dj.1 index 1fd7a63..49bf733 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -67,7 +67,7 @@ are discarded. .B -o .RS -Takes a file path as an argument to open and use as an output. +Takes a file path as an argument and opens it for use as an output. .RE .B -B From 0660db3d029ab12b58e77bba25e5be3cbfea7f42 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 24 May 2024 10:13:17 -0600 Subject: [PATCH 058/343] dj.1: -c: better description --- docs/dj.1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 49bf733..e4399c3 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -91,8 +91,8 @@ of an incomplete read from the input file. .B -c .RS -Specifies a number of reads to make. If set to zero (the default), reading will -continue until a partial or empty read is encountered. +Specifies a number of reads to make. The default is zero, in which case the +input is read until a partial or empty read is made. .RE .B -A From 122a10257e472893389fd2678dda3134272d4782 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 24 May 2024 10:13:59 -0600 Subject: [PATCH 059/343] dj.1: fixed option description locations --- docs/dj.1 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index e4399c3..2c2e634 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -89,12 +89,6 @@ Accepts a single literal byte with which input buffer is padded in the event of an incomplete read from the input file. .RE -.B -c -.RS -Specifies a number of reads to make. The default is zero, in which case the -input is read until a partial or empty read is made. -.RE - .B -A .RS Specifying this option pads the input buffer with null bytes in the event of an @@ -103,6 +97,12 @@ incomplete read. Equivalent to specifying with a null byte instead of a character. .RE +.B -c +.RS +Specifies a number of reads to make. The default is zero, in which case the +input is read until a partial or empty read is made. +.RE + .B -d .RS Prints invocation information before program execution as described in the From 922ee71283d0738b7c916f58eea45fb563c66aa5 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 24 May 2024 10:14:53 -0600 Subject: [PATCH 060/343] dj.1: fixes standard input section grammar --- docs/dj.1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 2c2e634..7534b6e 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -129,8 +129,8 @@ empty. Each invocation decrements the debug level of the program. .SH STANDARD INPUT -The standard input shall be used as an input if no inputs are specified one or -more of the input files is “-”. +The standard input shall be used as an input if no inputs are specified or if +one or more of the input files is “-”. .SH DIAGNOSTICS From b7f52902b6bde54876b5fd8efafa433e2cf0df9a Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 24 May 2024 10:21:06 -0600 Subject: [PATCH 061/343] dj.1: grammar & formatting --- docs/dj.1 | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 7534b6e..7af1c00 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -138,9 +138,9 @@ On a partial or empty read, a diagnostic message is printed (unless the .B -q option is specified) and the program exits (unless the .B -n -option is specified. +option is specified). -By default statistics are printed for input and output to the standard error in +By default, statistics are printed for input and output to the standard error in the following format: .RS @@ -163,9 +163,9 @@ option may be specified. In this event, the following format is used instead: If the .B -d -option is specified, debug output will be printed at the beginning of execution. -This debug information contains information regarding how the program was -invoked. The following example is the result of running the program with +option is specified, debug output will be printed at the beginning of +execution. This debug information contains information regarding how the program +was invoked. The following example is the result of running the program with .B -d as the only argument: @@ -183,29 +183,31 @@ sysexits.h(3) status. If .B -n -is specified along with a specified count, actual byte output may be lower than -expected (the product of the count multiplied by the input block size). If the +is specified along with the +.B -c +option and a count, actual byte output may be lower than expected (the product +of the count and the input block size). If the .B -a or .B -A -options are used this could make data written nonsensical. - -Many lowercase options have capitalized variants and vice-versa which can be -confusing. Capitalized options tend to affect output or are more intense -versions of lowercase options. +options are used, this could make data written nonsensical. .SH CAVEATS Existing files are not truncated on ouput and are instead overwritten. +Many lowercase options have capitalized variants and vice-versa which can be +confusing. Capitalized options tend to affect output or are more intense +versions of lowercase options. + .SH RATIONALE This program was based on the dd(1p) utility as specified in POSIX. While character conversion may have been the original intent of dd(1p), it is -irrelevant to its modern use. Because of this, it eschews character conversion -and adds typical option formatting, allowing seeks to be specified in bytes -rather than in blocks, allowing arbitrary bytes as padding, and printing in a -format that’s easy to parse for machines. +irrelevant to its modern use. Because of this, this program eschews character +conversion and adds typical option formatting, allowing seeks to be specified +in bytes rather than in blocks, allowing arbitrary bytes as padding, and +printing in a format that’s easy for machines to parse. .SH COPYRIGHT From 8508479a5b0e76aee6ce99999dcacaa093dedf10 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 27 May 2024 22:07:17 -0600 Subject: [PATCH 062/343] tests: test.sh: remove superfluous printing of test category --- tests/test.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/test.sh b/tests/test.sh index bec71ff..43f6eb8 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -17,8 +17,6 @@ then exit 1 fi -printf "Starting Bonsai testing.\n\n" - for script in tests/bonsai/*.sh; do export UTIL="$(printf '%s\n' "$script" \ | sed -e 's/\.sh//g' -e 's;tests\/bonsai\/;;g')" @@ -28,8 +26,6 @@ for script in tests/bonsai/*.sh; do printf '\n' done -printf "Starting POSIX compatibility testing.\n\n" - for test in tests/posix/*.sh; do export PATH="$BIN:$PATH" printf '%s: %s: Testing utility.\n' "$0" "$test" From 9bfc5876238d6808a8a0ed0581c9ff3d0a846571 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 27 May 2024 22:12:54 -0600 Subject: [PATCH 063/343] tests: posix: add environment script for sourcing in tests --- tests/posix/posix_env | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 tests/posix/posix_env diff --git a/tests/posix/posix_env b/tests/posix/posix_env new file mode 100644 index 0000000..56c5701 --- /dev/null +++ b/tests/posix/posix_env @@ -0,0 +1,3 @@ +#!/bin/sh + +PATH="$PWD/bin:$PATH" From 94ada03ce4a6624e3430091a805e131f0f35941b Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 27 May 2024 22:17:30 -0600 Subject: [PATCH 064/343] tests: adds easy localization --- tests/locales/en_US.UTF-8 | 4 ++++ tests/test.sh | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 tests/locales/en_US.UTF-8 diff --git a/tests/locales/en_US.UTF-8 b/tests/locales/en_US.UTF-8 new file mode 100644 index 0000000..95e2efb --- /dev/null +++ b/tests/locales/en_US.UTF-8 @@ -0,0 +1,4 @@ +#!/bin/sh + +export RUN_ERR='Run this script in the root of the project' +export TEST_STR='Testing utility' diff --git a/tests/test.sh b/tests/test.sh index 43f6eb8..47a57a3 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -9,11 +9,13 @@ set -e +. "./locales/$LANG" + export BIN=build/bin if ! ls Makefile >/dev/null 2>&1 then - printf '%s: Run this script in the root of the project.\n' "$0" 1>&2 + printf '%s: %s.\n' "$0" "$RUN_ERR" 1>&2 exit 1 fi @@ -21,7 +23,7 @@ for script in tests/bonsai/*.sh; do export UTIL="$(printf '%s\n' "$script" \ | sed -e 's/\.sh//g' -e 's;tests\/bonsai\/;;g')" - printf '%s: %s: Testing utility.\n' "$0" "$UTIL" + printf '%s: %s: %s\n' "$0" "$UTIL" "$TEST_STR" "$script" printf '\n' done From 787f0dc6e2d6b7cf3318fa22d46b17b8cd6f6a20 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 27 May 2024 22:23:49 -0600 Subject: [PATCH 065/343] tests: test.sh: actually includes localization variables --- tests/test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test.sh b/tests/test.sh index 47a57a3..0d39dff 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -15,7 +15,7 @@ export BIN=build/bin if ! ls Makefile >/dev/null 2>&1 then - printf '%s: %s.\n' "$0" "$RUN_ERR" 1>&2 + printf '%s: %s\n' "$0" "$RUN_ERR" 1>&2 exit 1 fi @@ -30,7 +30,7 @@ done for test in tests/posix/*.sh; do export PATH="$BIN:$PATH" - printf '%s: %s: Testing utility.\n' "$0" "$test" + printf '%s: %s: %s\n' "$0" "$test" "$TEST_STR" "$utility" printf '\n' done From 406feb3dc7bea899da4bcb97846d58bc89d06eb1 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 27 May 2024 22:37:15 -0600 Subject: [PATCH 066/343] tests: test.sh: fixes locales when run from root of project --- tests/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test.sh b/tests/test.sh index 0d39dff..61bb814 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -9,7 +9,7 @@ set -e -. "./locales/$LANG" +. "tests/locales/$LANG" export BIN=build/bin From 70cbc52c932e799b4b9e863d73adbdf95006184c Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 2 Jun 2024 18:47:14 -0600 Subject: [PATCH 067/343] docs: updates to use man(7) macros to fix formatting --- docs/dj.1 | 119 ++++++++++++++++-------------------------------- docs/false.1 | 40 +++++++++-------- docs/fop.1 | 58 ++++++++++++------------ docs/hru.1 | 58 ++++++++++++------------ docs/intcmp.1 | 107 +++++++++++++++++++++---------------------- docs/mm.1 | 51 +++++++-------------- docs/npc.1 | 61 ++++++++++++------------- docs/rpn.1 | 85 +++++++++++++++++++---------------- docs/scrut.1 | 122 ++++++++++++++++++-------------------------------- docs/str.1 | 44 +++++++++--------- docs/strcmp.1 | 66 ++++++++++++++------------- docs/swab.1 | 54 +++++++++------------- docs/true.1 | 36 ++++++++------- 13 files changed, 406 insertions(+), 495 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 7af1c00..df660fa 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -3,15 +3,13 @@ .\" .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . - -.TH dj 1 - +.\" +.TH DJ 1 .SH NAME - dj \(en disk jockey - +.\" .SH SYNOPSIS - +.\" dj .RB ( -AdHnq ) .RB ( -a @@ -44,102 +42,63 @@ dj .R [ .B output offset .R ]) - +.\" .SH OPTIONS - -.B -i -.RS +.\" +.IP \fB-i\fP Takes a file path as an argument and opens it for use as an input. -.RE - -.B -b -.RS +.IP \fB-b\fP Takes a numeric argument as the size in bytes of the input buffer, with the default being 1024. -.RE - -.B -s -.RS +.IP \fB-s\fP Takes a numeric argument as the number of bytes to skip into the input before starting to read. If the standard input is used, bytes read to this point are discarded. -.RE - -.B -o -.RS +.IP \fB-o\fP Takes a file path as an argument and opens it for use as an output. -.RE - -.B -B -.RS +.IP \fB-B\fP Does the same as .B -b but for the output buffer. -.RE - -.B -S -.RS +.IP \fB-S\fP Skips a number of bytes through the output before starting to write from the input. If the output is a stream, null characters are printed. -.RE - -.B -a -.RS +.IP \fB-a\fP Accepts a single literal byte with which input buffer is padded in the event of an incomplete read from the input file. -.RE - -.B -A -.RS +.IP \fB-A\fP Specifying this option pads the input buffer with null bytes in the event of an incomplete read. Equivalent to specifying .B -a -with a null byte instead of a character. -.RE - -.B -c -.RS +with a null byte instead of a character. +.IP \fB-c\fP Specifies a number of reads to make. The default is zero, in which case the input is read until a partial or empty read is made. -.RE - -.B -d -.RS +.IP \fB-d\fP Prints invocation information before program execution as described in the DIAGNOSTICS section below. Each invocation increments the debug level of the program. -.RE - -.B -H -.RS +.IP \fB-H\fP Prints diagnostics messages in a human-readable manner as described in the DIAGNOSTICS section below. -.RE - -.B -n -.RS +.IP \fB-n\fP Retries failed reads once more before exiting. -.RE - -.B -q -.RS +.IP \fB-q\fP Suppresses error messages which print when a read or write is partial or empty. Each invocation decrements the debug level of the program. -.RE - .SH STANDARD INPUT - +.\" The standard input shall be used as an input if no inputs are specified or if -one or more of the input files is “-”. - +one or more of the input files is \(lq-\(rq. +.\" .SH DIAGNOSTICS - +.\" On a partial or empty read, a diagnostic message is printed (unless the .B -q option is specified) and the program exits (unless the .B -n option is specified). - +.\" By default, statistics are printed for input and output to the standard error in the following format: @@ -175,12 +134,12 @@ as the only argument: .R out= obs=1024 seek=0 debug= 3 noerror=0 .RE -In non-recoverable errors that don’t pertain to the read-write cycle, a +In non-recoverable errors that don\(cqt pertain to the read-write cycle, a diagnostic message is printed and the program exits with the appropriate sysexits.h(3) status. - +.\" .SH BUGS - +.\" If .B -n is specified along with the @@ -191,29 +150,29 @@ of the count and the input block size). If the or .B -A options are used, this could make data written nonsensical. - +.\" .SH CAVEATS - +.\" Existing files are not truncated on ouput and are instead overwritten. Many lowercase options have capitalized variants and vice-versa which can be confusing. Capitalized options tend to affect output or are more intense versions of lowercase options. - +.\" .SH RATIONALE - +.\" This program was based on the dd(1p) utility as specified in POSIX. While character conversion may have been the original intent of dd(1p), it is irrelevant to its modern use. Because of this, this program eschews character conversion and adds typical option formatting, allowing seeks to be specified in bytes rather than in blocks, allowing arbitrary bytes as padding, and -printing in a format that’s easy for machines to parse. - +printing in a format that\(cqs easy for machines to parse. +.\" .SH COPYRIGHT - -Copyright © 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later +.\" +Copyright \(co 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later . - +.\" .SH SEE ALSO - -dd(1p) +.\" +.BR dd (1p) diff --git a/docs/false.1 b/docs/false.1 index b8463ae..5719899 100644 --- a/docs/false.1 +++ b/docs/false.1 @@ -3,32 +3,34 @@ .\" .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . - +.\" .TH FALSE 1 - .SH NAME - false \(en do nothing, unsuccessfully - +.\" .SH DESCRIPTION - -Do nothing regardless of operands or standard input. -An exit code of 1 will always be returned. - +.\" +Do nothing regardless of operands or standard input. An exit code of 1 will +always be returned. +.\" .SH RATIONALE - -In POSIX.1-2017, false(1p) exists for the construction of control flow and loops -based on a failure. This implementation functions as described in that standard. - +.\" +In POSIX.1-2017, +.BR false (1p) +exists for the construction of control flow and loops based on a failure. This +implementation functions as described in that standard. +.\" .SH AUTHOR - -Written by Emma Tebibyte . - +.\" +Written by Emma Tebibyte +.MT emma@tebibyte.media +.ME . +.\" .SH COPYRIGHT - +.\" This work is marked with CC0 1.0. To see a copy of this license, visit . - +.\" .SH SEE ALSO - -true(1p) +.\" +.BR true (1p) diff --git a/docs/fop.1 b/docs/fop.1 index aa71b50..75a956d 100644 --- a/docs/fop.1 +++ b/docs/fop.1 @@ -3,58 +3,58 @@ .\" .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . - +.\" .TH fop 1 - .SH NAME - fop \(en field operator - +.\" .SH SYNOPSIS - +.\" fop .RB ( -d ) .RB [ delimiter ] .RB index .RB program... - +.\" .SH DESCRIPTION - +.\" Performs operations on specified fields in input data. - +.\" .SH OPTIONS - -.B -d -.RS +.\" +.IP \fB-d\fP Sets a delimiter by which the input data will be split into fields. The default is an ASCII record separator (␞). -.RE - .SH STANDARD INPUT - +.\" Data will be read from the standard input. - +.\" .SH CAVEATS - +.\" Field indices are zero-indexed, which may be unexpected behavior for some users. - +.\" .SH RATIONALE - +.\" With the assumption that tools will output data separated with ASCII field -separators, there is +separators, there is a need for the ability to modify select fields in this data +easily and quickly. -The idea for this utility originated in the fact that GNU ls(1) utility contains -a +The idea for this utility originated in the fact that the GNU +.BR ls (1) +utility contains a .B -h option which enables human-readable units in file size outputs. This -functionality was broken out into hru(1), but there was no easy way to modify -the field in the ouput of ls(1p) without a new tool. - +functionality was broken out into +.BR hru (1), +but there was no easy way to modify the field in the ouput of +.BR ls (1p) +without creating a new tool. +.\" .SH COPYRIGHT - -Copyright © 2024 Emma Tebibyte. License AGPLv3+: GNU AGPL version 3 or later +.\" +Copyright \(co 2024 Emma Tebibyte. License AGPLv3+: GNU AGPL version 3 or later . - +.\" .SH SEE ALSO - -sed(1p) +.\" +.BR sed (1p) diff --git a/docs/hru.1 b/docs/hru.1 index 1ffc00e..f87be16 100644 --- a/docs/hru.1 +++ b/docs/hru.1 @@ -2,58 +2,60 @@ .\" .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . - -.TH hru 1 - +.\" +.TH HRU 1 .SH NAME - hru \(en human readable units - +.\" .SH SYNOPSIS - +.\" hru - +.\" .SH DESCRIPTION - +.\" Convert counts to higher units. - +.\" The program will read byte counts in the form of whole numbers from the standard -input and write to the standard output the same number converted to a higher +input and write to the standard output the same number converted to a higher unit of data as 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, the program 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) +.\" +The GNU project\(cqs 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 +functionality in GNU\(cqs ls(1) can be emulated with fop(1) combined with this program. - +.\" .SH STANDARDS - +.\" 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) are utilized for the ouput of conversions. - +.\" .SH AUTHOR - -Written by Emma Tebibyte . - +.\" +Written by Emma Tebibyte +.MT emma@tebibyte.media +.ME . +.\" .SH COPYRIGHT - -Copyright (c) 2024 Emma Tebibyte. License AGPLv3+: GNU AGPL version 3 or later +.\" +Copyright \(co 2024 Emma Tebibyte. License AGPLv3+: GNU AGPL version 3 or later . - +.\" .SH SEE ALSO - -GNU ls(1), The International System of Units (SI) 9th Edition +.\" +GNU +.BR ls (1), +The International System of Units (SI) 9th Edition diff --git a/docs/intcmp.1 b/docs/intcmp.1 index b15f4c1..79902b9 100644 --- a/docs/intcmp.1 +++ b/docs/intcmp.1 @@ -3,90 +3,87 @@ .\" .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . - -.TH intcmp 1 - +.\" +.TH INTCMP 1 .SH NAME - intcmp \(en compare integers - +.\" .SH SYNOPSIS - +.\" intcmp .RB ( -egl ) .RB [ integer ] .RB [ integer... ] - .SH DESCRIPTION - Compare integers to each other. - -.SH USAGE - -.B -e -.RS +.SH OPTIONS +.IP \fB-e\fP Permits given integers to be equal to each other. -.RE - -.B -g -.RS +.IP \fB-g\fP Permits a given integer to be greater than the following integer. -.RE - -.B -l -.RS +.IP \fB-l\fP Permits a given integer to be less than the following integer. -.RE - .SH EXAMPLES - +.\" It may help to think of the -e, -g, and -l options as equivalent to the -infix algebraic “=”, “>”, and “<” operators respectively, with each option -putting its symbol between every given integer. The following example is -equivalent to evaluating “1 < 2 < 3”: +infix algebraic \(lq=\(rq, \(lq>\(rq, and \(lq<\(rq operators respectively, with +each option putting its symbol between every given integer. The following +example is equivalent to evaluating \(lq1 < 2 < 3\(rq: .RS .R intcmp -l 1 2 3 .RE - +.\" .SH DIAGNOSTICS - +.\" The program will exit with a status code of 0 for a valid expression and with a code of 1 for an invalid expression. In the event of an error, a debug message will be printed and the program will -exit with the appropriate sysexits.h(3) error code. - +exit with the appropriate +.BR sysexits.h (3) +error code. +.\" .SH BUGS +.\" +-egl, \(lqequal to or less than or greater than\(rq, exits 0 no matter what for +valid program usage and may be abused to function as an integer validator. Use +.BR str (1) +instead. +.\" +.SH CAVEATS +.\" +There are multiple ways to express compound comparisons; \(lqless than or equal +to\(rq can be -le or -el, for example. -There are multiple ways to express compound comparisons; “less than or equal -to” can be -le or -el, for example. - -The inequality comparison is -gl or -lg for “less than or greater than”; this -is elegant but unintuitive. - --egl, “equal to or less than or greater than”, exits 0 no matter what for valid -program usage and may be abused to function as an integer validator. -Use str(1) instead. - +The inequality comparison is -gl or -lg for \(lqless than or greater than\(rq; +this is elegant but unintuitive. +.\" .SH RATIONALE - +.\" The traditional tool for integer comparisons in POSIX and other Unix shells has -been test(1). This tool also handles string comparisons and file scrutiny. -These parts of its functionality have been broken out into multiple utilities. - -This program’s functionality may be performed on a POSIX-compliant system with -test(1p). +been +.BR test (1). +This tool also handles string comparisons and file scrutiny. These parts of its +functionality have been broken out into multiple utilities. +This program\(cqs functionality may be performed on a POSIX-compliant system +with +.BR test (1p). +.\" .SH AUTHOR - -Written by DTB . - +.\" +Written by DTB +.MT trinity@trinity.moe +.ME . +.\" .SH COPYRIGHT - -Copyright © 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later +.\" +Copyright \(co 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later . - +.\" .SH SEE ALSO - -strcmp(1), scrut(1), str(1), test(1p) +.BR scrut (1), +.BR strcmp (1), +.BR str (1), +.BR test (1p) diff --git a/docs/mm.1 b/docs/mm.1 index 5315c8c..72ce9a1 100644 --- a/docs/mm.1 +++ b/docs/mm.1 @@ -2,62 +2,41 @@ .\" .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . - +.\" .TH mm 1 - .SH NAME - mm \(en middleman - .SH SYNOPSIS - +.\" mm .RB ( -aenu ) .RB ( -i .RB [ input ]) .RB ( -o .RB [ output ]) - +.\" .SH DESCRIPTION - +.\" Catenate input files and write them to the start of each output file or stream. - +.\" .SH OPTIONS - -.B -a -.RS +.\" +.IP -a Opens subsequent outputs for appending rather than updating. -.RE - -.B -e -.RS +.IP -e Use the standard error as an output. -.RE - -.B -i -.RS +.IP -i Opens a path as an input. Without any inputs specified mm will use the standard input. The standard input shall be used as an input if one or more of the input files is “-”. -.RE - -.B -o -.RS +.IP -o Opens a path as an output. Without any outputs specified mm will use the standard output. The standard output shall be used as an output if one or more of the output files is “-”. - -.RE - -.B -u -.RS +.IP -u Ensures neither input or output will be buffered. -.RE - -.B -n -.RS +.IP -n Causes SIGINT signals to be ignored. -.RE .SH DIAGNOSTICS @@ -84,5 +63,7 @@ Copyright (c) 2024 DTB. License AGPLv3+: GNU AGPL version 3 or later . .SH SEE ALSO - -cat(1p), dd(1), dj(1), tee(1p) +.BR cat (1p), +.BR dd (1), +.BR dj (1), +.BR tee (1p) diff --git a/docs/npc.1 b/docs/npc.1 index f3b7d0c..a75db5e 100644 --- a/docs/npc.1 +++ b/docs/npc.1 @@ -3,20 +3,18 @@ .\" .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . - -.TH npc 1 - +.\" +.TH NPC 1 .SH NAME - npc \(en show non-printing characters - +.\" .SH SYNOPSIS - +.\" npc .RB ( -et ) - +.\" .SH DESCRIPTION - +.\" Print normally non-printing characters. The program reads from standard input and writes to standard output, replacing @@ -26,41 +24,43 @@ character replaced (e.g. control-X becomes '^X'). The delete character (0x7F) becomes '^?'. Characters with the high bit set (>127) are printed as 'M-' followed by the graphical representation for the same character without the high bit set. - +.\" .SH USAGE - -.B -e -.RS +.\" +.IP -e Prints a currency sign ('$') before each line ending. -.RE - -.B -t -.RS +.IP -t Prints tab characters as '^I' rather than a literal horizontal tab. -.RE - +.\" .SH DIAGNOSTICS - +.\" In the event of an error, a debug message will be printed and the program will -exit with the appropriate sysexits.h(3) error code. - +exit with the appropriate +.BR sysexits.h (3) +error code. +.\" .SH BUGS - +.\" The program operates in single-byte chunks regardless of intended encoding. - +.\" .SH RATIONALE - +.\" POSIX currently lacks a way to display non-printing characters in the terminal -using a standard tool. A popular extension to cat(1p), the +using a standard tool. A popular extension to +.BR cat (1p), +the .B -v option, is the bandage solution GNU and other software suites use. - +.\" This functionality is a separate tool because its usefulness extends beyond that -of cat(1p). - +of +.BR cat (1p). +.\" .SH AUTHOR -Written by DTB . +Written by DTB +.MT trinity@trinity.moe +.ME . .SH COPYRIGHT @@ -69,7 +69,8 @@ Copyright © 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later .SH SEE ALSO -cat(1p), cat-v(1) +.BR cat (1p), +.BR cat-v (1) .I UNIX Style, or cat -v Considered Harmful by Rob Pike diff --git a/docs/rpn.1 b/docs/rpn.1 index 0b6b264..53a8a9f 100644 --- a/docs/rpn.1 +++ b/docs/rpn.1 @@ -3,20 +3,19 @@ .\" .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . - +.\" .TH rpn 1 - .SH NAME - rpn \(en reverse polish notation evaluation - +.\" .SH SYNOPSIS - +.\" rpn -.RB [numbers...]\ [operators...] - +.RB [ numbers... ] +.RB [ operators... ] +.\" .SH DESCRIPTION - +.\" Evaluate reverse polish notation. The program evaluates reverse polish notation expressions either read from the @@ -28,48 +27,58 @@ standard output. Any further specified numbers will be placed at the end of the stack. For information on for reverse polish notation syntax, see rpn(7). - +.\" .SH STANDARD INPUT - -If arguments are passed , they are interpreted as an expression to be evaluated. -Otherwise, it reads whitespace-delimited numbers and operations from the -standard input. - +.\" +If arguments are passed, they are interpreted as an expression to be +evaluated. Otherwise, it reads whitespace-delimited numbers and operations from +the standard input. +.\" .SH DIAGNOSTICS - +.\" In the event of a syntax error, the program will print an In the event of an error, a debug message will be printed and the program will -exit with the appropriate sysexits.h(3) error code. - +exit with the appropriate +.BR sysexits.h(3) +error code. +.\" .SH CAVEATS - +.\" Due to precision constraints and the way floats are represented in accordance -with the IEEE Standard for Floating Point Arithmetic (IEEE 754), floating-point -arithmetic has rounding errors. This is somewhat curbed by using the -machine epsilon as provided by the Rust standard library to which to round +with the IEEE Standard for Floating Point Arithmetic (\fIIEEE 754\fP), +floating-point arithmetic has rounding errors. This is somewhat curbed by using +the machine epsilon as provided by the Rust standard library to which to round numbers. Because of this, variation is expected in the number of decimal places the program can handle based on the platform and hardware of any given machine. - +.\" .SH RATIONALE - -An infix notation calculation utility, bc(1p), is included in the POSIX -standard, but does not accept expressions as arguments; in scripts, any -predefined, non-interactive input must be piped into the program. A dc(1) -pre-dates the standardized bc(1p), the latter originally being a preprocessor -for the former, and was included in UNIX v2 onward. While it implements reverse -polish notation, it still suffers from being unable to accept an expression as -an argument. - +.\" +An infix notation calculation utility, +.BR bc (1p), +is included in the POSIX standard, but does not accept expressions as arguments; +in scripts, any predefined, non-interactive input must be piped into the +program. A +.BR dc (1) +pre-dates the standardized +.BR bc (1p), +the latter originally being a preprocessor for the former, and was included in +UNIX v2 onward. While it implements reverse polish notation, it still suffers +from being unable to accept an expression as an argument. +.\" .SH AUTHOR - -Written by Emma Tebibyte . - +.\" +Written by Emma Tebibyte +.MT emma@tebibyte.media +.ME . +.\" .SH COPYRIGHT - +.\" Copyright (c) 2024 Emma Tebibyte. License AGPLv3+: GNU AGPL version 3 or later . - +.\" .SH SEE ALSO - -bc(1p), dc(1), rpn(7), IEEE 754 +.BR bc (1p), +.BR dc (1), +.BR rpn(7), +.I IEEE 754 diff --git a/docs/scrut.1 b/docs/scrut.1 index 4c0b75b..e6973ad 100644 --- a/docs/scrut.1 +++ b/docs/scrut.1 @@ -3,122 +3,86 @@ .\" .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . - +.\" .TH scrut 1 - .SH NAME - scrut \(en scrutinize file properties - .SH SYNOPSIS - +.\" scrut .RB ( -bcdefgkprsuwxLS ) .RB [ file... ] - +.\" .SH DESCRIPTION - +.\" Determine if files comply with requirements. - +.\" .SH OPTIONS - -.B -L -.RS +.\" +.IP -L Requires the given files to exist and be symbolic links. -.RE - -.B -S -.RS +.IP -S Requires the given files to exist and be sockets. -.RE - -.B -b -.RS +.IP -b Requires the given files to exist and be block special files. -.RE - -.B -c -.RS +.IP -c Requires the given files to exist and be character special files. -.RE - -.B -d -.RS +.IP -d Requires the given files to exist and be directories. -.RE - -.B -e -.RS +.IP -e Requires the given files to exist, and is redundant to any other option. -.RE - -.B -e -.RS +.IP -e Requires the given files to exist and be regular files. -.RE - -.B -g -.RS +.IP -g Requires the given files to exist and have their set group ID flags set. -.RE - -.B -k -.RS +.IP -k Requires the given files to exist and have their sticky bit set. -.RE - -.B -p -.RS +.IP -p Requires the given files to exist and be named pipes. -.RE - -.B -r -.RS +.IP -r Requires the given files to exist and be readable. -.RE - -.B -u -.RS +.IP -u Requires the given files to exist and have their set user ID flags set. -.RE - -.B -w -.RS +.IP -w Requires the given files to exist and be writable. -.RE - -.B -x -.RS +.IP -x Requires the given files to exist and be executable. -.RE - -.SH EXIT STATUS - +.\" +.SH DIAGNOSTICS +.\" If the given files comply with the specified requirements, the program will exit successfully. If not, it exits unsuccessfully. When invoked incorrectly, a debug message will be printed and the program will -exit with the appropriate sysexits.h(3) error code. - -.SH STANDARDS - -The test(1p) utility contains functionality that was broken out into separate -programs. Thus, the scope of this program is narrower than it. Notably, the +exit with the appropriate +.BR sysexits.h (3) +error code. +.\" +.SH RATIONALE +.\" +The +.BR test (1p) +utility contains functionality that was broken out into separate programs. Thus, +the scope of this program is narrower than it. Notably, the .B -h option is now invalid and therefore shows usage information instead of being an alias to the modern .B -L option. - +.\" .SH AUTHOR - -Written by DTB . - +.\" +Written by DTB +.MT trinity@trinity.moe +.ME . +.\" .SH COPYRIGHT -Copyright © 2024 DTB. License AGPLv3+: GNU AGPL version 3 or later +Copyright \(co 2024 DTB. License AGPLv3+: GNU AGPL version 3 or later . .SH SEE ALSO -access(3p), lstat(3p), test(1p) +.BR access (3p), +.BR lstat (3p), +.BR test (1p) diff --git a/docs/str.1 b/docs/str.1 index ef86861..641a75f 100644 --- a/docs/str.1 +++ b/docs/str.1 @@ -3,28 +3,27 @@ .\" .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . - +.\" .TH STR 1 - .SH NAME - str \(en test the character types of string arguments - +.\" .SH SYNOPSIS - +.\" str .RB [ type ] .RB [ string... ] - +.\" .SH DESCRIPTION - +.\" Test string arguments. The tests in this program are equivalent to the functions with the same names in -ctype.h(0p) and are the methods by which string arguments are tested. - +.BR ctype.h (0p) +and are the methods by which string arguments are tested. +.\" .SH DIAGNOSTICS - +.\" If all tests pass, the program will exit with an exit code of 0. If any of the tests fail, the program will exit unsuccessfully with an error code of 1. @@ -33,23 +32,26 @@ tests. When invoked incorrectly, a debug message will be printed and the program will exit with the appropriate sysexits.h(3) error code. - -.SH BUGS - +.\" +.SH CAVEATS +.\" There’s no way of knowing which argument failed the test without re-testing arguments individually. If a character in a string isn't valid ASCII str will exit unsuccessfully. - +.\" .SH AUTHOR - -Written by DTB . - +.\" +Written by DTB +.MT trinity@trinity.moe +.ME . +.\" .SH COPYRIGHT - +.\" Copyright © 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later . - +.\" .SH SEE ALSO - -ctype(3p), strcmp(1), ascii(7) +.BR ctype (3p), +.BR strcmp(1), +.BR ascii(7) diff --git a/docs/strcmp.1 b/docs/strcmp.1 index 48681c6..1cc03dd 100644 --- a/docs/strcmp.1 +++ b/docs/strcmp.1 @@ -3,61 +3,63 @@ .\" .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . - +.\" .TH STRCMP 1 - .SH NAME - strcmp \(en compare strings - +.\" .SH SYNOPSIS - +.\" strcmp .RM [ string ] .RB [ strings... ] - +.\" .SH DESCRIPTION - +.\" Check whether string arguments are the same. - +.\" .SH DIAGNOSTICS - +.\" The program will exit successfully if the strings are identical. Otherwise, it exits with the value 1 if an earlier string has a greater byte value than a -later string (e.g. -.R strcmp b a -) -and 255 if an earlier string has a lesser byte value (e.g. -.R strcmp a b -). +later string (e.g. strcmp b a) and 255 if an earlier string has a lesser byte +value (e.g. strcmp a b). When invoked incorrectly, a debug message will be printed and the program will -exit with the appropriate sysexits.h(3) error code. - -.SH UNICODE - +exit with the appropriate +.BR sysexits.h (3) +error code. +.\" +.SH CAVEATS +.\" The program will exit unsuccessfully if the given strings are not identical; therefore, Unicode strings may need to be normalized if the intent is to check visual similarity and not byte similarity. - +.\" .SH RATIONALE - +.\" The traditional tool for string comparisons in POSIX and other Unix shells has -been test(1). This tool also handles integer comparisons and file scrutiny. -These parts of its functionality have been broken out into multiple utilities. +been +.BR test (1). +This tool also handles integer comparisons and file scrutiny. These parts of its +functionality have been broken out into multiple utilities. This program’s functionality may be performed on a POSIX-compliant system with -test(1p). - +.BR test (1p). +.\" .SH AUTHOR - -Written by DTB . - +.\" +Written by DTB +.MT trinity@trinity.moe +.ME . +.\" .SH COPYRIGHT - +.\" Copyright © 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later . - +.\" .SH SEE ALSO - -strcmp(3), intcmp(1), scrut(1), test(1p) +.BR strcmp (3), +.BR intcmp (1), +.BR scrut (1), +.BR test (1p) diff --git a/docs/swab.1 b/docs/swab.1 index f7e10b0..078dd54 100644 --- a/docs/swab.1 +++ b/docs/swab.1 @@ -3,43 +3,36 @@ .\" .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . - -.TH swab 1 - +.\" +.TH SWAB 1 .SH NAME - swab \(en swap bytes - +.\" .SH SYNOPSIS - +.\" swab .RB ( -f ) .RB ( -w .R [ .B word size .R ]) - +.\" .SH USAGE - +.\" Swap the latter and former halves of a block of bytes. - +.\" .SH OPTIONS - -.B -f -.RS +.\" +.IP -f Ignore system call interruptions. -.RE - -.B -w -.RS +.IP -w 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. -.RE - +.\" .SH EXAMPLES - +.\" The following sh(1p) line: .RS @@ -51,27 +44,24 @@ Produces the following output: .RS .R ehll oowlr!d .RE - +.\" .SH DIAGNOSTICS - +.\" In the event of an error, a debug message will be printed and the program will exit with the appropriate sysexits.h(3) error code. - +.\" .SH RATIONALE - -This program was modeled and named after the -.R conv=swab -functionality specified in the dd(1p) utility. It additionally allows the word -size to be configured. +.\" +This program was modeled and named after the conv=swab functionality specified +in the dd(1p) utility. It additionally allows the word size to be configured. This functionality 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) +.BR dd (1p) diff --git a/docs/true.1 b/docs/true.1 index 9b02fdd..1025c21 100644 --- a/docs/true.1 +++ b/docs/true.1 @@ -3,32 +3,34 @@ .\" .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . - +.\" .TH TRUE 1 - .SH NAME - true \(en do nothing, successfully - +.\" .SH DESCRIPTION - +.\" Do nothing regardless of operands or standard input. An exit code of 0 will always be returned. - +.\" .SH RATIONALE - -In POSIX.1-2017, true(1p) exists for the construction of control flow and loops -based on a success. This implementation functions as described in that standard. - +.\" +In \fIPOSIX.1-2017\fP, +.BR true (1p) +exists for the construction of control flow and loops based on a success. This +implementation functions as described in that standard. +.\" .SH AUTHOR - -Written by Emma Tebibyte . - +.\" +Written by Emma Tebibyte +.MT emma@tebibyte.media +.ME . +.\" .SH COPYRIGHT - +.\" This work is marked with CC0 1.0. To see a copy of this license, visit . - +.\" .SH SEE ALSO - -false(1p) +.BR false (1p), +.BR true (1p) From 2dd6c0ded7a65fee58a8fbff5f62891d5484b778 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 2 Jun 2024 19:05:30 -0600 Subject: [PATCH 068/343] fop(1): adds the ability to use any string as a delimiter --- src/fop.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/fop.rs b/src/fop.rs index b829602..d28a7b0 100644 --- a/src/fop.rs +++ b/src/fop.rs @@ -32,18 +32,12 @@ use sysexits::{ EX_DATAERR, EX_IOERR, EX_UNAVAILABLE, EX_USAGE }; fn main() { let argv = args().collect::>(); - let mut d = '␞'; + let mut d = "␞".to_owned(); let mut arg_parser = Parser::new(&argv, "d:"); while let Some(opt) = arg_parser.next() { match opt { - Ok(Opt('d', Some(arg))) => { - let arg_char = arg.chars().collect::>(); - if arg_char.len() > 1 { - eprintln!("{}: {}: Not a character.", argv[0], arg); - exit(EX_USAGE); - } else { d = arg_char[0]; } - }, + Ok(Opt('d', Some(arg))) => d = arg, _ => {}, }; } @@ -63,7 +57,7 @@ fn main() { let mut buf = String::new(); let _ = stdin().read_to_string(&mut buf); - let mut fields = buf.split(d).collect::>(); + let mut fields = buf.split(&d).collect::>(); let opts = argv .iter() From 24b235e7c1737a5e01c5390dcac3052e3c64d760 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 2 Jun 2024 19:15:23 -0600 Subject: [PATCH 069/343] README: updated to make current --- README | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README b/README index accfc7e..d7a79f6 100644 --- a/README +++ b/README @@ -20,9 +20,9 @@ See docs/ for more on the specific utilities currently implemented. Building The coreutils require a POSIX-compliant environment to compile, including a C -compiler and preprocessor (cc(1) and cpp(1) by default) with the -idirafter -flag, a Rust compiler (rustc(1) by default), bindgen(1), and a POSIX-compliant -make(1) utility. +compiler and preprocessor (cc(1) and cpp(1) by default), an edition 2023 Rust +compiler (rustc(1) by default), bindgen(1), and a POSIX-compliant make(1) +utility. To build and install: From 642774bccf76b7025005c0d34f1f6b0b2d22b275 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 2 Jun 2024 19:21:56 -0600 Subject: [PATCH 070/343] src: removed erroneous file --- src/test.rs | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 src/test.rs diff --git a/src/test.rs b/src/test.rs deleted file mode 100644 index 4a602b1..0000000 --- a/src/test.rs +++ /dev/null @@ -1,10 +0,0 @@ -extern crate strerror; - -use strerror::raw_message; - -fn main() { - stdout.write_all(b"meow\n").unwrap_or_else(|e| { - eprintln!("{}", raw_message(e)); - std::process::exit(1); - }); -} From c88c41b21370a1866b3a2324a0c79f5bb208e06e Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 2 Jun 2024 20:14:06 -0600 Subject: [PATCH 071/343] tests: adds toki pona locale --- tests/locales/tok | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 tests/locales/tok diff --git a/tests/locales/tok b/tests/locales/tok new file mode 100644 index 0000000..7770742 --- /dev/null +++ b/tests/locales/tok @@ -0,0 +1,5 @@ +#!/bin/sh + +export RUN_ERR="ilo ni li ken ala pali lon ma ni. sina ken kepeken ona lon ma \ +sewi" +export TEST_STR='ilo pali' From d6fb08019eb4a1d80b6160f02678afd67567ebc2 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 2 Jun 2024 23:14:40 -0600 Subject: [PATCH 072/343] CONDUCT: initial commit --- CONDUCT | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++ CONTRIBUTING | 2 ++ 2 files changed, 82 insertions(+) create mode 100644 CONDUCT diff --git a/CONDUCT b/CONDUCT new file mode 100644 index 0000000..0585d15 --- /dev/null +++ b/CONDUCT @@ -0,0 +1,80 @@ +Code of Conduct + +This Code of Conduct is derived from the 10 Pāramitās of Theravadin Buddhism. +You can read more about them in Ṭhānissaro Bhikkhu’s Ten Perfections: A Study +Guide [0]. + +1. Generosity (Dāna) + +Give contributions freely and willingly under the terms of the GNU Affero +General Public License, version 3 or later, or a compatible license. + +2. Ethics (Sīla) + +Do not use nonfree code or uncredited code in contributions. Do not take credit +for others’ contributions. Make sure to utilize the copyright header and license +notice on source files to credit yourself and others for their work. + +3. Renunciation (Nekkhamma) + +Stay committed to the principles of simplicity and interoperability embodied by +the project. Keep your personal will and desire out of the project, for it can +only prove harmful to its success. + +4. Wisdom (Pañña) + +Look to established sources for standards, best practices, and important +implementation details when setting new precedence. Follow the existing +precedence where it applies. + +5. Energy (Viriya) + +Focus on the currently-open, currently-assigned, and currently-in-progress +issues, pull requests, and other endeavors in order to keep yourself and others +from being overwhelmed with responsibility, either from your zeal or your +negligence. + +If you notice an issue, open an issue as soon as you can. If you see a neglected +branch, open a pull request or comment on an existing one, if applicable. Be +diligent in your commitment to making this project work. + +6. Patience (Khanti) + +Be patient with maintainers and other contributors. We all have our own lives +going on and may need significant time to get to things. + +7. Truthfulness (Sacca) + +Communicate honestly and openly. Do not embellish facts to get your way. Make +sure to let maintainers know about any issues along the way and keep ample +communication channels open. + +8. Determination (Adhiṭṭhāna) + +Stay focused on long-term objectives and cultivate attainment to that +achievement by utilizing to the fullest extent possible the tools available to +you for managing the workload. + +9. Loving-Kindness (Mettā) + +Treat everyone with respect, even if they treat you poorly. This does not mean +you have to put up with abuse, but make sure to respond with kindness and with +love in your heart. Support and uplift maintainers and other contributors with +your words and actions. + +Do not use angry or hateful language toward contributors, such as demeaning +phrases and slurs. Make sure that if you do not know the pronouns of a +contributor to ask for them and, in the meantime, use gender-neutral they/them +or equivalent pronouns. + +10. Equanimity (Upekkhā) + +Keep a balanced perspective on all suggestions and contributions and make +judgements not from a place of ego and personal preference but on their +usefulness and suitability to the project. Make sure to keep an eye on the +bigger picture as implementing individual features may seem intuitive at first +but scale poorly in practical use. Keep a level head about your own work: it is +not shameful to make a mistake in this vein, and fixing it usually leads to +more insight. + +[0] diff --git a/CONTRIBUTING b/CONTRIBUTING index d7fdc8e..74e821e 100644 --- a/CONTRIBUTING +++ b/CONTRIBUTING @@ -1,3 +1,5 @@ +Make sure to read our code of conduct in the CONDUCT file. + When contributing a pull request to the main branch, please sign your commits with a PGP key and add your name and the year to the bottom of the list of copyright holders for the file. For example, an existing copyright header might From c32c554e03f8f7fdd62bbf981bbf70e3fe318f71 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 3 Jun 2024 23:07:19 -0600 Subject: [PATCH 073/343] docs: removed unnecessary comments --- docs/dj.1 | 19 +++++++++---------- docs/false.1 | 9 ++++----- docs/fop.1 | 15 +++++++-------- docs/hru.1 | 19 +++++++++---------- docs/intcmp.1 | 17 ++++++++++------- docs/mm.1 | 17 +++++++++-------- docs/npc.1 | 19 +++++++++---------- docs/rpn.1 | 16 ++++++++-------- docs/scrut.1 | 15 +++++++-------- docs/str.1 | 12 ++++++------ docs/strcmp.1 | 14 +++++++------- docs/swab.1 | 14 +++++++------- docs/true.1 | 8 ++++---- 13 files changed, 96 insertions(+), 98 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index df660fa..21f0e1d 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -9,7 +9,7 @@ dj \(en disk jockey .\" .SH SYNOPSIS -.\" + dj .RB ( -AdHnq ) .RB ( -a @@ -44,7 +44,7 @@ dj .R ]) .\" .SH OPTIONS -.\" + .IP \fB-i\fP Takes a file path as an argument and opens it for use as an input. .IP \fB-b\fP @@ -87,18 +87,18 @@ Retries failed reads once more before exiting. Suppresses error messages which print when a read or write is partial or empty. Each invocation decrements the debug level of the program. .SH STANDARD INPUT -.\" + The standard input shall be used as an input if no inputs are specified or if one or more of the input files is \(lq-\(rq. .\" .SH DIAGNOSTICS -.\" + On a partial or empty read, a diagnostic message is printed (unless the .B -q option is specified) and the program exits (unless the .B -n option is specified). -.\" + By default, statistics are printed for input and output to the standard error in the following format: @@ -139,7 +139,7 @@ diagnostic message is printed and the program exits with the appropriate sysexits.h(3) status. .\" .SH BUGS -.\" + If .B -n is specified along with the @@ -152,7 +152,7 @@ or options are used, this could make data written nonsensical. .\" .SH CAVEATS -.\" + Existing files are not truncated on ouput and are instead overwritten. Many lowercase options have capitalized variants and vice-versa which can be @@ -160,7 +160,7 @@ confusing. Capitalized options tend to affect output or are more intense versions of lowercase options. .\" .SH RATIONALE -.\" + This program was based on the dd(1p) utility as specified in POSIX. While character conversion may have been the original intent of dd(1p), it is irrelevant to its modern use. Because of this, this program eschews character @@ -169,10 +169,9 @@ in bytes rather than in blocks, allowing arbitrary bytes as padding, and printing in a format that\(cqs easy for machines to parse. .\" .SH COPYRIGHT -.\" + Copyright \(co 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later . .\" .SH SEE ALSO -.\" .BR dd (1p) diff --git a/docs/false.1 b/docs/false.1 index 5719899..91bd286 100644 --- a/docs/false.1 +++ b/docs/false.1 @@ -9,28 +9,27 @@ false \(en do nothing, unsuccessfully .\" .SH DESCRIPTION -.\" + Do nothing regardless of operands or standard input. An exit code of 1 will always be returned. .\" .SH RATIONALE -.\" + In POSIX.1-2017, .BR false (1p) exists for the construction of control flow and loops based on a failure. This implementation functions as described in that standard. .\" .SH AUTHOR -.\" + Written by Emma Tebibyte .MT emma@tebibyte.media .ME . .\" .SH COPYRIGHT -.\" + This work is marked with CC0 1.0. To see a copy of this license, visit . .\" .SH SEE ALSO -.\" .BR true (1p) diff --git a/docs/fop.1 b/docs/fop.1 index 75a956d..29ba7ea 100644 --- a/docs/fop.1 +++ b/docs/fop.1 @@ -9,7 +9,7 @@ fop \(en field operator .\" .SH SYNOPSIS -.\" + fop .RB ( -d ) .RB [ delimiter ] @@ -17,24 +17,24 @@ fop .RB program... .\" .SH DESCRIPTION -.\" + Performs operations on specified fields in input data. .\" .SH OPTIONS -.\" + .IP \fB-d\fP Sets a delimiter by which the input data will be split into fields. The default is an ASCII record separator (␞). .SH STANDARD INPUT -.\" + Data will be read from the standard input. .\" .SH CAVEATS -.\" + Field indices are zero-indexed, which may be unexpected behavior for some users. .\" .SH RATIONALE -.\" + With the assumption that tools will output data separated with ASCII field separators, there is a need for the ability to modify select fields in this data easily and quickly. @@ -51,10 +51,9 @@ but there was no easy way to modify the field in the ouput of without creating a new tool. .\" .SH COPYRIGHT -.\" + Copyright \(co 2024 Emma Tebibyte. License AGPLv3+: GNU AGPL version 3 or later . .\" .SH SEE ALSO -.\" .BR sed (1p) diff --git a/docs/hru.1 b/docs/hru.1 index f87be16..984222a 100644 --- a/docs/hru.1 +++ b/docs/hru.1 @@ -8,28 +8,28 @@ hru \(en human readable units .\" .SH SYNOPSIS -.\" + hru .\" .SH DESCRIPTION -.\" + Convert counts to higher units. -.\" + The program will read byte counts in the form of whole numbers from the standard input and write to the standard output the same number converted to a higher unit of data as 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, the program will exit with the appropriate error code as defined by sysexits.h(3) and print an error message. .\" .SH RATIONALE -.\" + The GNU project\(cqs 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 @@ -38,24 +38,23 @@ functionality in GNU\(cqs ls(1) can be emulated with fop(1) combined with this program. .\" .SH STANDARDS -.\" + 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) are utilized for the ouput of conversions. .\" .SH AUTHOR -.\" + Written by Emma Tebibyte .MT emma@tebibyte.media .ME . .\" .SH COPYRIGHT -.\" + Copyright \(co 2024 Emma Tebibyte. License AGPLv3+: GNU AGPL version 3 or later . .\" .SH SEE ALSO -.\" GNU .BR ls (1), The International System of Units (SI) 9th Edition diff --git a/docs/intcmp.1 b/docs/intcmp.1 index 79902b9..ed88038 100644 --- a/docs/intcmp.1 +++ b/docs/intcmp.1 @@ -9,22 +9,25 @@ intcmp \(en compare integers .\" .SH SYNOPSIS -.\" + intcmp .RB ( -egl ) .RB [ integer ] .RB [ integer... ] .SH DESCRIPTION Compare integers to each other. +.\" .SH OPTIONS + .IP \fB-e\fP Permits given integers to be equal to each other. .IP \fB-g\fP Permits a given integer to be greater than the following integer. .IP \fB-l\fP Permits a given integer to be less than the following integer. -.SH EXAMPLES .\" +.SH EXAMPLES + It may help to think of the -e, -g, and -l options as equivalent to the infix algebraic \(lq=\(rq, \(lq>\(rq, and \(lq<\(rq operators respectively, with each option putting its symbol between every given integer. The following @@ -35,7 +38,7 @@ example is equivalent to evaluating \(lq1 < 2 < 3\(rq: .RE .\" .SH DIAGNOSTICS -.\" + The program will exit with a status code of 0 for a valid expression and with a code of 1 for an invalid expression. @@ -45,14 +48,14 @@ exit with the appropriate error code. .\" .SH BUGS -.\" + -egl, \(lqequal to or less than or greater than\(rq, exits 0 no matter what for valid program usage and may be abused to function as an integer validator. Use .BR str (1) instead. .\" .SH CAVEATS -.\" + There are multiple ways to express compound comparisons; \(lqless than or equal to\(rq can be -le or -el, for example. @@ -60,7 +63,7 @@ The inequality comparison is -gl or -lg for \(lqless than or greater than\(rq; this is elegant but unintuitive. .\" .SH RATIONALE -.\" + The traditional tool for integer comparisons in POSIX and other Unix shells has been .BR test (1). @@ -72,7 +75,7 @@ with .BR test (1p). .\" .SH AUTHOR -.\" + Written by DTB .MT trinity@trinity.moe .ME . diff --git a/docs/mm.1 b/docs/mm.1 index 72ce9a1..c971c00 100644 --- a/docs/mm.1 +++ b/docs/mm.1 @@ -6,8 +6,9 @@ .TH mm 1 .SH NAME mm \(en middleman -.SH SYNOPSIS .\" +.SH SYNOPSIS + mm .RB ( -aenu ) .RB ( -i @@ -16,11 +17,11 @@ mm .RB [ output ]) .\" .SH DESCRIPTION -.\" + Catenate input files and write them to the start of each output file or stream. .\" .SH OPTIONS -.\" + .IP -a Opens subsequent outputs for appending rather than updating. .IP -e @@ -37,7 +38,7 @@ of the output files is “-”. Ensures neither input or output will be buffered. .IP -n Causes SIGINT signals to be ignored. - +.\" .SH DIAGNOSTICS If an output can no longer be written mm prints a diagnostic message, ceases @@ -46,22 +47,22 @@ continues, eventually exiting unsuccessfully. When an error is encountered, diagnostic message is printed and the program exits with the appropriate sysexits.h(3) status. - +.\" .SH CAVEATS Existing files are not truncated on ouput and are instead overwritten. - +.\" .SH RATIONALE The cat(1p) and tee(1p) programs specified in POSIX together provide similar functionality. The separation of the two sets of functionality into separate APIs seemed unncessary. - +.\" .SH COPYRIGHT Copyright (c) 2024 DTB. License AGPLv3+: GNU AGPL version 3 or later . - +.\" .SH SEE ALSO .BR cat (1p), .BR dd (1), diff --git a/docs/npc.1 b/docs/npc.1 index a75db5e..64f3406 100644 --- a/docs/npc.1 +++ b/docs/npc.1 @@ -9,12 +9,12 @@ npc \(en show non-printing characters .\" .SH SYNOPSIS -.\" + npc .RB ( -et ) .\" .SH DESCRIPTION -.\" + Print normally non-printing characters. The program reads from standard input and writes to standard output, replacing @@ -26,32 +26,32 @@ followed by the graphical representation for the same character without the high bit set. .\" .SH USAGE -.\" + .IP -e Prints a currency sign ('$') before each line ending. .IP -t Prints tab characters as '^I' rather than a literal horizontal tab. .\" .SH DIAGNOSTICS -.\" + In the event of an error, a debug message will be printed and the program will exit with the appropriate .BR sysexits.h (3) error code. .\" .SH BUGS -.\" + The program operates in single-byte chunks regardless of intended encoding. .\" .SH RATIONALE -.\" + POSIX currently lacks a way to display non-printing characters in the terminal using a standard tool. A popular extension to .BR cat (1p), the .B -v option, is the bandage solution GNU and other software suites use. -.\" + This functionality is a separate tool because its usefulness extends beyond that of .BR cat (1p). @@ -61,14 +61,13 @@ of Written by DTB .MT trinity@trinity.moe .ME . - +.\" .SH COPYRIGHT Copyright © 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later . - +.\" .SH SEE ALSO - .BR cat (1p), .BR cat-v (1) diff --git a/docs/rpn.1 b/docs/rpn.1 index 53a8a9f..c791613 100644 --- a/docs/rpn.1 +++ b/docs/rpn.1 @@ -9,13 +9,13 @@ rpn \(en reverse polish notation evaluation .\" .SH SYNOPSIS -.\" + rpn .RB [ numbers... ] .RB [ operators... ] .\" .SH DESCRIPTION -.\" + Evaluate reverse polish notation. The program evaluates reverse polish notation expressions either read from the @@ -29,13 +29,13 @@ stack. For information on for reverse polish notation syntax, see rpn(7). .\" .SH STANDARD INPUT -.\" + If arguments are passed, they are interpreted as an expression to be evaluated. Otherwise, it reads whitespace-delimited numbers and operations from the standard input. .\" .SH DIAGNOSTICS -.\" + In the event of a syntax error, the program will print an In the event of an error, a debug message will be printed and the program will @@ -44,7 +44,7 @@ exit with the appropriate error code. .\" .SH CAVEATS -.\" + Due to precision constraints and the way floats are represented in accordance with the IEEE Standard for Floating Point Arithmetic (\fIIEEE 754\fP), floating-point arithmetic has rounding errors. This is somewhat curbed by using @@ -53,7 +53,7 @@ numbers. Because of this, variation is expected in the number of decimal places the program can handle based on the platform and hardware of any given machine. .\" .SH RATIONALE -.\" + An infix notation calculation utility, .BR bc (1p), is included in the POSIX standard, but does not accept expressions as arguments; @@ -67,13 +67,13 @@ UNIX v2 onward. While it implements reverse polish notation, it still suffers from being unable to accept an expression as an argument. .\" .SH AUTHOR -.\" + Written by Emma Tebibyte .MT emma@tebibyte.media .ME . .\" .SH COPYRIGHT -.\" + Copyright (c) 2024 Emma Tebibyte. License AGPLv3+: GNU AGPL version 3 or later . .\" diff --git a/docs/scrut.1 b/docs/scrut.1 index e6973ad..52d96ed 100644 --- a/docs/scrut.1 +++ b/docs/scrut.1 @@ -8,17 +8,17 @@ .SH NAME scrut \(en scrutinize file properties .SH SYNOPSIS -.\" + scrut .RB ( -bcdefgkprsuwxLS ) .RB [ file... ] .\" .SH DESCRIPTION -.\" + Determine if files comply with requirements. .\" .SH OPTIONS -.\" + .IP -L Requires the given files to exist and be symbolic links. .IP -S @@ -49,7 +49,7 @@ Requires the given files to exist and be writable. Requires the given files to exist and be executable. .\" .SH DIAGNOSTICS -.\" + If the given files comply with the specified requirements, the program will exit successfully. If not, it exits unsuccessfully. @@ -59,7 +59,7 @@ exit with the appropriate error code. .\" .SH RATIONALE -.\" + The .BR test (1p) utility contains functionality that was broken out into separate programs. Thus, @@ -71,7 +71,7 @@ alias to the modern option. .\" .SH AUTHOR -.\" + Written by DTB .MT trinity@trinity.moe .ME . @@ -80,9 +80,8 @@ Written by DTB Copyright \(co 2024 DTB. License AGPLv3+: GNU AGPL version 3 or later . - +.\" .SH SEE ALSO - .BR access (3p), .BR lstat (3p), .BR test (1p) diff --git a/docs/str.1 b/docs/str.1 index 641a75f..d40eafa 100644 --- a/docs/str.1 +++ b/docs/str.1 @@ -9,13 +9,13 @@ str \(en test the character types of string arguments .\" .SH SYNOPSIS -.\" + str .RB [ type ] .RB [ string... ] .\" .SH DESCRIPTION -.\" + Test string arguments. The tests in this program are equivalent to the functions with the same names in @@ -23,7 +23,7 @@ The tests in this program are equivalent to the functions with the same names in and are the methods by which string arguments are tested. .\" .SH DIAGNOSTICS -.\" + If all tests pass, the program will exit with an exit code of 0. If any of the tests fail, the program will exit unsuccessfully with an error code of 1. @@ -34,20 +34,20 @@ When invoked incorrectly, a debug message will be printed and the program will exit with the appropriate sysexits.h(3) error code. .\" .SH CAVEATS -.\" + There’s no way of knowing which argument failed the test without re-testing arguments individually. If a character in a string isn't valid ASCII str will exit unsuccessfully. .\" .SH AUTHOR -.\" + Written by DTB .MT trinity@trinity.moe .ME . .\" .SH COPYRIGHT -.\" + Copyright © 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later . .\" diff --git a/docs/strcmp.1 b/docs/strcmp.1 index 1cc03dd..768be0f 100644 --- a/docs/strcmp.1 +++ b/docs/strcmp.1 @@ -9,17 +9,17 @@ strcmp \(en compare strings .\" .SH SYNOPSIS -.\" + strcmp .RM [ string ] .RB [ strings... ] .\" .SH DESCRIPTION -.\" + Check whether string arguments are the same. .\" .SH DIAGNOSTICS -.\" + The program will exit successfully if the strings are identical. Otherwise, it exits with the value 1 if an earlier string has a greater byte value than a later string (e.g. strcmp b a) and 255 if an earlier string has a lesser byte @@ -31,13 +31,13 @@ exit with the appropriate error code. .\" .SH CAVEATS -.\" + The program will exit unsuccessfully if the given strings are not identical; therefore, Unicode strings may need to be normalized if the intent is to check visual similarity and not byte similarity. .\" .SH RATIONALE -.\" + The traditional tool for string comparisons in POSIX and other Unix shells has been .BR test (1). @@ -48,13 +48,13 @@ This program’s functionality may be performed on a POSIX-compliant system with .BR test (1p). .\" .SH AUTHOR -.\" + Written by DTB .MT trinity@trinity.moe .ME . .\" .SH COPYRIGHT -.\" + Copyright © 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later . .\" diff --git a/docs/swab.1 b/docs/swab.1 index 078dd54..b1a0834 100644 --- a/docs/swab.1 +++ b/docs/swab.1 @@ -9,7 +9,7 @@ swab \(en swap bytes .\" .SH SYNOPSIS -.\" + swab .RB ( -f ) .RB ( -w @@ -18,11 +18,11 @@ swab .R ]) .\" .SH USAGE -.\" + Swap the latter and former halves of a block of bytes. .\" .SH OPTIONS -.\" + .IP -f Ignore system call interruptions. .IP -w @@ -32,7 +32,7 @@ cleanly divisible by 2, otherwise the block of bytes being processed can't be halved. .\" .SH EXAMPLES -.\" + The following sh(1p) line: .RS @@ -46,12 +46,12 @@ Produces the following output: .RE .\" .SH DIAGNOSTICS -.\" + In the event of an error, a debug message will be printed and the program will exit with the appropriate sysexits.h(3) error code. .\" .SH RATIONALE -.\" + This program was modeled and named after the conv=swab functionality specified in the dd(1p) utility. It additionally allows the word size to be configured. @@ -59,7 +59,7 @@ This functionality 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 . .\" diff --git a/docs/true.1 b/docs/true.1 index 1025c21..ac2e222 100644 --- a/docs/true.1 +++ b/docs/true.1 @@ -9,25 +9,25 @@ true \(en do nothing, successfully .\" .SH DESCRIPTION -.\" + Do nothing regardless of operands or standard input. An exit code of 0 will always be returned. .\" .SH RATIONALE -.\" + In \fIPOSIX.1-2017\fP, .BR true (1p) exists for the construction of control flow and loops based on a success. This implementation functions as described in that standard. .\" .SH AUTHOR -.\" + Written by Emma Tebibyte .MT emma@tebibyte.media .ME . .\" .SH COPYRIGHT -.\" + This work is marked with CC0 1.0. To see a copy of this license, visit . .\" From e7ba74013b9cbaed29334cc540a607e95ad618b3 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 3 Jun 2024 23:21:00 -0600 Subject: [PATCH 074/343] dj.1: fixes man page reference formatting --- docs/dj.1 | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 21f0e1d..ea73a75 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -161,12 +161,15 @@ versions of lowercase options. .\" .SH RATIONALE -This program was based on the dd(1p) utility as specified in POSIX. While -character conversion may have been the original intent of dd(1p), it is -irrelevant to its modern use. Because of this, this program eschews character -conversion and adds typical option formatting, allowing seeks to be specified -in bytes rather than in blocks, allowing arbitrary bytes as padding, and -printing in a format that\(cqs easy for machines to parse. +This program was based on the +.BR dd (1p) +utility as specified in POSIX. While character conversion may have been the +original intent of +.BR dd (1p), +it is irrelevant to its modern use. Because of this, this program eschews +character conversion and adds typical option formatting, allowing seeks to be +specified in bytes rather than in blocks, allowing arbitrary bytes as padding, +and printing in a format that\(cqs easy for machines to parse. .\" .SH COPYRIGHT From beff2d98c672cf3696db6aff4b5a25d757cf7cdd Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 3 Jun 2024 23:45:26 -0600 Subject: [PATCH 075/343] mm.1: fixed manpage reference formatting --- docs/mm.1 | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/mm.1 b/docs/mm.1 index c971c00..ef0336a 100644 --- a/docs/mm.1 +++ b/docs/mm.1 @@ -46,7 +46,9 @@ writing to that particular output, and if there are more outputs specified, continues, eventually exiting unsuccessfully. When an error is encountered, diagnostic message is printed and the program -exits with the appropriate sysexits.h(3) status. +exits with the appropriate +.BR sysexits.h (3) +status. .\" .SH CAVEATS @@ -54,9 +56,13 @@ Existing files are not truncated on ouput and are instead overwritten. .\" .SH RATIONALE -The cat(1p) and tee(1p) programs specified in POSIX together provide similar -functionality. The separation of the two sets of functionality into separate -APIs seemed unncessary. +The +.BR cat (1p) +and +.BR tee (1p) +programs specified in POSIX together provide similar functionality. The +separation of the two sets of functionality into separate APIs seemed +unncessary. .\" .SH COPYRIGHT From fec61fee1b2009dd095d79be567a6a478a874519 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 3 Jun 2024 23:47:14 -0600 Subject: [PATCH 076/343] swab.1: fixes formatting --- docs/swab.1 | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/swab.1 b/docs/swab.1 index b1a0834..90b50b0 100644 --- a/docs/swab.1 +++ b/docs/swab.1 @@ -23,9 +23,9 @@ Swap the latter and former halves of a block of bytes. .\" .SH OPTIONS -.IP -f +.IP \fB-f\fP Ignore system call interruptions. -.IP -w +.IP \fB-w\fP 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 @@ -33,7 +33,9 @@ halved. .\" .SH EXAMPLES -The following sh(1p) line: +The following +.Br sh (1p) +line: .RS .R printf 'hello world!\n' | swab @@ -48,12 +50,16 @@ Produces the following output: .SH DIAGNOSTICS In the event of an error, a debug message will be printed and the program will -exit with the appropriate sysexits.h(3) error code. +exit with the appropriate +.BR sysexits.h (3) +error code. .\" .SH RATIONALE This program was modeled and named after the conv=swab functionality specified -in the dd(1p) utility. It additionally allows the word size to be configured. +in the +.BR dd (1p) +utility. It additionally allows the word size to be configured. This functionality is useful for fixing the endianness of binary files produced on other machines. From 896b251434bc544fc548bff69b63593d2b214018 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 3 Jun 2024 23:52:28 -0600 Subject: [PATCH 077/343] hru.1: fixes formatting --- docs/hru.1 | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/docs/hru.1 b/docs/hru.1 index 984222a..c3a5cdc 100644 --- a/docs/hru.1 +++ b/docs/hru.1 @@ -25,23 +25,30 @@ value is greater than one. .SH DIAGNOSTICS If encountering non-integer characters in the standard input, the program will -exit with the appropriate error code as defined by sysexits.h(3) and print an -error message. +exit with the appropriate error code as defined by +.BR sysexits.h (3) +and print an error message. .\" .SH RATIONALE -The GNU project\(cqs 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\(cqs ls(1) can be emulated with fop(1) combined with this -program. +The GNU project\(cqs +.BR ls (1) +implementation contains a human-readable option (\fB-h\fP) 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 +.BR ls (1) +so the decision was made to split it into a new tool. The original functionality +in GNU\(cqs +.BR ls (1) +can be emulated with +.BR fop (1) +combined with this program. .\" .SH STANDARDS 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) are utilized for the ouput of conversions. +et Mesures (BIPM) in the ninth edition of The International System of Units (SI) +are utilized for the ouput of conversions. .\" .SH AUTHOR From a5a9c91cb6f18159e39c87143ece06a4ceb8d7df Mon Sep 17 00:00:00 2001 From: emma Date: Tue, 4 Jun 2024 14:28:19 -0600 Subject: [PATCH 078/343] getopt.rs(3): optind support --- src/getopt.rs | 49 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/src/getopt.rs b/src/getopt.rs index b146400..79879df 100644 --- a/src/getopt.rs +++ b/src/getopt.rs @@ -18,6 +18,21 @@ use std::ffi::{ c_int, c_char, CString, CStr }; + +/* binding to getopt(3p) */ +extern "C" { + static mut optarg: *mut c_char; + static mut _opterr: c_int; + static mut optind: c_int; + static mut optopt: c_int; + + fn getopt( + ___argc: c_int, + ___argv: *const *mut c_char, + __shortopts: *const c_char, + ) -> c_int; +} + pub struct Opt { pub arg: Option, pub ind: i32, @@ -50,7 +65,7 @@ impl GetOpt for Vec { let opts = CString::new(optstring).unwrap().into_raw(); let len = self.len() as c_int; - unsafe { // TODO: enable optind modification + unsafe { match getopt(len, argv_ptr, opts) { /* From getopt(3p): * @@ -103,16 +118,24 @@ impl GetOpt for Vec { } } } -/* binding to getopt(3p) */ -extern "C" { - static mut optarg: *mut c_char; - static mut _opterr: c_int; - static mut optind: c_int; - static mut optopt: c_int; - fn getopt( - ___argc: c_int, - ___argv: *const *mut c_char, - __shortopts: *const c_char, - ) -> c_int; -} +/* From getopt(3p): + * + * The variable optind is the index of the next element of the argv[] + * vector to be processed. It shall be initialized to 1 by the system, and + * getopt() shall update it when it finishes with each element of argv[]. + * If the application sets optind to zero before calling getopt(), the + * behavior is unspecified. When an element of argv[] contains multiple + * option characters, it is unspecified how getopt() determines which + * options have already been processed. + * + * This API can be utilized using unsafe blocks and dereferencing: + * + * use getopt::OPTIND; + * + * unsafe { while *OPTIND < 5 { + * println!("{}", *OPTIND); // 1..4 + * *OPTIND += 1; + * }} + */ +pub static mut OPTIND: *mut i32 = unsafe { std::ptr::addr_of_mut!(optind) }; From b7283d54fe42fe7d6ac3899c2e6ea1fea55552f6 Mon Sep 17 00:00:00 2001 From: emma Date: Tue, 4 Jun 2024 15:07:11 -0600 Subject: [PATCH 079/343] getopt.rs(3): formatting & organization --- src/getopt.rs | 55 +++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/src/getopt.rs b/src/getopt.rs index 79879df..0324f87 100644 --- a/src/getopt.rs +++ b/src/getopt.rs @@ -18,7 +18,6 @@ use std::ffi::{ c_int, c_char, CString, CStr }; - /* binding to getopt(3p) */ extern "C" { static mut optarg: *mut c_char; @@ -33,6 +32,27 @@ extern "C" { ) -> c_int; } +/* From getopt(3p): + * + * The variable optind is the index of the next element of the argv[] + * vector to be processed. It shall be initialized to 1 by the system, and + * getopt() shall update it when it finishes with each element of argv[]. + * If the application sets optind to zero before calling getopt(), the + * behavior is unspecified. When an element of argv[] contains multiple + * option characters, it is unspecified how getopt() determines which + * options have already been processed. + * + * This API can be utilized using unsafe blocks and dereferencing: + * + * use getopt::OPTIND; + * + * unsafe { while *OPTIND < 5 { + * println!("{}", *OPTIND); // 1..4 + * *OPTIND += 1; + * }} + */ +pub static mut OPTIND: *mut i32 = unsafe { std::ptr::addr_of_mut!(optind) }; + pub struct Opt { pub arg: Option, pub ind: i32, @@ -83,12 +103,12 @@ impl GetOpt for Vec { * * Otherwise, getopt() shall return -1 when all command line * options are parsed. */ - 58 => { /* numerical ASCII value for ':' */ - Some(Err(OptError::MissingArg(optopt.to_string()))) - }, - 63 => { /* numerical ASCII value for '?' */ - Some(Err(OptError::UnknownOpt(optopt.to_string()))) - }, + 58 => { /* numerical ASCII value for ':' */ + Some(Err(OptError::MissingArg(optopt.to_string()))) + }, + 63 => { /* numerical ASCII value for '?' */ + Some(Err(OptError::UnknownOpt(optopt.to_string()))) + }, /* From getopt(3p): * * If, when getopt() is called: @@ -118,24 +138,3 @@ impl GetOpt for Vec { } } } - -/* From getopt(3p): - * - * The variable optind is the index of the next element of the argv[] - * vector to be processed. It shall be initialized to 1 by the system, and - * getopt() shall update it when it finishes with each element of argv[]. - * If the application sets optind to zero before calling getopt(), the - * behavior is unspecified. When an element of argv[] contains multiple - * option characters, it is unspecified how getopt() determines which - * options have already been processed. - * - * This API can be utilized using unsafe blocks and dereferencing: - * - * use getopt::OPTIND; - * - * unsafe { while *OPTIND < 5 { - * println!("{}", *OPTIND); // 1..4 - * *OPTIND += 1; - * }} - */ -pub static mut OPTIND: *mut i32 = unsafe { std::ptr::addr_of_mut!(optind) }; From f4cad598c467c07f2a7d3014e70093a85103eed6 Mon Sep 17 00:00:00 2001 From: emma Date: Tue, 4 Jun 2024 16:11:33 -0600 Subject: [PATCH 080/343] docs: formatting --- docs/intcmp.1 | 2 +- docs/mm.1 | 18 +++++++++--------- docs/npc.1 | 7 +++---- docs/rpn.1 | 7 ++++--- docs/scrut.1 | 30 +++++++++++++++--------------- docs/str.1 | 11 +++++++---- docs/strcmp.1 | 20 +++++++++++++++----- docs/swab.1 | 6 +++--- 8 files changed, 57 insertions(+), 44 deletions(-) diff --git a/docs/intcmp.1 b/docs/intcmp.1 index ed88038..905d31d 100644 --- a/docs/intcmp.1 +++ b/docs/intcmp.1 @@ -32,7 +32,7 @@ It may help to think of the -e, -g, and -l options as equivalent to the infix algebraic \(lq=\(rq, \(lq>\(rq, and \(lq<\(rq operators respectively, with each option putting its symbol between every given integer. The following example is equivalent to evaluating \(lq1 < 2 < 3\(rq: - +\" .RS .R intcmp -l 1 2 3 .RE diff --git a/docs/mm.1 b/docs/mm.1 index ef0336a..58bc26e 100644 --- a/docs/mm.1 +++ b/docs/mm.1 @@ -22,21 +22,21 @@ Catenate input files and write them to the start of each output file or stream. .\" .SH OPTIONS -.IP -a +.IP \fB-a\fP Opens subsequent outputs for appending rather than updating. -.IP -e +.IP \fB-e\fP Use the standard error as an output. -.IP -i +.IP \fB-i\fP Opens a path as an input. Without any inputs specified mm will use the standard input. The standard input shall be used as an input if one or more of -the input files is “-”. -.IP -o +the input files is \(lq-\(rq. +.IP \fB-o\fP Opens a path as an output. Without any outputs specified mm will use the standard output. The standard output shall be used as an output if one or more -of the output files is “-”. -.IP -u +of the output files is \(lq-\(rq. +.IP \fB-u\fP Ensures neither input or output will be buffered. -.IP -n +.IP \fB-n\fP Causes SIGINT signals to be ignored. .\" .SH DIAGNOSTICS @@ -66,7 +66,7 @@ unncessary. .\" .SH COPYRIGHT -Copyright (c) 2024 DTB. License AGPLv3+: GNU AGPL version 3 or later +Copyright \(co 2024 DTB. License AGPLv3+: GNU AGPL version 3 or later . .\" .SH SEE ALSO diff --git a/docs/npc.1 b/docs/npc.1 index 64f3406..e18e4ff 100644 --- a/docs/npc.1 +++ b/docs/npc.1 @@ -27,9 +27,9 @@ high bit set. .\" .SH USAGE -.IP -e +.IP \fB-e\fP Prints a currency sign ('$') before each line ending. -.IP -t +.IP \fB-t\fP Prints tab characters as '^I' rather than a literal horizontal tab. .\" .SH DIAGNOSTICS @@ -69,7 +69,6 @@ Copyright © 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later .\" .SH SEE ALSO .BR cat (1p), -.BR cat-v (1) - +.BR cat-v (1), .I UNIX Style, or cat -v Considered Harmful by Rob Pike diff --git a/docs/rpn.1 b/docs/rpn.1 index c791613..8e87802 100644 --- a/docs/rpn.1 +++ b/docs/rpn.1 @@ -26,7 +26,8 @@ Upon evaluation, the program will print the resulting number on the stack to the standard output. Any further specified numbers will be placed at the end of the stack. -For information on for reverse polish notation syntax, see rpn(7). +For information on for reverse polish notation syntax, see +.BR rpn (7). .\" .SH STANDARD INPUT @@ -40,7 +41,7 @@ In the event of a syntax error, the program will print an In the event of an error, a debug message will be printed and the program will exit with the appropriate -.BR sysexits.h(3) +.BR sysexits.h (3) error code. .\" .SH CAVEATS @@ -80,5 +81,5 @@ Copyright (c) 2024 Emma Tebibyte. License AGPLv3+: GNU AGPL version 3 or later .SH SEE ALSO .BR bc (1p), .BR dc (1), -.BR rpn(7), +.BR rpn (7), .I IEEE 754 diff --git a/docs/scrut.1 b/docs/scrut.1 index 52d96ed..22c77fb 100644 --- a/docs/scrut.1 +++ b/docs/scrut.1 @@ -10,7 +10,7 @@ scrut \(en scrutinize file properties .SH SYNOPSIS scrut -.RB ( -bcdefgkprsuwxLS ) +.RB ( -LSbcdefgkprsuwx ) .RB [ file... ] .\" .SH DESCRIPTION @@ -19,33 +19,33 @@ Determine if files comply with requirements. .\" .SH OPTIONS -.IP -L +.IP \fB-L\fB Requires the given files to exist and be symbolic links. -.IP -S +.IP \fB-S\fP Requires the given files to exist and be sockets. -.IP -b +.IP \fB-b\fP Requires the given files to exist and be block special files. -.IP -c +.IP \fB-c\fP Requires the given files to exist and be character special files. -.IP -d +.IP \fB-d\fP Requires the given files to exist and be directories. -.IP -e +.IP \fB-e\fP Requires the given files to exist, and is redundant to any other option. -.IP -e +.IP \fB-f\fP Requires the given files to exist and be regular files. -.IP -g +.IP \fB-g\fP Requires the given files to exist and have their set group ID flags set. -.IP -k +.IP \fB-k\fP Requires the given files to exist and have their sticky bit set. -.IP -p +.IP \fB-p\fP Requires the given files to exist and be named pipes. -.IP -r +.IP \fB-r\fP Requires the given files to exist and be readable. -.IP -u +.IP \fB-u\fP Requires the given files to exist and have their set user ID flags set. -.IP -w +.IP \fB-w\fP Requires the given files to exist and be writable. -.IP -x +.IP \fB-x\fP Requires the given files to exist and be executable. .\" .SH DIAGNOSTICS diff --git a/docs/str.1 b/docs/str.1 index d40eafa..87caabb 100644 --- a/docs/str.1 +++ b/docs/str.1 @@ -31,14 +31,17 @@ An empty string will cause an unsuccessful exit as none of its contents pass any tests. When invoked incorrectly, a debug message will be printed and the program will -exit with the appropriate sysexits.h(3) error code. +exit with the appropriate +.BR sysexits.h (3) +error code. .\" .SH CAVEATS -There’s no way of knowing which argument failed the test without re-testing +There\(cqs no way of knowing which argument failed the test without re-testing arguments individually. -If a character in a string isn't valid ASCII str will exit unsuccessfully. +If a character in a string isn\(cqt valid ASCII the program will exit +unsuccessfully. .\" .SH AUTHOR @@ -48,7 +51,7 @@ Written by DTB .\" .SH COPYRIGHT -Copyright © 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later +Copyright \(co 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later . .\" .SH SEE ALSO diff --git a/docs/strcmp.1 b/docs/strcmp.1 index 768be0f..84b661d 100644 --- a/docs/strcmp.1 +++ b/docs/strcmp.1 @@ -21,9 +21,19 @@ Check whether string arguments are the same. .SH DIAGNOSTICS The program will exit successfully if the strings are identical. Otherwise, it -exits with the value 1 if an earlier string has a greater byte value than a -later string (e.g. strcmp b a) and 255 if an earlier string has a lesser byte -value (e.g. strcmp a b). +will exit with an error code of 1 if a string passed has a lesser byte value +than one of the prior strings: + +.RS +.R strcmp b a +.RE + +and with an error code of 255 if it has a greater byte value than one of the +prior strings: + +.RS +.R strcmp a b +.RE When invoked incorrectly, a debug message will be printed and the program will exit with the appropriate @@ -44,7 +54,7 @@ been This tool also handles integer comparisons and file scrutiny. These parts of its functionality have been broken out into multiple utilities. -This program’s functionality may be performed on a POSIX-compliant system with +This program\(cqs functionality may be performed on a POSIX-compliant system with .BR test (1p). .\" .SH AUTHOR @@ -55,7 +65,7 @@ Written by DTB .\" .SH COPYRIGHT -Copyright © 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later +Copyright \(co 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later . .\" .SH SEE ALSO diff --git a/docs/swab.1 b/docs/swab.1 index 90b50b0..7197a0a 100644 --- a/docs/swab.1 +++ b/docs/swab.1 @@ -17,7 +17,7 @@ swab .B word size .R ]) .\" -.SH USAGE +.SH DESCRIPTION Swap the latter and former halves of a block of bytes. .\" @@ -28,7 +28,7 @@ Ignore system call interruptions. .IP \fB-w\fP 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 +cleanly divisible by 2, otherwise the block of bytes being processed can\(cqt be halved. .\" .SH EXAMPLES @@ -66,7 +66,7 @@ on other machines. .\" .SH COPYRIGHT -Copyright (c) 2024 DTB. License AGPLv3+: GNU AGPL version 3 or later +Copyright \(co 2024 DTB. License AGPLv3+: GNU AGPL version 3 or later . .\" .SH SEE ALSO From 46c4be5c591f189598bbaaa23d8fc73947e4befd Mon Sep 17 00:00:00 2001 From: emma Date: Tue, 4 Jun 2024 16:21:25 -0600 Subject: [PATCH 081/343] CONDUCT: no llm contributions --- CONDUCT | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/CONDUCT b/CONDUCT index 0585d15..4a26e37 100644 --- a/CONDUCT +++ b/CONDUCT @@ -11,9 +11,11 @@ General Public License, version 3 or later, or a compatible license. 2. Ethics (Sīla) -Do not use nonfree code or uncredited code in contributions. Do not take credit -for others’ contributions. Make sure to utilize the copyright header and license -notice on source files to credit yourself and others for their work. +Do not use nonfree code or uncredited code in contributions. Do not contribute +code of dubious origins, such as code generated in large part by large language +models [1]. Do not take credit for others’ contributions. Make sure to utilize +the copyright header and license notice on source files to credit yourself and +others for their work. 3. Renunciation (Nekkhamma) @@ -78,3 +80,4 @@ not shameful to make a mistake in this vein, and fixing it usually leads to more insight. [0] +[1] From 35ddc729fdc78334ab3656094ca0c6b81f32ca2d Mon Sep 17 00:00:00 2001 From: emma Date: Tue, 4 Jun 2024 19:15:22 -0600 Subject: [PATCH 082/343] getopt.rs(3): makes optind part of the Opt struct --- src/getopt.rs | 42 ++++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/src/getopt.rs b/src/getopt.rs index 0324f87..62696e0 100644 --- a/src/getopt.rs +++ b/src/getopt.rs @@ -32,30 +32,9 @@ extern "C" { ) -> c_int; } -/* From getopt(3p): - * - * The variable optind is the index of the next element of the argv[] - * vector to be processed. It shall be initialized to 1 by the system, and - * getopt() shall update it when it finishes with each element of argv[]. - * If the application sets optind to zero before calling getopt(), the - * behavior is unspecified. When an element of argv[] contains multiple - * option characters, it is unspecified how getopt() determines which - * options have already been processed. - * - * This API can be utilized using unsafe blocks and dereferencing: - * - * use getopt::OPTIND; - * - * unsafe { while *OPTIND < 5 { - * println!("{}", *OPTIND); // 1..4 - * *OPTIND += 1; - * }} - */ -pub static mut OPTIND: *mut i32 = unsafe { std::ptr::addr_of_mut!(optind) }; - pub struct Opt { pub arg: Option, - pub ind: i32, + pub ind: *mut i32, pub opt: String, } @@ -89,7 +68,7 @@ impl GetOpt for Vec { match getopt(len, argv_ptr, opts) { /* From getopt(3p): * - * The getopt() function shall return the next option character + * The getopt() f unction shall return the next option character * specified on the command line. * * A (':') shall be returned if getopt() detects a @@ -130,7 +109,22 @@ impl GetOpt for Vec { Some(Ok(Opt { arg: Some(arg), /* opt argument */ - ind: optind, /* opt index */ + /* From getopt(3p): + * + * The variable optind is the index of the next element + * of the argv[] vector to be processed. It shall be + * initialized to 1 by the system, and getopt() shall + * update it when it finishes with each element of + * argv[]. If the application sets optind to zero + * before calling getopt(), the behavior is unspecified. + * When an element of argv[] contains multiple option + * characters, it is unspecified how getopt() + * determines which options have already been processed. + * + * This API is unsafe and can be utilized by + * dereferencing the ind field before reading to and + * writing from the optind memory. */ + ind: std::ptr::addr_of_mut!(optind), opt: opt.to_string(), /* option itself */ })) }, From 05cde15105239a1fc960c2563826dc367e11bd0b Mon Sep 17 00:00:00 2001 From: emma Date: Tue, 4 Jun 2024 19:15:55 -0600 Subject: [PATCH 083/343] fop(1): updated to use new optind api --- src/fop.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fop.rs b/src/fop.rs index a56a0a6..8ffb447 100644 --- a/src/fop.rs +++ b/src/fop.rs @@ -50,7 +50,7 @@ fn main() { eprintln!("{}: {}: Not a character.", argv[0], arg); exit(EX_USAGE); } else { d = arg_char[0]; } - index_arg = o.ind as usize; + unsafe { index_arg = *o.ind as usize; } }, Err(_) => { eprintln!("{}", usage); From e862b7fec6a1fa12222ce298b4df8c9cdbee7d89 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 5 Jun 2024 11:54:55 -0600 Subject: [PATCH 084/343] getopt.rs(3): safe api around optind reading and setting --- src/getopt.rs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/getopt.rs b/src/getopt.rs index 62696e0..dca53e0 100644 --- a/src/getopt.rs +++ b/src/getopt.rs @@ -34,10 +34,16 @@ extern "C" { pub struct Opt { pub arg: Option, - pub ind: *mut i32, + ind: *mut i32, pub opt: String, } +impl Opt { + pub fn index(&self) -> usize { unsafe { *self.ind as usize } } + + pub fn set_index(&self, ind: i32) { unsafe { *self.ind = ind; } } +} + pub enum OptError { MissingArg(String), UnknownOpt(String), @@ -82,12 +88,12 @@ impl GetOpt for Vec { * * Otherwise, getopt() shall return -1 when all command line * options are parsed. */ - 58 => { /* numerical ASCII value for ':' */ - Some(Err(OptError::MissingArg(optopt.to_string()))) - }, - 63 => { /* numerical ASCII value for '?' */ - Some(Err(OptError::UnknownOpt(optopt.to_string()))) - }, + 58 => { /* numerical ASCII value for ':' */ + Some(Err(OptError::MissingArg(optopt.to_string()))) + }, + 63 => { /* numerical ASCII value for '?' */ + Some(Err(OptError::UnknownOpt(optopt.to_string()))) + }, /* From getopt(3p): * * If, when getopt() is called: @@ -121,9 +127,8 @@ impl GetOpt for Vec { * characters, it is unspecified how getopt() * determines which options have already been processed. * - * This API is unsafe and can be utilized by - * dereferencing the ind field before reading to and - * writing from the optind memory. */ + * This API is can be utilized with the index() and + * set_index() methods implemented for Opt. */ ind: std::ptr::addr_of_mut!(optind), opt: opt.to_string(), /* option itself */ })) From 02daca87dcd3a098d0c85b5021949a8e731d2947 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 5 Jun 2024 11:55:16 -0600 Subject: [PATCH 085/343] fop(1): updated to latest optind api --- src/fop.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fop.rs b/src/fop.rs index 8ffb447..e0bba4c 100644 --- a/src/fop.rs +++ b/src/fop.rs @@ -44,13 +44,13 @@ fn main() { Ok(o) => { /* unwrap because Err(OptError::MissingArg) will be returned if * o.arg is None */ - let arg = o.arg.unwrap(); + let arg = o.arg.clone().unwrap(); let arg_char = arg.chars().collect::>(); if arg_char.len() > 1 { eprintln!("{}: {}: Not a character.", argv[0], arg); exit(EX_USAGE); } else { d = arg_char[0]; } - unsafe { index_arg = *o.ind as usize; } + index_arg = o.index(); }, Err(_) => { eprintln!("{}", usage); From 3c0725f137a6089b549ae928dbd37c41eb336fbe Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 5 Jun 2024 17:15:42 -0600 Subject: [PATCH 086/343] dj.1: adds DESCRIPTION and removes seek/skip confusion --- docs/dj.1 | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/dj.1 b/docs/dj.1 index ea73a75..d4c5053 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -43,6 +43,17 @@ dj .B output offset .R ]) .\" +.SH DESCRIPTION + +Perform precise read and write operations on files. This utility is useful for +reading and writing binary data to and from disks, hence the name. + +This manual page uses the terms \(lqskip\(rq and \(lqseek\(rq to refer to moving +to a specified byte by index in the input and output of the program +respectively. This language is inherited from the +.BR dd (1p) +utility and is used here to decrease ambiguity. +.\" .SH OPTIONS .IP \fB-i\fP @@ -61,7 +72,7 @@ Does the same as .B -b but for the output buffer. .IP \fB-S\fP -Skips a number of bytes through the output before starting to write from +Seeks a number of bytes through the output before starting to write from the input. If the output is a stream, null characters are printed. .IP \fB-a\fP Accepts a single literal byte with which input buffer is padded in the event @@ -86,6 +97,7 @@ Retries failed reads once more before exiting. .IP \fB-q\fP Suppresses error messages which print when a read or write is partial or empty. Each invocation decrements the debug level of the program. +.\" .SH STANDARD INPUT The standard input shall be used as an input if no inputs are specified or if From 11b1b424a022d8a86abdc74e21720e98cb55d520 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 5 Jun 2024 17:18:21 -0600 Subject: [PATCH 087/343] dj.1: more clarification --- docs/dj.1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/dj.1 b/docs/dj.1 index d4c5053..67d294d 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -53,6 +53,9 @@ to a specified byte by index in the input and output of the program respectively. This language is inherited from the .BR dd (1p) utility and is used here to decrease ambiguity. + +When seeking or skipping to a byte, writing or reading starts at the byte +immediately subsequent to the specified byte. .\" .SH OPTIONS From 3392d64e440b8911a51bfead6c73fb5c4fe3f452 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 5 Jun 2024 17:25:22 -0600 Subject: [PATCH 088/343] fop(1): literal record separator --- src/fop.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fop.rs b/src/fop.rs index d28a7b0..1cc8152 100644 --- a/src/fop.rs +++ b/src/fop.rs @@ -32,7 +32,7 @@ use sysexits::{ EX_DATAERR, EX_IOERR, EX_UNAVAILABLE, EX_USAGE }; fn main() { let argv = args().collect::>(); - let mut d = "␞".to_owned(); + let mut d = 0x1E.to_string(); let mut arg_parser = Parser::new(&argv, "d:"); while let Some(opt) = arg_parser.next() { From 516d10e21d37bc94f63e67c0ec930fd374d61e22 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 5 Jun 2024 17:27:13 -0600 Subject: [PATCH 089/343] CONDUCT: wording --- CONDUCT | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CONDUCT b/CONDUCT index 4a26e37..4dd97a9 100644 --- a/CONDUCT +++ b/CONDUCT @@ -12,10 +12,10 @@ General Public License, version 3 or later, or a compatible license. 2. Ethics (Sīla) Do not use nonfree code or uncredited code in contributions. Do not contribute -code of dubious origins, such as code generated in large part by large language -models [1]. Do not take credit for others’ contributions. Make sure to utilize -the copyright header and license notice on source files to credit yourself and -others for their work. +code of dubious origins, such as code generated by large language models or +unlicensed snippets found online [1]. Do not take credit for others’ +contributions. Make sure to utilize the copyright header and license notice on +source files to credit yourself and others for their work. 3. Renunciation (Nekkhamma) From ad6f9d565baf1999675fcbfcfa9fd34a5cca1030 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 5 Jun 2024 20:39:37 -0600 Subject: [PATCH 090/343] dj.1: formats sysexits.h(3) reference --- docs/dj.1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/dj.1 b/docs/dj.1 index 67d294d..f5dbe18 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -151,7 +151,8 @@ as the only argument: In non-recoverable errors that don\(cqt pertain to the read-write cycle, a diagnostic message is printed and the program exits with the appropriate -sysexits.h(3) status. +.BR sysexits.h (3) +status. .\" .SH BUGS From 526185c2c3e9900a03a1c591665fbb05f2664bc8 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 5 Jun 2024 22:35:50 -0600 Subject: [PATCH 091/343] swab.1: typo --- docs/swab.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/swab.1 b/docs/swab.1 index 7197a0a..b1d27fc 100644 --- a/docs/swab.1 +++ b/docs/swab.1 @@ -34,7 +34,7 @@ halved. .SH EXAMPLES The following -.Br sh (1p) +.BR sh (1p) line: .RS From 8ce7890124307220a2ef9edd7057461c50ee5ad8 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 5 Jun 2024 23:07:15 -0600 Subject: [PATCH 092/343] fop.1: removes Unicode representation of RS; hru.1: removes erroneous line break; mm.1: formatting & grammar; npc.1: dollar sign, not currency sign; rpn.1: syntax error; scrut.1: move description to DESCRIPTION; str.1: comma; swab.1: wording & escape codes; true.1: formatting --- docs/fop.1 | 3 ++- docs/hru.1 | 4 ++-- docs/mm.1 | 17 +++++++---------- docs/npc.1 | 2 +- docs/rpn.1 | 5 ++--- docs/scrut.1 | 7 +++---- docs/str.1 | 2 +- docs/swab.1 | 4 ++-- docs/true.1 | 4 ++-- 9 files changed, 22 insertions(+), 26 deletions(-) diff --git a/docs/fop.1 b/docs/fop.1 index 29ba7ea..295d9ff 100644 --- a/docs/fop.1 +++ b/docs/fop.1 @@ -24,7 +24,8 @@ Performs operations on specified fields in input data. .IP \fB-d\fP Sets a delimiter by which the input data will be split into fields. The default -is an ASCII record separator (␞). +is an ASCII record separator. +.\" .SH STANDARD INPUT Data will be read from the standard input. diff --git a/docs/hru.1 b/docs/hru.1 index c3a5cdc..8b898f8 100644 --- a/docs/hru.1 +++ b/docs/hru.1 @@ -34,8 +34,8 @@ and print an error message. The GNU project\(cqs .BR ls (1) implementation contains a human-readable option (\fB-h\fP) 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 +makes the tool print size information in a format more immediately +readable. This functionality is useful not only in the context of .BR ls (1) so the decision was made to split it into a new tool. The original functionality in GNU\(cqs diff --git a/docs/mm.1 b/docs/mm.1 index 58bc26e..812aef7 100644 --- a/docs/mm.1 +++ b/docs/mm.1 @@ -27,13 +27,11 @@ Opens subsequent outputs for appending rather than updating. .IP \fB-e\fP Use the standard error as an output. .IP \fB-i\fP -Opens a path as an input. Without any inputs specified mm will use the -standard input. The standard input shall be used as an input if one or more of -the input files is \(lq-\(rq. +Opens a path as an input. If one or more of the input files is \(lq-\(rq or if +no inputs are specified, the standard input shall be used. .IP \fB-o\fP -Opens a path as an output. Without any outputs specified mm will use the -standard output. The standard output shall be used as an output if one or more -of the output files is \(lq-\(rq. +Opens a path as an output. If one or more of the output files is \(lq-\(rq or if +no outputs are specified, the standard output shall be used. .IP \fB-u\fP Ensures neither input or output will be buffered. .IP \fB-n\fP @@ -41,11 +39,10 @@ Causes SIGINT signals to be ignored. .\" .SH DIAGNOSTICS -If an output can no longer be written mm prints a diagnostic message, ceases -writing to that particular output, and if there are more outputs specified, -continues, eventually exiting unsuccessfully. +If an output cannot be written to, an error occurs. Additional outputs are not +affected and writing to them continues. -When an error is encountered, diagnostic message is printed and the program +When an error is encountered, a diagnostic message is printed and the program exits with the appropriate .BR sysexits.h (3) status. diff --git a/docs/npc.1 b/docs/npc.1 index e18e4ff..27926ee 100644 --- a/docs/npc.1 +++ b/docs/npc.1 @@ -28,7 +28,7 @@ high bit set. .SH USAGE .IP \fB-e\fP -Prints a currency sign ('$') before each line ending. +Prints a dollar sign ('$') before each line ending. .IP \fB-t\fP Prints tab characters as '^I' rather than a literal horizontal tab. .\" diff --git a/docs/rpn.1 b/docs/rpn.1 index 8e87802..8a3b0fe 100644 --- a/docs/rpn.1 +++ b/docs/rpn.1 @@ -37,12 +37,11 @@ the standard input. .\" .SH DIAGNOSTICS -In the event of a syntax error, the program will print an - In the event of an error, a debug message will be printed and the program will exit with the appropriate .BR sysexits.h (3) -error code. +error code; however, in the event of a syntax error, the program will print an +error message and continue accepting input. .\" .SH CAVEATS diff --git a/docs/scrut.1 b/docs/scrut.1 index 22c77fb..2cb687c 100644 --- a/docs/scrut.1 +++ b/docs/scrut.1 @@ -15,7 +15,9 @@ scrut .\" .SH DESCRIPTION -Determine if files comply with requirements. +Determine if files comply with requirements. If the given files comply with the +specified requirements, the program will exit successfully. Otherwise, it exits +unsuccessfully. .\" .SH OPTIONS @@ -50,9 +52,6 @@ Requires the given files to exist and be executable. .\" .SH DIAGNOSTICS -If the given files comply with the specified requirements, the program will exit -successfully. If not, it exits unsuccessfully. - When invoked incorrectly, a debug message will be printed and the program will exit with the appropriate .BR sysexits.h (3) diff --git a/docs/str.1 b/docs/str.1 index 87caabb..66565b9 100644 --- a/docs/str.1 +++ b/docs/str.1 @@ -40,7 +40,7 @@ error code. There\(cqs no way of knowing which argument failed the test without re-testing arguments individually. -If a character in a string isn\(cqt valid ASCII the program will exit +If a character in a string isn\(cqt valid ASCII, the program will exit unsuccessfully. .\" .SH AUTHOR diff --git a/docs/swab.1 b/docs/swab.1 index b1d27fc..64aed1a 100644 --- a/docs/swab.1 +++ b/docs/swab.1 @@ -27,7 +27,7 @@ Swap the latter and former halves of a block of bytes. Ignore system call interruptions. .IP \fB-w\fP 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 +on which to operate. The default word size is 2. The word size must be cleanly divisible by 2, otherwise the block of bytes being processed can\(cqt be halved. .\" @@ -38,7 +38,7 @@ The following line: .RS -.R printf 'hello world!\n' | swab +.R printf 'hello world!\(rsn' | swab .RE Produces the following output: diff --git a/docs/true.1 b/docs/true.1 index ac2e222..ecf4c8e 100644 --- a/docs/true.1 +++ b/docs/true.1 @@ -10,8 +10,8 @@ true \(en do nothing, successfully .\" .SH DESCRIPTION -Do nothing regardless of operands or standard input. -An exit code of 0 will always be returned. +Do nothing regardless of operands or standard input. An exit code of 0 will +always be returned. .\" .SH RATIONALE From 4d27a4976c51126cd15058a415cfab3e62aff555 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 5 Jun 2024 23:17:21 -0600 Subject: [PATCH 093/343] swab.1: -f Ignores the SIGINT signal --- docs/swab.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/swab.1 b/docs/swab.1 index 64aed1a..0ca19e8 100644 --- a/docs/swab.1 +++ b/docs/swab.1 @@ -24,7 +24,7 @@ Swap the latter and former halves of a block of bytes. .SH OPTIONS .IP \fB-f\fP -Ignore system call interruptions. +Ignore SIGINT signal. .IP \fB-w\fP Configures the word size; that is, the size in bytes of the block size on which to operate. The default word size is 2. The word size must be From 51421b2128ba93502dec3ccb19b01772ac7c2226 Mon Sep 17 00:00:00 2001 From: emma Date: Thu, 6 Jun 2024 00:14:55 -0600 Subject: [PATCH 094/343] dj.1, strcmp.1, swab.1: remove nonexistent roff macros --- docs/dj.1 | 44 ++++++++++++++++---------------------------- docs/strcmp.1 | 4 ++-- docs/swab.1 | 4 ++-- 3 files changed, 20 insertions(+), 32 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index f5dbe18..f2570ae 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -18,30 +18,18 @@ dj .RB [ count ]) .RB ( -i -.R [ -.B input file -.R ]) +[\fBinput file\fP]) .RB ( -b -.R [ -.B input block size -.R ]) +[\fBinput block size\fP]) .RB ( -s -.R [ -.B input offset -.R ]) +[\fBinput offset\fP]) .RB ( -o -.R [ -.B output file -.R ]) +[\fBoutput file\fP]) .RB ( -B -.R [ -.B output block size -.R ]) +[\fBoutput block size\fP]) .RB ( -S -.R [ -.B output offset -.R ]) +[\fBoutput offset\fP]) .\" .SH DESCRIPTION @@ -118,10 +106,10 @@ By default, statistics are printed for input and output to the standard error in the following format: .RS -.R {records read} {ASCII unit separator} {partial records read} -.R {ASCII record separator} {records written} {ASCII unit separator} -.R {partial records written} {ASCII group separator} {bytes read} -.R {ASCII record separator} {bytes written} {ASCII file separator} +{records read} {ASCII unit separator} {partial records read} +{ASCII record separator} {records written} {ASCII unit separator} +{partial records written} {ASCII group separator} {bytes read} +{ASCII record separator} {bytes written} {ASCII file separator} .RE This format for diagnostic output is designed to be machine-parseable for @@ -130,9 +118,9 @@ convenience. For a more human-readable format, the option may be specified. In this event, the following format is used instead: .RS -.R {records read} '+' {partial records read} '>' {records written} -.R '+' {partial records written} ';' {bytes read} '>' {bytes written} -.R {ASCII line feed} +{records read} '+' {partial records read} '>' {records written} +'+' {partial records written} ';' {bytes read} '>' {bytes written} +{ASCII line feed} .RE If the @@ -144,9 +132,9 @@ was invoked. The following example is the result of running the program with as the only argument: .RS -.R argv0=dj -.R in= ibs=1024 skip=0 align=ff count=0 -.R out= obs=1024 seek=0 debug= 3 noerror=0 +argv0=dj +in= ibs=1024 skip=0 align=ff count=0 +out= obs=1024 seek=0 debug= 3 noerror=0 .RE In non-recoverable errors that don\(cqt pertain to the read-write cycle, a diff --git a/docs/strcmp.1 b/docs/strcmp.1 index 84b661d..46eccdf 100644 --- a/docs/strcmp.1 +++ b/docs/strcmp.1 @@ -25,14 +25,14 @@ will exit with an error code of 1 if a string passed has a lesser byte value than one of the prior strings: .RS -.R strcmp b a +strcmp b a .RE and with an error code of 255 if it has a greater byte value than one of the prior strings: .RS -.R strcmp a b +strcmp a b .RE When invoked incorrectly, a debug message will be printed and the program will diff --git a/docs/swab.1 b/docs/swab.1 index 0ca19e8..526b057 100644 --- a/docs/swab.1 +++ b/docs/swab.1 @@ -38,13 +38,13 @@ The following line: .RS -.R printf 'hello world!\(rsn' | swab +printf 'hello world!\(rsn' | swab .RE Produces the following output: .RS -.R ehll oowlr!d +ehll oowlr!d .RE .\" .SH DIAGNOSTICS From 40da8135f189db009dfb24bbc1c3ccc7e2879ed1 Mon Sep 17 00:00:00 2001 From: emma Date: Thu, 6 Jun 2024 01:03:01 -0600 Subject: [PATCH 095/343] getopt.rs(3): relicense to AGPLv3 --- COPYING.GPL | 674 ------------------------------------------------- COPYING.LESSER | 165 ------------ src/getopt.rs | 10 +- 3 files changed, 5 insertions(+), 844 deletions(-) delete mode 100644 COPYING.GPL delete mode 100644 COPYING.LESSER diff --git a/COPYING.GPL b/COPYING.GPL deleted file mode 100644 index f288702..0000000 --- a/COPYING.GPL +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/COPYING.LESSER b/COPYING.LESSER deleted file mode 100644 index 0a04128..0000000 --- a/COPYING.LESSER +++ /dev/null @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/src/getopt.rs b/src/getopt.rs index dca53e0..5ce094c 100644 --- a/src/getopt.rs +++ b/src/getopt.rs @@ -1,18 +1,18 @@ /* - * Copyright (c) 2024 Emma Tebibyte - * SPDX-License-Identifier: LGPL-3.0-or-later + * Copyright (c) 2023–2024 Emma Tebibyte + * 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 Lesser General Public License as published by the Free + * 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 Lesser General Public License for more + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more * details. * - * You should have received a copy of the GNU Lesser General Public License + * 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/. */ From 314254b32f2cd508724f55a2310ff076e26493ba Mon Sep 17 00:00:00 2001 From: emma Date: Thu, 6 Jun 2024 13:32:54 -0600 Subject: [PATCH 096/343] docs: hotfix --- docs/dj.1 | 2 +- docs/false.1 | 2 +- docs/fop.1 | 2 +- docs/hru.1 | 2 +- docs/intcmp.1 | 2 +- docs/mm.1 | 2 +- docs/npc.1 | 2 +- docs/rpn.1 | 2 +- docs/scrut.1 | 2 +- docs/str.1 | 2 +- docs/strcmp.1 | 2 +- docs/swab.1 | 2 +- docs/true.1 | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index f2570ae..1572991 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH DJ 1 +.TH DJ 1 2024-06-06 "Bonsai Core Utilites 0.13.8" .SH NAME dj \(en disk jockey .\" diff --git a/docs/false.1 b/docs/false.1 index 91bd286..1dec3ce 100644 --- a/docs/false.1 +++ b/docs/false.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH FALSE 1 +.TH FALSE 1 2024-06-06 "Bonsai Core Utilites 0.13.8" .SH NAME false \(en do nothing, unsuccessfully .\" diff --git a/docs/fop.1 b/docs/fop.1 index 295d9ff..fe1a3c5 100644 --- a/docs/fop.1 +++ b/docs/fop.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH fop 1 +.TH FOP 1 2024-06-06 "Bonsai Core Utilites 0.13.8" .SH NAME fop \(en field operator .\" diff --git a/docs/hru.1 b/docs/hru.1 index 8b898f8..b24671e 100644 --- a/docs/hru.1 +++ b/docs/hru.1 @@ -3,7 +3,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH HRU 1 +.TH HRU 1 2024-06-06 "Bonsai Core Utilites 0.13.8" .SH NAME hru \(en human readable units .\" diff --git a/docs/intcmp.1 b/docs/intcmp.1 index 905d31d..94e88a4 100644 --- a/docs/intcmp.1 +++ b/docs/intcmp.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH INTCMP 1 +.TH INTCMP 1 2024-06-06 "Bonsai Core Utilites 0.13.8" .SH NAME intcmp \(en compare integers .\" diff --git a/docs/mm.1 b/docs/mm.1 index 812aef7..2585cab 100644 --- a/docs/mm.1 +++ b/docs/mm.1 @@ -3,7 +3,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH mm 1 +.TH MM 1 2024-06-06 "Bonsai Core Utilites 0.13.8" .SH NAME mm \(en middleman .\" diff --git a/docs/npc.1 b/docs/npc.1 index 27926ee..a2c4fd8 100644 --- a/docs/npc.1 +++ b/docs/npc.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH NPC 1 +.TH NPC 1 2024-06-06 "Bonsai Core Utilites 0.13.8" .SH NAME npc \(en show non-printing characters .\" diff --git a/docs/rpn.1 b/docs/rpn.1 index 8a3b0fe..507789d 100644 --- a/docs/rpn.1 +++ b/docs/rpn.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH rpn 1 +.TH RPN 1 2024-06-06 "Bonsai Core Utilites 0.13.8" .SH NAME rpn \(en reverse polish notation evaluation .\" diff --git a/docs/scrut.1 b/docs/scrut.1 index 2cb687c..636c5d3 100644 --- a/docs/scrut.1 +++ b/docs/scrut.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH scrut 1 +.TH SCRUT 1 2024-06-06 "Bonsai Core Utilites 0.13.8" .SH NAME scrut \(en scrutinize file properties .SH SYNOPSIS diff --git a/docs/str.1 b/docs/str.1 index 66565b9..c3f7538 100644 --- a/docs/str.1 +++ b/docs/str.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH STR 1 +.TH STR 1 2024-06-06 "Bonsai Core Utilites 0.13.8" .SH NAME str \(en test the character types of string arguments .\" diff --git a/docs/strcmp.1 b/docs/strcmp.1 index 46eccdf..facfdeb 100644 --- a/docs/strcmp.1 +++ b/docs/strcmp.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH STRCMP 1 +.TH STRCMP 1 2024-06-06 "Bonsai Core Utilites 0.13.8" .SH NAME strcmp \(en compare strings .\" diff --git a/docs/swab.1 b/docs/swab.1 index 526b057..a3af1ad 100644 --- a/docs/swab.1 +++ b/docs/swab.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH SWAB 1 +.TH SWAB 1 2024-06-06 "Bonsai Core Utilites 0.13.8" .SH NAME swab \(en swap bytes .\" diff --git a/docs/true.1 b/docs/true.1 index ecf4c8e..2e8d5eb 100644 --- a/docs/true.1 +++ b/docs/true.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH TRUE 1 +.TH TRUE 1 2024-06-06 "Bonsai Core Utilites 0.13.8" .SH NAME true \(en do nothing, successfully .\" From 5cfccf75af614ca5838cfa5b889895a89fadccc3 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 7 Jun 2024 23:30:13 -0600 Subject: [PATCH 097/343] tests: bonsai/test_env: set -e; tests: strcmp: -h causes error --- tests/bonsai/strcmp.sh | 2 +- tests/bonsai/test_env | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/bonsai/strcmp.sh b/tests/bonsai/strcmp.sh index 018cee2..9d9024e 100755 --- a/tests/bonsai/strcmp.sh +++ b/tests/bonsai/strcmp.sh @@ -12,5 +12,5 @@ strcmp equals equals ! strcmp inequals equals strcmp - - -strcmp -h +! strcmp -h ! strcmp nocmp diff --git a/tests/bonsai/test_env b/tests/bonsai/test_env index a3d07ca..aaf2b50 100644 --- a/tests/bonsai/test_env +++ b/tests/bonsai/test_env @@ -1,5 +1,5 @@ #!/bin/sh -set -x +set -ex alias "$UTIL=$BIN/$UTIL" From 376feb9ae9a884c0f3655902c1027cebdf5b6203 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 17 Jun 2024 22:52:58 -0600 Subject: [PATCH 098/343] npc.1: fixes minor details --- docs/npc.1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/npc.1 b/docs/npc.1 index a2c4fd8..a0e503e 100644 --- a/docs/npc.1 +++ b/docs/npc.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH NPC 1 2024-06-06 "Bonsai Core Utilites 0.13.8" +.TH NPC 1 2024-06-17 "Bonsai Core Utilites 0.13.8" .SH NAME npc \(en show non-printing characters .\" @@ -25,10 +25,10 @@ becomes '^?'. Characters with the high bit set (>127) are printed as 'M-' followed by the graphical representation for the same character without the high bit set. .\" -.SH USAGE +.SH OPTIONS .IP \fB-e\fP -Prints a dollar sign ('$') before each line ending. +Prints a dollar sign ('$') before each newline. .IP \fB-t\fP Prints tab characters as '^I' rather than a literal horizontal tab. .\" @@ -52,8 +52,8 @@ the .B -v option, is the bandage solution GNU and other software suites use. -This functionality is a separate tool because its usefulness extends beyond that -of +This functionality is included in a separate tool because its usefulness extends +beyond that of .BR cat (1p). .\" .SH AUTHOR From 15d5761cd7f9919700cbd893f7f1d18d18bc4223 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 17 Jun 2024 22:57:08 -0600 Subject: [PATCH 099/343] mm.1: fixes clunky sentence --- docs/mm.1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/mm.1 b/docs/mm.1 index 2585cab..1fe64ba 100644 --- a/docs/mm.1 +++ b/docs/mm.1 @@ -3,7 +3,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH MM 1 2024-06-06 "Bonsai Core Utilites 0.13.8" +.TH MM 1 2024-06-17 "Bonsai Core Utilites 0.13.8" .SH NAME mm \(en middleman .\" @@ -39,8 +39,8 @@ Causes SIGINT signals to be ignored. .\" .SH DIAGNOSTICS -If an output cannot be written to, an error occurs. Additional outputs are not -affected and writing to them continues. +If an output cannot be written to, an error occurs; however, exiting will be +deferred until writing to any other specified outputs completes. When an error is encountered, a diagnostic message is printed and the program exits with the appropriate From ee9d42d0d4b5f04f6380eb9c109adad589b10925 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 17 Jun 2024 23:02:13 -0600 Subject: [PATCH 100/343] str.1: cleanup --- docs/str.1 | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/str.1 b/docs/str.1 index c3f7538..d45289a 100644 --- a/docs/str.1 +++ b/docs/str.1 @@ -6,7 +6,7 @@ .\" .TH STR 1 2024-06-06 "Bonsai Core Utilites 0.13.8" .SH NAME -str \(en test the character types of string arguments +str \(en test string arguments .\" .SH SYNOPSIS @@ -16,7 +16,7 @@ str .\" .SH DESCRIPTION -Test string arguments. +Test the character types of string arguments. The tests in this program are equivalent to the functions with the same names in .BR ctype.h (0p) @@ -24,11 +24,8 @@ and are the methods by which string arguments are tested. .\" .SH DIAGNOSTICS -If all tests pass, the program will exit with an exit code of 0. If any of the -tests fail, the program will exit unsuccessfully with an error code of 1. - -An empty string will cause an unsuccessful exit as none of its contents pass any -tests. +If all tests pass, the program will exit successfully. If any of the tests fail, +the program will exit unsuccessfully with an error code of 1. When invoked incorrectly, a debug message will be printed and the program will exit with the appropriate @@ -37,6 +34,9 @@ error code. .\" .SH CAVEATS +None of an empty string\(cqs contents pass any of the tests, so the program will +exit unsuccessfully if one is specified. + There\(cqs no way of knowing which argument failed the test without re-testing arguments individually. From 53d5a1db73542cc9a11a1e9356f0a5f232c225f9 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 17 Jun 2024 23:09:15 -0600 Subject: [PATCH 101/343] hru.1: italics and removes clunky sentences --- docs/hru.1 | 24 +++++++++++++----------- docs/str.1 | 2 +- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/docs/hru.1 b/docs/hru.1 index b24671e..acd5876 100644 --- a/docs/hru.1 +++ b/docs/hru.1 @@ -3,7 +3,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH HRU 1 2024-06-06 "Bonsai Core Utilites 0.13.8" +.TH HRU 1 2024-06-17 "Bonsai Core Utilites 0.13.8" .SH NAME hru \(en human readable units .\" @@ -15,9 +15,9 @@ hru Convert counts to higher units. -The program will read byte counts in the form of whole numbers from the standard -input and write to the standard output the same number converted to a higher -unit of data as defined by the International System of Units. +Byte counts will be read in the form of whole numbers from the standard input +and be written to the standard output the same number converted to a higher unit +of data as defined by the \fIInternational System of Units\fP. The program will convert the byte count to the highest unit possible where the value is greater than one. @@ -35,10 +35,8 @@ The GNU project\(cqs .BR ls (1) implementation contains a human-readable option (\fB-h\fP) 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 -.BR ls (1) -so the decision was made to split it into a new tool. The original functionality -in GNU\(cqs +readable. This functionality is useful not only in this context, so the decision +was made to split it into a new tool. The original functionality from GNU\(cqs .BR ls (1) can be emulated with .BR fop (1) @@ -46,8 +44,12 @@ combined with this program. .\" .SH STANDARDS -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) +The standard unit prefixes as specified by the +.I Bureau International des Poids et Mesures +.RI ( BIPM ) +in the ninth edition of +.I The International System of Units +.RI ( SI ) are utilized for the ouput of conversions. .\" .SH AUTHOR @@ -64,4 +66,4 @@ Copyright \(co 2024 Emma Tebibyte. License AGPLv3+: GNU AGPL version 3 or later .SH SEE ALSO GNU .BR ls (1), -The International System of Units (SI) 9th Edition +.I The International System of Units (SI) 9th Edition diff --git a/docs/str.1 b/docs/str.1 index d45289a..55dd0bb 100644 --- a/docs/str.1 +++ b/docs/str.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH STR 1 2024-06-06 "Bonsai Core Utilites 0.13.8" +.TH STR 1 2024-06-17 "Bonsai Core Utilites 0.13.8" .SH NAME str \(en test string arguments .\" From 1b299f8ee1f3cbf367327bd3eedbe600f7c32b57 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 17 Jun 2024 23:16:25 -0600 Subject: [PATCH 102/343] rpn.1: fixes clunkiness --- docs/rpn.1 | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/docs/rpn.1 b/docs/rpn.1 index 507789d..01e00b9 100644 --- a/docs/rpn.1 +++ b/docs/rpn.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH RPN 1 2024-06-06 "Bonsai Core Utilites 0.13.8" +.TH RPN 1 2024-06-17 "Bonsai Core Utilites 0.13.8" .SH NAME rpn \(en reverse polish notation evaluation .\" @@ -18,12 +18,12 @@ rpn Evaluate reverse polish notation. -The program evaluates reverse polish notation expressions either read from the +The program evaluates reverse polish notation expressions read either from the standard input or parsed from provided arguments. See the STANDARD INPUT section. -Upon evaluation, the program will print the resulting number on the stack to the -standard output. Any further specified numbers will be placed at the end of the +Upon evaluation, the resulting number on the stack will be printed to the +standard output. Any further numbers specified will be placed at the end of the stack. For information on for reverse polish notation syntax, see @@ -31,8 +31,8 @@ For information on for reverse polish notation syntax, see .\" .SH STANDARD INPUT -If arguments are passed, they are interpreted as an expression to be -evaluated. Otherwise, it reads whitespace-delimited numbers and operations from +If arguments are specified, they are interpreted as an expression to be +evaluated. Otherwise, whitespace-delimited numbers and operations are read from the standard input. .\" .SH DIAGNOSTICS @@ -46,11 +46,13 @@ error message and continue accepting input. .SH CAVEATS Due to precision constraints and the way floats are represented in accordance -with the IEEE Standard for Floating Point Arithmetic (\fIIEEE 754\fP), -floating-point arithmetic has rounding errors. This is somewhat curbed by using -the machine epsilon as provided by the Rust standard library to which to round -numbers. Because of this, variation is expected in the number of decimal places -the program can handle based on the platform and hardware of any given machine. +with the +.I IEEE Standard for Floating Point Arithmetic +(\fIIEEE 754\fP), floating-point arithmetic has rounding errors. This is +somewhat curbed by using the machine epsilon as provided by the Rust standard +library to which numbers are rounded. Because of this, variation is expected in +the number of decimal places the program can handle based on the platform and +hardware of any given machine. .\" .SH RATIONALE @@ -63,8 +65,8 @@ program. A pre-dates the standardized .BR bc (1p), the latter originally being a preprocessor for the former, and was included in -UNIX v2 onward. While it implements reverse polish notation, it still suffers -from being unable to accept an expression as an argument. +Second Edition UNIX and onward. While it implements reverse polish notation, it +still suffers from being unable to accept an expression as an argument. .\" .SH AUTHOR From 266ee20d5c7d7dc93cd925df84936ab182dcc8a4 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 17 Jun 2024 23:18:45 -0600 Subject: [PATCH 103/343] fop.1: removes unnecessary stdin section and adds AUTHOR --- docs/fop.1 | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/fop.1 b/docs/fop.1 index fe1a3c5..b5c1b7c 100644 --- a/docs/fop.1 +++ b/docs/fop.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH FOP 1 2024-06-06 "Bonsai Core Utilites 0.13.8" +.TH FOP 1 2024-06-17 "Bonsai Core Utilites 0.13.8" .SH NAME fop \(en field operator .\" @@ -18,7 +18,7 @@ fop .\" .SH DESCRIPTION -Performs operations on specified fields in input data. +Performs operations on specified fields in data read from the standard input. .\" .SH OPTIONS @@ -26,10 +26,6 @@ Performs operations on specified fields in input data. Sets a delimiter by which the input data will be split into fields. The default is an ASCII record separator. .\" -.SH STANDARD INPUT - -Data will be read from the standard input. -.\" .SH CAVEATS Field indices are zero-indexed, which may be unexpected behavior for some users. @@ -51,6 +47,12 @@ but there was no easy way to modify the field in the ouput of .BR ls (1p) without creating a new tool. .\" +.SH AUTHOR + +Written by Emma Tebibyte +.MT emma@tebibyte.media +.ME . +.\" .SH COPYRIGHT Copyright \(co 2024 Emma Tebibyte. License AGPLv3+: GNU AGPL version 3 or later From bf10689606b53588dac03d6d48ded1d8560228fd Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 17 Jun 2024 23:20:29 -0600 Subject: [PATCH 104/343] swab.1: bold --- docs/swab.1 | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/swab.1 b/docs/swab.1 index a3af1ad..abaab0b 100644 --- a/docs/swab.1 +++ b/docs/swab.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH SWAB 1 2024-06-06 "Bonsai Core Utilites 0.13.8" +.TH SWAB 1 2024-06-17 "Bonsai Core Utilites 0.13.8" .SH NAME swab \(en swap bytes .\" @@ -56,7 +56,9 @@ error code. .\" .SH RATIONALE -This program was modeled and named after the conv=swab functionality specified +This program was modeled and named after the +.B conv=swab +functionality specified in the .BR dd (1p) utility. It additionally allows the word size to be configured. @@ -64,6 +66,12 @@ utility. It additionally allows the word size to be configured. This functionality is useful for fixing the endianness of binary files produced on other machines. .\" +.SH AUTHOR + +Written by DTB +.MT trinity@trinity.moe +.ME . +.\" .SH COPYRIGHT Copyright \(co 2024 DTB. License AGPLv3+: GNU AGPL version 3 or later From 59eee27979666b3eaca0c2721965bf2c82eca342 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 17 Jun 2024 23:21:44 -0600 Subject: [PATCH 105/343] strcmp.1: or --- docs/strcmp.1 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/strcmp.1 b/docs/strcmp.1 index facfdeb..5941762 100644 --- a/docs/strcmp.1 +++ b/docs/strcmp.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH STRCMP 1 2024-06-06 "Bonsai Core Utilites 0.13.8" +.TH STRCMP 1 2024-06-17 "Bonsai Core Utilites 0.13.8" .SH NAME strcmp \(en compare strings .\" @@ -28,7 +28,7 @@ than one of the prior strings: strcmp b a .RE -and with an error code of 255 if it has a greater byte value than one of the +or with an error code of 255 if it has a greater byte value than one of the prior strings: .RS @@ -54,7 +54,8 @@ been This tool also handles integer comparisons and file scrutiny. These parts of its functionality have been broken out into multiple utilities. -This program\(cqs functionality may be performed on a POSIX-compliant system with +This program\(cqs functionality may be performed on a POSIX-compliant system +with .BR test (1p). .\" .SH AUTHOR From e38dcc09b12a0fa2c1c1a7e4e645027a29bfbe56 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 17 Jun 2024 23:27:19 -0600 Subject: [PATCH 106/343] intcmp.1: bold --- docs/intcmp.1 | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/docs/intcmp.1 b/docs/intcmp.1 index 94e88a4..2808362 100644 --- a/docs/intcmp.1 +++ b/docs/intcmp.1 @@ -28,19 +28,23 @@ Permits a given integer to be less than the following integer. .\" .SH EXAMPLES -It may help to think of the -e, -g, and -l options as equivalent to the -infix algebraic \(lq=\(rq, \(lq>\(rq, and \(lq<\(rq operators respectively, with -each option putting its symbol between every given integer. The following -example is equivalent to evaluating \(lq1 < 2 < 3\(rq: +It may help to think of the +.BR -e , +.BR -g , +and +.B -l +options as equivalent to the infix algebraic \(lq=\(rq, \(lq>\(rq, and \(lq<\(rq +operators respectively, with each option putting its symbol between every given +integer. The following example is equivalent to evaluating \(lq1 < 2 < 3\(rq: \" .RS -.R intcmp -l 1 2 3 +intcmp -l 1 2 3 .RE .\" .SH DIAGNOSTICS -The program will exit with a status code of 0 for a valid expression and with a -code of 1 for an invalid expression. +The program will exit with a successfully for a valid expression and with an +error code of 1 for an invalid expression. In the event of an error, a debug message will be printed and the program will exit with the appropriate @@ -49,7 +53,8 @@ error code. .\" .SH BUGS --egl, \(lqequal to or less than or greater than\(rq, exits 0 no matter what for +.BR -egl , +\(lqequal to or less than or greater than\(rq, always exits successfully for valid program usage and may be abused to function as an integer validator. Use .BR str (1) instead. @@ -57,9 +62,17 @@ instead. .SH CAVEATS There are multiple ways to express compound comparisons; \(lqless than or equal -to\(rq can be -le or -el, for example. +to\(rq can be +.B -le +or +.BR -el , +for example. -The inequality comparison is -gl or -lg for \(lqless than or greater than\(rq; +The inequality comparison is +.B -gl +.B or +.B -lg +for \(lqless than or greater than\(rq; this is elegant but unintuitive. .\" .SH RATIONALE From 6814111ad1a6d14ac5b514212f5a9e1a9a7c6947 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 17 Jun 2024 23:36:52 -0600 Subject: [PATCH 107/343] dj.1: fixes many clunky sentences --- docs/dj.1 | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 1572991..6073fc6 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH DJ 1 2024-06-06 "Bonsai Core Utilites 0.13.8" +.TH DJ 1 2024-06-17 "Bonsai Core Utilites 0.13.8" .SH NAME dj \(en disk jockey .\" @@ -34,13 +34,13 @@ dj .SH DESCRIPTION Perform precise read and write operations on files. This utility is useful for -reading and writing binary data to and from disks, hence the name. +reading and writing binary data to and from disks. This manual page uses the terms \(lqskip\(rq and \(lqseek\(rq to refer to moving to a specified byte by index in the input and output of the program respectively. This language is inherited from the .BR dd (1p) -utility and is used here to decrease ambiguity. +utility and used here to decrease ambiguity. When seeking or skipping to a byte, writing or reading starts at the byte immediately subsequent to the specified byte. @@ -50,8 +50,8 @@ immediately subsequent to the specified byte. .IP \fB-i\fP Takes a file path as an argument and opens it for use as an input. .IP \fB-b\fP -Takes a numeric argument as the size in bytes of the input buffer, with the -default being 1024. +Takes a numeric argument as the size in bytes of the input buffer, the default +being 1024. .IP \fB-s\fP Takes a numeric argument as the number of bytes to skip into the input before starting to read. If the standard input is used, bytes read to this point @@ -66,25 +66,25 @@ but for the output buffer. Seeks a number of bytes through the output before starting to write from the input. If the output is a stream, null characters are printed. .IP \fB-a\fP -Accepts a single literal byte with which input buffer is padded in the event +Accepts a single literal byte with which the input buffer is padded in the event of an incomplete read from the input file. .IP \fB-A\fP Specifying this option pads the input buffer with null bytes in the event of an -incomplete read. Equivalent to specifying +incomplete read. This is equivalent to specifying .B -a with a null byte instead of a character. .IP \fB-c\fP -Specifies a number of reads to make. The default is zero, in which case the +Specifies a number of reads to make. The default is 0, in which case the input is read until a partial or empty read is made. .IP \fB-d\fP Prints invocation information before program execution as described in the -DIAGNOSTICS section below. Each invocation increments the debug level of the +DIAGNOSTICS section. Each invocation increments the debug level of the program. .IP \fB-H\fP Prints diagnostics messages in a human-readable manner as described in the -DIAGNOSTICS section below. +DIAGNOSTICS section. .IP \fB-n\fP -Retries failed reads once more before exiting. +Retries failed reads once before exiting. .IP \fB-q\fP Suppresses error messages which print when a read or write is partial or empty. Each invocation decrements the debug level of the program. @@ -94,13 +94,18 @@ empty. Each invocation decrements the debug level of the program. The standard input shall be used as an input if no inputs are specified or if one or more of the input files is \(lq-\(rq. .\" +.SH STANDARD OUTPUT +The standard output shall be used as an output if no inputs are specified or if +one or more of the input files is \(lq-\(rq. +.\" .SH DIAGNOSTICS -On a partial or empty read, a diagnostic message is printed (unless the +On a partial or empty read, unless the .B -q -option is specified) and the program exits (unless the +option is specified, a diagnostic message is printed. Then, the program exits +unless the .B -n -option is specified). +option is specified. By default, statistics are printed for input and output to the standard error in the following format: @@ -125,9 +130,9 @@ option may be specified. In this event, the following format is used instead: If the .B -d -option is specified, debug output will be printed at the beginning of -execution. This debug information contains information regarding how the program -was invoked. The following example is the result of running the program with +option is specified, debug information will be printed at the beginning of +execution. This output contains information regarding how the program was +invoked. The following example is the result of running the program with .B -d as the only argument: @@ -148,12 +153,12 @@ If .B -n is specified along with the .B -c -option and a count, actual byte output may be lower than expected (the product -of the count and the input block size). If the +option and a count, actual byte output is the product of the count and the input +block size and therefore may be lower than expected. If the .B -a or .B -A -options are used, this could make data written nonsensical. +options are specified, this could make written data nonsensical. .\" .SH CAVEATS From d201f9228ce6e6379c845d1a541a133629da4b05 Mon Sep 17 00:00:00 2001 From: emma Date: Tue, 18 Jun 2024 16:32:20 -0600 Subject: [PATCH 108/343] Makefile: updates to use new POSIX 2024 standard features! --- Makefile | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 1952a25..15b2968 100644 --- a/Makefile +++ b/Makefile @@ -11,8 +11,7 @@ .POSIX: # if using BSD make(1), remove these pragmas because they break it -.PRAGMA: posix_202x # future POSIX standard support à la pdpmake(1) -.PRAGMA: command_comment # breaks without this? + DESTDIR ?= dist PREFIX ?= /usr/local @@ -32,9 +31,9 @@ CFLAGS += -I$(SYSEXITS) .PHONY: all all: dj false fop hru intcmp mm npc rpn scrut str strcmp swab true +# keep build/include until bindgen(1) has stdin support +# https://github.com/rust-lang/rust-bindgen/issues/2703 build: - # keep build/include until bindgen(1) has stdin support - # https://github.com/rust-lang/rust-bindgen/issues/2703 mkdir -p build/bin build/include build/lib build/o build/test .PHONY: clean @@ -67,9 +66,9 @@ build/o/libstrerror.rlib: build src/strerror.rs $(RUSTC) $(RUSTFLAGS) --crate-type=lib -o $@ \ src/strerror.rs +# bandage solution until bindgen(1) gets stdin support build/o/libsysexits.rlib: build $(SYSEXITS)sysexits.h - # bandage solution until bindgen(1) gets stdin support - printf '#define EXIT_FAILURE 1\n' | cat - $(SYSEXITS)sysexits.h \ + printf '\043define EXIT_FAILURE 1\n' | cat - $(SYSEXITS)sysexits.h \ > build/include/sysexits.h bindgen --default-macro-constant-type signed --use-core --formatter=none \ build/include/sysexits.h | $(RUSTC) $(RUSTFLAGS) --crate-type lib -o $@ - From f553cff09651512b609e2c394f368775fe9c674b Mon Sep 17 00:00:00 2001 From: emma Date: Tue, 18 Jun 2024 16:33:22 -0600 Subject: [PATCH 109/343] Makefile: removes unneeded comment --- Makefile | 3 --- 1 file changed, 3 deletions(-) diff --git a/Makefile b/Makefile index 15b2968..0dee534 100644 --- a/Makefile +++ b/Makefile @@ -10,9 +10,6 @@ .POSIX: -# if using BSD make(1), remove these pragmas because they break it - - DESTDIR ?= dist PREFIX ?= /usr/local From 125b4c89300916bd3325343c71ff601be3916911 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 19 Jun 2024 02:52:58 -0600 Subject: [PATCH 110/343] README: updated for clarity --- README | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README b/README index d7a79f6..68be16c 100644 --- a/README +++ b/README @@ -1,9 +1,11 @@ “Seek not to walk the path of the masters; seek what they sought.” – Matsuo Basho -The Bonsai core utilities are the result of the careful examination of the -current state of POSIX and Unix utilies. The Unix Philosophy, “do one thing and -do it well” is its core but these tools do not cling to the names of the past. +The Bonsai core utilities are a replacement for standard POSIX utilities which +aim to fill its niche while expanding on their capabilities. These new tools are +the result of the careful examination of the current state of POSIX and Unix +utilies. The Unix Philosophy of “do one thing and do it well” are their core but +they avoid clinging to the past. The era of the original Unix tools has been long and fruitful, but they have their flaws. The new, non-POSIX era of this project started with frustration @@ -38,7 +40,7 @@ To test the utilities: $ make test -To remove all untracked files: +To remove all build and distributable files: $ make clean From e1ac40e7ee285131711117d5373825addfafb522 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 19 Jun 2024 15:03:06 -0600 Subject: [PATCH 111/343] docs: updates version number --- docs/dj.1 | 2 +- docs/false.1 | 2 +- docs/fop.1 | 2 +- docs/hru.1 | 2 +- docs/intcmp.1 | 2 +- docs/mm.1 | 2 +- docs/npc.1 | 2 +- docs/rpn.1 | 2 +- docs/scrut.1 | 2 +- docs/str.1 | 2 +- docs/strcmp.1 | 2 +- docs/swab.1 | 2 +- docs/true.1 | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 6073fc6..e229d1f 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH DJ 1 2024-06-17 "Bonsai Core Utilites 0.13.8" +.TH DJ 1 2024-06-17 "Bonsai Core Utilites 0.13.9" .SH NAME dj \(en disk jockey .\" diff --git a/docs/false.1 b/docs/false.1 index 1dec3ce..f86e1d8 100644 --- a/docs/false.1 +++ b/docs/false.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH FALSE 1 2024-06-06 "Bonsai Core Utilites 0.13.8" +.TH FALSE 1 2024-06-06 "Bonsai Core Utilites 0.13.9" .SH NAME false \(en do nothing, unsuccessfully .\" diff --git a/docs/fop.1 b/docs/fop.1 index b5c1b7c..6c7b991 100644 --- a/docs/fop.1 +++ b/docs/fop.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH FOP 1 2024-06-17 "Bonsai Core Utilites 0.13.8" +.TH FOP 1 2024-06-17 "Bonsai Core Utilites 0.13.9" .SH NAME fop \(en field operator .\" diff --git a/docs/hru.1 b/docs/hru.1 index acd5876..60a5afd 100644 --- a/docs/hru.1 +++ b/docs/hru.1 @@ -3,7 +3,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH HRU 1 2024-06-17 "Bonsai Core Utilites 0.13.8" +.TH HRU 1 2024-06-17 "Bonsai Core Utilites 0.13.9" .SH NAME hru \(en human readable units .\" diff --git a/docs/intcmp.1 b/docs/intcmp.1 index 2808362..b50b3f9 100644 --- a/docs/intcmp.1 +++ b/docs/intcmp.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH INTCMP 1 2024-06-06 "Bonsai Core Utilites 0.13.8" +.TH INTCMP 1 2024-06-06 "Bonsai Core Utilites 0.13.9" .SH NAME intcmp \(en compare integers .\" diff --git a/docs/mm.1 b/docs/mm.1 index 1fe64ba..107d5b0 100644 --- a/docs/mm.1 +++ b/docs/mm.1 @@ -3,7 +3,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH MM 1 2024-06-17 "Bonsai Core Utilites 0.13.8" +.TH MM 1 2024-06-17 "Bonsai Core Utilites 0.13.9" .SH NAME mm \(en middleman .\" diff --git a/docs/npc.1 b/docs/npc.1 index a0e503e..7b54e31 100644 --- a/docs/npc.1 +++ b/docs/npc.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH NPC 1 2024-06-17 "Bonsai Core Utilites 0.13.8" +.TH NPC 1 2024-06-17 "Bonsai Core Utilites 0.13.9" .SH NAME npc \(en show non-printing characters .\" diff --git a/docs/rpn.1 b/docs/rpn.1 index 01e00b9..10cd709 100644 --- a/docs/rpn.1 +++ b/docs/rpn.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH RPN 1 2024-06-17 "Bonsai Core Utilites 0.13.8" +.TH RPN 1 2024-06-17 "Bonsai Core Utilites 0.13.9" .SH NAME rpn \(en reverse polish notation evaluation .\" diff --git a/docs/scrut.1 b/docs/scrut.1 index 636c5d3..9dac85b 100644 --- a/docs/scrut.1 +++ b/docs/scrut.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH SCRUT 1 2024-06-06 "Bonsai Core Utilites 0.13.8" +.TH SCRUT 1 2024-06-06 "Bonsai Core Utilites 0.13.9" .SH NAME scrut \(en scrutinize file properties .SH SYNOPSIS diff --git a/docs/str.1 b/docs/str.1 index 55dd0bb..cfc859f 100644 --- a/docs/str.1 +++ b/docs/str.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH STR 1 2024-06-17 "Bonsai Core Utilites 0.13.8" +.TH STR 1 2024-06-17 "Bonsai Core Utilites 0.13.9" .SH NAME str \(en test string arguments .\" diff --git a/docs/strcmp.1 b/docs/strcmp.1 index 5941762..0e5d46f 100644 --- a/docs/strcmp.1 +++ b/docs/strcmp.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH STRCMP 1 2024-06-17 "Bonsai Core Utilites 0.13.8" +.TH STRCMP 1 2024-06-17 "Bonsai Core Utilites 0.13.9" .SH NAME strcmp \(en compare strings .\" diff --git a/docs/swab.1 b/docs/swab.1 index abaab0b..97002e7 100644 --- a/docs/swab.1 +++ b/docs/swab.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH SWAB 1 2024-06-17 "Bonsai Core Utilites 0.13.8" +.TH SWAB 1 2024-06-17 "Bonsai Core Utilites 0.13.9" .SH NAME swab \(en swap bytes .\" diff --git a/docs/true.1 b/docs/true.1 index 2e8d5eb..b23021d 100644 --- a/docs/true.1 +++ b/docs/true.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH TRUE 1 2024-06-06 "Bonsai Core Utilites 0.13.8" +.TH TRUE 1 2024-06-06 "Bonsai Core Utilites 0.13.9" .SH NAME true \(en do nothing, successfully .\" From 35f49a699f5d4edb252b873dda1841645ba486a2 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 19 Jun 2024 15:26:46 -0600 Subject: [PATCH 112/343] fop(1): fixes record separator, again --- src/fop.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fop.rs b/src/fop.rs index 1cc8152..9bf2396 100644 --- a/src/fop.rs +++ b/src/fop.rs @@ -32,7 +32,7 @@ use sysexits::{ EX_DATAERR, EX_IOERR, EX_UNAVAILABLE, EX_USAGE }; fn main() { let argv = args().collect::>(); - let mut d = 0x1E.to_string(); + let mut d = char::from(0x1E).to_string(); let mut arg_parser = Parser::new(&argv, "d:"); while let Some(opt) = arg_parser.next() { From 72f57ba08be24574ecd458f351c13ecf75d8192d Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 19 Jun 2024 23:29:22 -0600 Subject: [PATCH 113/343] Makefile: adds octal disclaimer --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 0dee534..7756c56 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,9 @@ # permitted in any medium without royalty provided the copyright notice and this # notice are preserved. This file is offered as-is, without any warranty. +# The octal escape \043 is utilized twice in this file as make(1p) will +# interpret a hash in a rule as an inline comment. + .POSIX: DESTDIR ?= dist From 4b3333d8d31eae5a0d1a3f5c8601c696179150c2 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 21 Jun 2024 03:23:39 -0600 Subject: [PATCH 114/343] fop(1): record separator worky now? --- docs/dj.1 | 2 +- docs/false.1 | 2 +- docs/fop.1 | 2 +- docs/hru.1 | 2 +- docs/intcmp.1 | 2 +- docs/mm.1 | 2 +- docs/npc.1 | 2 +- docs/rpn.1 | 2 +- docs/scrut.1 | 2 +- docs/str.1 | 2 +- docs/strcmp.1 | 2 +- docs/swab.1 | 2 +- docs/true.1 | 2 +- src/fop.rs | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index e229d1f..7d28ac8 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH DJ 1 2024-06-17 "Bonsai Core Utilites 0.13.9" +.TH DJ 1 2024-06-17 "Bonsai Core Utilites 0.13.11" .SH NAME dj \(en disk jockey .\" diff --git a/docs/false.1 b/docs/false.1 index f86e1d8..5b582dd 100644 --- a/docs/false.1 +++ b/docs/false.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH FALSE 1 2024-06-06 "Bonsai Core Utilites 0.13.9" +.TH FALSE 1 2024-06-06 "Bonsai Core Utilites 0.13.11" .SH NAME false \(en do nothing, unsuccessfully .\" diff --git a/docs/fop.1 b/docs/fop.1 index 6c7b991..f7afa54 100644 --- a/docs/fop.1 +++ b/docs/fop.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH FOP 1 2024-06-17 "Bonsai Core Utilites 0.13.9" +.TH FOP 1 2024-06-17 "Bonsai Core Utilites 0.13.11" .SH NAME fop \(en field operator .\" diff --git a/docs/hru.1 b/docs/hru.1 index 60a5afd..346f200 100644 --- a/docs/hru.1 +++ b/docs/hru.1 @@ -3,7 +3,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH HRU 1 2024-06-17 "Bonsai Core Utilites 0.13.9" +.TH HRU 1 2024-06-17 "Bonsai Core Utilites 0.13.11" .SH NAME hru \(en human readable units .\" diff --git a/docs/intcmp.1 b/docs/intcmp.1 index b50b3f9..315cda2 100644 --- a/docs/intcmp.1 +++ b/docs/intcmp.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH INTCMP 1 2024-06-06 "Bonsai Core Utilites 0.13.9" +.TH INTCMP 1 2024-06-06 "Bonsai Core Utilites 0.13.11" .SH NAME intcmp \(en compare integers .\" diff --git a/docs/mm.1 b/docs/mm.1 index 107d5b0..3ca0722 100644 --- a/docs/mm.1 +++ b/docs/mm.1 @@ -3,7 +3,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH MM 1 2024-06-17 "Bonsai Core Utilites 0.13.9" +.TH MM 1 2024-06-17 "Bonsai Core Utilites 0.13.11" .SH NAME mm \(en middleman .\" diff --git a/docs/npc.1 b/docs/npc.1 index 7b54e31..51cb851 100644 --- a/docs/npc.1 +++ b/docs/npc.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH NPC 1 2024-06-17 "Bonsai Core Utilites 0.13.9" +.TH NPC 1 2024-06-17 "Bonsai Core Utilites 0.13.11" .SH NAME npc \(en show non-printing characters .\" diff --git a/docs/rpn.1 b/docs/rpn.1 index 10cd709..7d3b477 100644 --- a/docs/rpn.1 +++ b/docs/rpn.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH RPN 1 2024-06-17 "Bonsai Core Utilites 0.13.9" +.TH RPN 1 2024-06-17 "Bonsai Core Utilites 0.13.11" .SH NAME rpn \(en reverse polish notation evaluation .\" diff --git a/docs/scrut.1 b/docs/scrut.1 index 9dac85b..1e17f7e 100644 --- a/docs/scrut.1 +++ b/docs/scrut.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH SCRUT 1 2024-06-06 "Bonsai Core Utilites 0.13.9" +.TH SCRUT 1 2024-06-06 "Bonsai Core Utilites 0.13.11" .SH NAME scrut \(en scrutinize file properties .SH SYNOPSIS diff --git a/docs/str.1 b/docs/str.1 index cfc859f..6f01125 100644 --- a/docs/str.1 +++ b/docs/str.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH STR 1 2024-06-17 "Bonsai Core Utilites 0.13.9" +.TH STR 1 2024-06-17 "Bonsai Core Utilites 0.13.11" .SH NAME str \(en test string arguments .\" diff --git a/docs/strcmp.1 b/docs/strcmp.1 index 0e5d46f..2ff08f6 100644 --- a/docs/strcmp.1 +++ b/docs/strcmp.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH STRCMP 1 2024-06-17 "Bonsai Core Utilites 0.13.9" +.TH STRCMP 1 2024-06-17 "Bonsai Core Utilites 0.13.11" .SH NAME strcmp \(en compare strings .\" diff --git a/docs/swab.1 b/docs/swab.1 index 97002e7..1c75705 100644 --- a/docs/swab.1 +++ b/docs/swab.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH SWAB 1 2024-06-17 "Bonsai Core Utilites 0.13.9" +.TH SWAB 1 2024-06-17 "Bonsai Core Utilites 0.13.11" .SH NAME swab \(en swap bytes .\" diff --git a/docs/true.1 b/docs/true.1 index b23021d..ebf8916 100644 --- a/docs/true.1 +++ b/docs/true.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH TRUE 1 2024-06-06 "Bonsai Core Utilites 0.13.9" +.TH TRUE 1 2024-06-06 "Bonsai Core Utilites 0.13.11" .SH NAME true \(en do nothing, successfully .\" diff --git a/src/fop.rs b/src/fop.rs index 9bf2396..5244300 100644 --- a/src/fop.rs +++ b/src/fop.rs @@ -32,7 +32,7 @@ use sysexits::{ EX_DATAERR, EX_IOERR, EX_UNAVAILABLE, EX_USAGE }; fn main() { let argv = args().collect::>(); - let mut d = char::from(0x1E).to_string(); + let mut d = '\u{1E}'.to_string(); let mut arg_parser = Parser::new(&argv, "d:"); while let Some(opt) = arg_parser.next() { From 8f990ba515ccdb548b8f4a858e128e204842fcbd Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 22 Jun 2024 22:18:13 -0600 Subject: [PATCH 115/343] getopt.rs(3): adds testing --- Makefile | 6 +- src/getopt.rs | 151 +++++++++++++++++++++++++++++++++++--------------- 2 files changed, 111 insertions(+), 46 deletions(-) diff --git a/Makefile b/Makefile index 7736a78..734a62c 100644 --- a/Makefile +++ b/Makefile @@ -49,9 +49,13 @@ install: dist cp -r $(DESTDIR)/* / .PHONY: test -test: build +test: build /tmp/getopt tests/posix-compat.sh +/tmp/getopt: src/getopt.rs + $(RUSTC) --test -o /tmp/getopt src/getopt.rs + /tmp/getopt + .PHONY: rustlibs rustlibs: build/o/libsysexits.rlib build/o/libgetopt.rlib \ build/o/libstrerror.rlib diff --git a/src/getopt.rs b/src/getopt.rs index 5ce094c..dc88229 100644 --- a/src/getopt.rs +++ b/src/getopt.rs @@ -32,49 +32,71 @@ extern "C" { ) -> c_int; } -pub struct Opt { - pub arg: Option, - ind: *mut i32, - pub opt: String, -} - -impl Opt { - pub fn index(&self) -> usize { unsafe { *self.ind as usize } } - - pub fn set_index(&self, ind: i32) { unsafe { *self.ind = ind; } } -} - +#[derive(Clone, Debug)] pub enum OptError { MissingArg(String), UnknownOpt(String), } +#[derive(Clone, Debug)] +pub struct Opt { + arg: Option, + ind: *mut i32, + opt: Result, +} + +impl Opt { + pub fn arg(&self) -> Option { self.arg.clone() } + + /* sets optarg if default is desired */ + pub fn arg_or(&self, default: impl std::fmt::Display) -> String { + default.to_string() + } + + pub fn opt(&self) -> Result<&str, OptError> { + self.opt.as_ref().map(|o| o.as_str()).map_err(OptError::clone) + } + + /* From getopt(3p): + * + * The variable optind is the index of the next element of the argv[] + * vector to be processed. It shall be initialized to 1 by the system, and + * getopt() shall update it when it finishes with each element of argv[]. + * If the application sets optind to zero before calling getopt(), the + * behavior is unspecified. When an element of argv[] contains multiple + * option characters, it is unspecified how getopt() determines which + * options have already been processed. */ + pub fn ind(&self) -> usize { unsafe { *self.ind as usize } } + + pub fn set_ind(&self, ind: i32) { unsafe { *self.ind = ind; } } +} + /* function signature */ pub trait GetOpt { - fn getopt(&self, optstring: &str) -> Option>; + fn getopt(&self, optstring: &str) -> Option; } impl GetOpt for Vec { - fn getopt(&self, optstring: &str) -> Option> { + fn getopt(&self, optstring: &str) -> Option { let c_strings: Vec<_> = self .iter() .cloned() - .map(CString::new) - .map(Result::unwrap) + .map(|x| CString::new(x).unwrap().into_raw()) .collect(); + let boxed = Box::into_raw(c_strings.into_boxed_slice()); + let argv = boxed as *const *mut i8; + /* these operations must be separated out into separate operations so * the CStrings can live long enough */ - let argv: Vec<_> = c_strings.iter().map(|x| x.as_ptr()).collect(); - let argv_ptr = argv.as_ptr() as *const *mut c_char; let opts = CString::new(optstring).unwrap().into_raw(); let len = self.len() as c_int; unsafe { - match getopt(len, argv_ptr, opts) { + let ret = match getopt(len, argv, opts) { /* From getopt(3p): * - * The getopt() f unction shall return the next option character + * The getopt() function shall return the next option character * specified on the command line. * * A (':') shall be returned if getopt() detects a @@ -89,10 +111,24 @@ impl GetOpt for Vec { * Otherwise, getopt() shall return -1 when all command line * options are parsed. */ 58 => { /* numerical ASCII value for ':' */ - Some(Err(OptError::MissingArg(optopt.to_string()))) + Some(Opt { + /* opt argument */ + arg: None, + /* opt index */ + ind: std::ptr::addr_of_mut!(optind), + /* error containing option */ + opt: Err(OptError::MissingArg(optopt.to_string())), + }) }, 63 => { /* numerical ASCII value for '?' */ - Some(Err(OptError::UnknownOpt(optopt.to_string()))) + Some(Opt { + /* opt argument */ + arg: None, + /* opt index */ + ind: std::ptr::addr_of_mut!(optind), + /* error containing option */ + opt: Err(OptError::UnknownOpt(optopt.to_string())), + }) }, /* From getopt(3p): * @@ -109,31 +145,56 @@ impl GetOpt for Vec { * getopt() shall return -1 after incrementing optind. */ -1 => return None, opt => { - let arg = CStr::from_ptr(optarg) - .to_string_lossy() - .into_owned(); + let arg: Option; - Some(Ok(Opt { - arg: Some(arg), /* opt argument */ - /* From getopt(3p): - * - * The variable optind is the index of the next element - * of the argv[] vector to be processed. It shall be - * initialized to 1 by the system, and getopt() shall - * update it when it finishes with each element of - * argv[]. If the application sets optind to zero - * before calling getopt(), the behavior is unspecified. - * When an element of argv[] contains multiple option - * characters, it is unspecified how getopt() - * determines which options have already been processed. - * - * This API is can be utilized with the index() and - * set_index() methods implemented for Opt. */ - ind: std::ptr::addr_of_mut!(optind), - opt: opt.to_string(), /* option itself */ - })) + if optarg.is_null() { arg = None; } + else { + arg = Some(CStr::from_ptr(optarg) + .to_string_lossy() + .into_owned()); + } + + Some(Opt { + arg, /* opt argument */ + ind: std::ptr::addr_of_mut!(optind), /* opt index */ + /* option itself */ + opt: Ok((opt as u8 as char).to_string()), + }) }, - } + }; + + /* delloc argv */ + let _ = Box::from_raw(boxed); + return ret; } } } + +#[cfg(test)] +mod tests { + use GetOpt; + + #[test] + fn testing() { + let argv: Vec = ["test", "-b", "-f", "arg", "-o", "arg"] + .iter() + .map(|s| s.to_string()) + .collect(); + + while let Some(opt) = argv.getopt(":abf:o:") { + match opt.opt() { + Ok("a") => assert_eq!(opt.ind(), 1), + Ok("b") => assert_eq!(opt.ind(), 2), + Ok("f") | Ok("o") => { + assert_eq!(opt.arg(), Some("arg".into())); + }, + _ => assert!(false), + }; + } + + if let Some(opt) = argv.getopt("abc:") { + opt.clone().set_ind(1); + assert_eq!(opt.ind(), 1); + } + } +} From e1bf49c75af4ff75aaae9761cc5a8196c4d6e198 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 22 Jun 2024 22:30:30 -0600 Subject: [PATCH 116/343] getopt.rs(3): adds comments & documentation --- src/getopt.rs | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/getopt.rs b/src/getopt.rs index dc88229..ee8cafa 100644 --- a/src/getopt.rs +++ b/src/getopt.rs @@ -40,9 +40,9 @@ pub enum OptError { #[derive(Clone, Debug)] pub struct Opt { - arg: Option, - ind: *mut i32, - opt: Result, + arg: Option, /* option argument */ + ind: *mut i32, /* option index */ + opt: Result, /* option option */ } impl Opt { @@ -53,6 +53,7 @@ impl Opt { default.to_string() } + /* makes matching the output of this method more bearable */ pub fn opt(&self) -> Result<&str, OptError> { self.opt.as_ref().map(|o| o.as_str()).map_err(OptError::clone) } @@ -68,6 +69,7 @@ impl Opt { * options have already been processed. */ pub fn ind(&self) -> usize { unsafe { *self.ind as usize } } + /* this is patently terrible and is only happening because I’m stubborn */ pub fn set_ind(&self, ind: i32) { unsafe { *self.ind = ind; } } } @@ -84,11 +86,11 @@ impl GetOpt for Vec { .map(|x| CString::new(x).unwrap().into_raw()) .collect(); + /* god knows what this does */ let boxed = Box::into_raw(c_strings.into_boxed_slice()); let argv = boxed as *const *mut i8; - /* these operations must be separated out into separate operations so - * the CStrings can live long enough */ + /* operations are separated out so that everything lives long enough */ let opts = CString::new(optstring).unwrap().into_raw(); let len = self.len() as c_int; @@ -110,21 +112,17 @@ impl GetOpt for Vec { * * Otherwise, getopt() shall return -1 when all command line * options are parsed. */ - 58 => { /* numerical ASCII value for ':' */ + 58 => { /* ASCII ':' */ Some(Opt { - /* opt argument */ arg: None, - /* opt index */ ind: std::ptr::addr_of_mut!(optind), /* error containing option */ opt: Err(OptError::MissingArg(optopt.to_string())), }) }, - 63 => { /* numerical ASCII value for '?' */ + 63 => { /* ASCII '?' */ Some(Opt { - /* opt argument */ arg: None, - /* opt index */ ind: std::ptr::addr_of_mut!(optind), /* error containing option */ opt: Err(OptError::UnknownOpt(optopt.to_string())), @@ -155,21 +153,25 @@ impl GetOpt for Vec { } Some(Opt { - arg, /* opt argument */ - ind: std::ptr::addr_of_mut!(optind), /* opt index */ - /* option itself */ + arg, + ind: std::ptr::addr_of_mut!(optind), + /* I didn’t need to cast this before; I rewrote the + * pointer logic and now I do + * + * I don’t know why this is */ opt: Ok((opt as u8 as char).to_string()), }) }, }; - /* delloc argv */ + /* delloc argv (something online said I should do this) */ let _ = Box::from_raw(boxed); return ret; } } } +/* tests (good) */ #[cfg(test)] mod tests { use GetOpt; From 6e4aeb7be7615ea899d7ba234713e50a63cc0a20 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 23 Jun 2024 01:00:48 -0600 Subject: [PATCH 117/343] fop(1): bring getopt(3) usage up-to-date --- src/fop.rs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/fop.rs b/src/fop.rs index 29f1522..91c8a72 100644 --- a/src/fop.rs +++ b/src/fop.rs @@ -33,25 +33,20 @@ use sysexits::{ EX_DATAERR, EX_IOERR, EX_UNAVAILABLE, EX_USAGE }; fn main() { let argv = args().collect::>(); let mut d = '\u{1E}'.to_string(); + let mut index_arg = 0; + let usage = format!( "Usage: {} [-d delimiter] index command [args...]", argv[0], ); - let mut index_arg = 0; - let mut arg_parser = Parser::new(&argv, "d:"); while let Some(opt) = argv.getopt("d:") { - match opt { - Ok(o) => { + match opt.opt() { + Ok(_) => { /* unwrap because Err(OptError::MissingArg) will be returned if - * o.arg is None */ - let arg = o.arg.clone().unwrap(); - let arg_char = arg.chars().collect::>(); - if arg_char.len() > 1 { - eprintln!("{}: {}: Not a character.", argv[0], arg); - exit(EX_USAGE); - } else { d = arg_char[0]; } - index_arg = o.index(); + * opt.arg() is None */ + d = opt.arg().unwrap(); + index_arg = opt.ind(); }, Err(_) => { eprintln!("{}", usage); From 8b400d8a6251115d449d6930245e0dda0457ef95 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 23 Jun 2024 23:34:23 -0600 Subject: [PATCH 118/343] Makefile, docs: rename --- README | 23 +++++++++++------------ docs/dj.1 | 2 +- docs/false.1 | 2 +- docs/fop.1 | 2 +- docs/hru.1 | 2 +- docs/intcmp.1 | 2 +- docs/mm.1 | 2 +- docs/npc.1 | 2 +- docs/rpn.1 | 2 +- docs/scrut.1 | 2 +- docs/str.1 | 2 +- docs/strcmp.1 | 2 +- docs/swab.1 | 2 +- docs/true.1 | 2 +- 14 files changed, 24 insertions(+), 25 deletions(-) diff --git a/README b/README index 68be16c..fdb05fb 100644 --- a/README +++ b/README @@ -1,28 +1,27 @@ “Seek not to walk the path of the masters; seek what they sought.” – Matsuo Basho -The Bonsai core utilities are a replacement for standard POSIX utilities which -aim to fill its niche while expanding on their capabilities. These new tools are -the result of the careful examination of the current state of POSIX and Unix -utilies. The Unix Philosophy of “do one thing and do it well” are their core but -they avoid clinging to the past. +The Bonsai harakit utilities are a replacement for standard POSIX utilities +which aim to fill its niche while expanding on their capabilities. These new +tools are the result of the careful examination of the current state of POSIX +and Unix utilies. The Unix Philosophy of “do one thing and do it well” are their +core but they avoid clinging to the past. The era of the original Unix tools has been long and fruitful, but they have -their flaws. The new, non-POSIX era of this project started with frustration -with the way certain tools work and how other projects that extend POSIX don’t -make anything better. +their flaws. This project originated from frustrations with the way certain +tools work and how other projects that extend POSIX don’t make anything better. This project will not follow in the footsteps of GNU; extensions of POSIX will not be found here. GNU extensions are a gateway to the misuse of the shell. The -Bonsai core utilities will intentionally discourage use of the shell for -purposes beyond its scope. +harakit utilities will intentionally discourage use of the shell for purposes +beyond its scope. See docs/ for more on the specific utilities currently implemented. Building -The coreutils require a POSIX-compliant environment to compile, including a C -compiler and preprocessor (cc(1) and cpp(1) by default), an edition 2023 Rust +Harakit utilities require a POSIX-compliant environment to compile, including a +C compiler and preprocessor (cc(1) and cpp(1) by default), an edition 2023 Rust compiler (rustc(1) by default), bindgen(1), and a POSIX-compliant make(1) utility. diff --git a/docs/dj.1 b/docs/dj.1 index 7d28ac8..5cf2368 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH DJ 1 2024-06-17 "Bonsai Core Utilites 0.13.11" +.TH DJ 1 2024-06-17 "Harakit 0.13.11" .SH NAME dj \(en disk jockey .\" diff --git a/docs/false.1 b/docs/false.1 index 5b582dd..1d6691b 100644 --- a/docs/false.1 +++ b/docs/false.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH FALSE 1 2024-06-06 "Bonsai Core Utilites 0.13.11" +.TH FALSE 1 2024-06-06 "Harakit 0.13.11" .SH NAME false \(en do nothing, unsuccessfully .\" diff --git a/docs/fop.1 b/docs/fop.1 index f7afa54..2d54720 100644 --- a/docs/fop.1 +++ b/docs/fop.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH FOP 1 2024-06-17 "Bonsai Core Utilites 0.13.11" +.TH FOP 1 2024-06-17 "Harakit 0.13.11" .SH NAME fop \(en field operator .\" diff --git a/docs/hru.1 b/docs/hru.1 index 346f200..eb0ce5e 100644 --- a/docs/hru.1 +++ b/docs/hru.1 @@ -3,7 +3,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH HRU 1 2024-06-17 "Bonsai Core Utilites 0.13.11" +.TH HRU 1 2024-06-17 "Harakit 0.13.11" .SH NAME hru \(en human readable units .\" diff --git a/docs/intcmp.1 b/docs/intcmp.1 index 315cda2..19c2c75 100644 --- a/docs/intcmp.1 +++ b/docs/intcmp.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH INTCMP 1 2024-06-06 "Bonsai Core Utilites 0.13.11" +.TH INTCMP 1 2024-06-06 "Harakit 0.13.11" .SH NAME intcmp \(en compare integers .\" diff --git a/docs/mm.1 b/docs/mm.1 index 3ca0722..0f1b97b 100644 --- a/docs/mm.1 +++ b/docs/mm.1 @@ -3,7 +3,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH MM 1 2024-06-17 "Bonsai Core Utilites 0.13.11" +.TH MM 1 2024-06-17 "Harakit 0.13.11" .SH NAME mm \(en middleman .\" diff --git a/docs/npc.1 b/docs/npc.1 index 51cb851..03890fb 100644 --- a/docs/npc.1 +++ b/docs/npc.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH NPC 1 2024-06-17 "Bonsai Core Utilites 0.13.11" +.TH NPC 1 2024-06-17 "Harakit 0.13.11" .SH NAME npc \(en show non-printing characters .\" diff --git a/docs/rpn.1 b/docs/rpn.1 index 7d3b477..f937889 100644 --- a/docs/rpn.1 +++ b/docs/rpn.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH RPN 1 2024-06-17 "Bonsai Core Utilites 0.13.11" +.TH RPN 1 2024-06-17 "Harakit 0.13.11" .SH NAME rpn \(en reverse polish notation evaluation .\" diff --git a/docs/scrut.1 b/docs/scrut.1 index 1e17f7e..541dcf2 100644 --- a/docs/scrut.1 +++ b/docs/scrut.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH SCRUT 1 2024-06-06 "Bonsai Core Utilites 0.13.11" +.TH SCRUT 1 2024-06-06 "Harakit 0.13.11" .SH NAME scrut \(en scrutinize file properties .SH SYNOPSIS diff --git a/docs/str.1 b/docs/str.1 index 6f01125..c4d68cc 100644 --- a/docs/str.1 +++ b/docs/str.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH STR 1 2024-06-17 "Bonsai Core Utilites 0.13.11" +.TH STR 1 2024-06-17 "Harakit 0.13.11" .SH NAME str \(en test string arguments .\" diff --git a/docs/strcmp.1 b/docs/strcmp.1 index 2ff08f6..781fc92 100644 --- a/docs/strcmp.1 +++ b/docs/strcmp.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH STRCMP 1 2024-06-17 "Bonsai Core Utilites 0.13.11" +.TH STRCMP 1 2024-06-17 "Harakit 0.13.11" .SH NAME strcmp \(en compare strings .\" diff --git a/docs/swab.1 b/docs/swab.1 index 1c75705..708a59b 100644 --- a/docs/swab.1 +++ b/docs/swab.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH SWAB 1 2024-06-17 "Bonsai Core Utilites 0.13.11" +.TH SWAB 1 2024-06-17 "Harakit 0.13.11" .SH NAME swab \(en swap bytes .\" diff --git a/docs/true.1 b/docs/true.1 index ebf8916..15a4667 100644 --- a/docs/true.1 +++ b/docs/true.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH TRUE 1 2024-06-06 "Bonsai Core Utilites 0.13.11" +.TH TRUE 1 2024-06-06 "Harakit 0.13.11" .SH NAME true \(en do nothing, successfully .\" From 0fc9a6b533d740214b4364a52bbebe86f81c7dee Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 23 Jun 2024 23:47:29 -0600 Subject: [PATCH 119/343] Makefile, docs: programmatically generate version for docs (i got tired of doing it myself) --- Makefile | 13 ++++++++++--- docs/dj.1 | 2 +- docs/false.1 | 2 +- docs/fop.1 | 2 +- docs/hru.1 | 2 +- docs/intcmp.1 | 2 +- docs/mm.1 | 2 +- docs/npc.1 | 2 +- docs/rpn.1 | 2 +- docs/scrut.1 | 2 +- docs/str.1 | 2 +- docs/strcmp.1 | 2 +- docs/swab.1 | 2 +- docs/true.1 | 2 +- 14 files changed, 23 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index 7756c56..9ecbedb 100644 --- a/Makefile +++ b/Makefile @@ -29,12 +29,12 @@ RUSTLIBS = --extern getopt=build/o/libgetopt.rlib \ CFLAGS += -I$(SYSEXITS) .PHONY: all -all: dj false fop hru intcmp mm npc rpn scrut str strcmp swab true +all: docs dj false fop hru intcmp mm npc rpn scrut str strcmp swab true # keep build/include until bindgen(1) has stdin support # https://github.com/rust-lang/rust-bindgen/issues/2703 build: - mkdir -p build/bin build/include build/lib build/o build/test + mkdir -p build/bin build/docs build/include build/lib build/o build/test .PHONY: clean clean: @@ -43,7 +43,7 @@ clean: dist: all mkdir -p $(DESTDIR)/$(PREFIX)/bin $(DESTDIR)/$(PREFIX)/share/man/man1 cp build/bin/* $(DESTDIR)/$(PREFIX)/bin - cp docs/*.1 $(DESTDIR)/$(PREFIX)/$(MANDIR)/man1 + cp build/docs/*.1 $(DESTDIR)/$(PREFIX)/$(MANDIR)/man1 .PHONY: install install: dist @@ -54,6 +54,13 @@ test: build tests/posix-compat.sh $(RUSTC) --test src/getopt-rs/lib.rs -o build/test/getopt +.PHONY: docs +docs: docs/ build + for file in docs/*; do original="$$(sed -n '/^\.TH/p' <"$$file")"; \ + title="$$(printf '%s\n' "$$original" | sed \ + "s/X\.X\.X/$$(git describe --tags --long | cut -d'-' -f1)/g")"; \ + sed "s/$$original/$$title/g" <"$$file" >"build/$$file"; done + .PHONY: rustlibs rustlibs: build/o/libsysexits.rlib build/o/libgetopt.rlib \ build/o/libstrerror.rlib diff --git a/docs/dj.1 b/docs/dj.1 index 5cf2368..7031ccf 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH DJ 1 2024-06-17 "Harakit 0.13.11" +.TH DJ 1 2024-06-17 "Harakit X.X.X" .SH NAME dj \(en disk jockey .\" diff --git a/docs/false.1 b/docs/false.1 index 1d6691b..b940909 100644 --- a/docs/false.1 +++ b/docs/false.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH FALSE 1 2024-06-06 "Harakit 0.13.11" +.TH FALSE 1 2024-06-06 "Harakit X.X.X" .SH NAME false \(en do nothing, unsuccessfully .\" diff --git a/docs/fop.1 b/docs/fop.1 index 2d54720..d777c68 100644 --- a/docs/fop.1 +++ b/docs/fop.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH FOP 1 2024-06-17 "Harakit 0.13.11" +.TH FOP 1 2024-06-17 "Harakit X.X.X" .SH NAME fop \(en field operator .\" diff --git a/docs/hru.1 b/docs/hru.1 index eb0ce5e..6929d51 100644 --- a/docs/hru.1 +++ b/docs/hru.1 @@ -3,7 +3,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH HRU 1 2024-06-17 "Harakit 0.13.11" +.TH HRU 1 2024-06-17 "Harakit X.X.X" .SH NAME hru \(en human readable units .\" diff --git a/docs/intcmp.1 b/docs/intcmp.1 index 19c2c75..034a4fd 100644 --- a/docs/intcmp.1 +++ b/docs/intcmp.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH INTCMP 1 2024-06-06 "Harakit 0.13.11" +.TH INTCMP 1 2024-06-06 "Harakit X.X.X" .SH NAME intcmp \(en compare integers .\" diff --git a/docs/mm.1 b/docs/mm.1 index 0f1b97b..2ff9f44 100644 --- a/docs/mm.1 +++ b/docs/mm.1 @@ -3,7 +3,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH MM 1 2024-06-17 "Harakit 0.13.11" +.TH MM 1 2024-06-17 "Harakit X.X.X" .SH NAME mm \(en middleman .\" diff --git a/docs/npc.1 b/docs/npc.1 index 03890fb..3e7af39 100644 --- a/docs/npc.1 +++ b/docs/npc.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH NPC 1 2024-06-17 "Harakit 0.13.11" +.TH NPC 1 2024-06-17 "Harakit X.X.X" .SH NAME npc \(en show non-printing characters .\" diff --git a/docs/rpn.1 b/docs/rpn.1 index f937889..8c8cd84 100644 --- a/docs/rpn.1 +++ b/docs/rpn.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH RPN 1 2024-06-17 "Harakit 0.13.11" +.TH RPN 1 2024-06-17 "Harakit X.X.X" .SH NAME rpn \(en reverse polish notation evaluation .\" diff --git a/docs/scrut.1 b/docs/scrut.1 index 541dcf2..56383b8 100644 --- a/docs/scrut.1 +++ b/docs/scrut.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH SCRUT 1 2024-06-06 "Harakit 0.13.11" +.TH SCRUT 1 2024-06-06 "Harakit X.X.X" .SH NAME scrut \(en scrutinize file properties .SH SYNOPSIS diff --git a/docs/str.1 b/docs/str.1 index c4d68cc..22ffea1 100644 --- a/docs/str.1 +++ b/docs/str.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH STR 1 2024-06-17 "Harakit 0.13.11" +.TH STR 1 2024-06-17 "Harakit X.X.X" .SH NAME str \(en test string arguments .\" diff --git a/docs/strcmp.1 b/docs/strcmp.1 index 781fc92..0ad21b2 100644 --- a/docs/strcmp.1 +++ b/docs/strcmp.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH STRCMP 1 2024-06-17 "Harakit 0.13.11" +.TH STRCMP 1 2024-06-17 "Harakit X.X.X" .SH NAME strcmp \(en compare strings .\" diff --git a/docs/swab.1 b/docs/swab.1 index 708a59b..72f0f19 100644 --- a/docs/swab.1 +++ b/docs/swab.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH SWAB 1 2024-06-17 "Harakit 0.13.11" +.TH SWAB 1 2024-06-17 "Harakit X.X.X" .SH NAME swab \(en swap bytes .\" diff --git a/docs/true.1 b/docs/true.1 index 15a4667..97af65b 100644 --- a/docs/true.1 +++ b/docs/true.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH TRUE 1 2024-06-06 "Harakit 0.13.11" +.TH TRUE 1 2024-06-06 "Harakit X.X.X" .SH NAME true \(en do nothing, successfully .\" From d3f5246242984a1ff03982d92adb0d2b8fb465af Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 26 Jun 2024 11:36:52 -0600 Subject: [PATCH 120/343] dj(1), dj.1: remove the unnecessary -d and -q --- docs/dj.1 | 29 +++-------------------------- src/dj.c | 41 ++++++++--------------------------------- 2 files changed, 11 insertions(+), 59 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 7d28ac8..5de56eb 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -11,7 +11,7 @@ dj \(en disk jockey .SH SYNOPSIS dj -.RB ( -AdHnq ) +.RB ( -AHn ) .RB ( -a .RB [ byte ]) .RB ( -c @@ -76,18 +76,11 @@ with a null byte instead of a character. .IP \fB-c\fP Specifies a number of reads to make. The default is 0, in which case the input is read until a partial or empty read is made. -.IP \fB-d\fP -Prints invocation information before program execution as described in the -DIAGNOSTICS section. Each invocation increments the debug level of the -program. .IP \fB-H\fP Prints diagnostics messages in a human-readable manner as described in the DIAGNOSTICS section. .IP \fB-n\fP Retries failed reads once before exiting. -.IP \fB-q\fP -Suppresses error messages which print when a read or write is partial or -empty. Each invocation decrements the debug level of the program. .\" .SH STANDARD INPUT @@ -100,10 +93,8 @@ one or more of the input files is \(lq-\(rq. .\" .SH DIAGNOSTICS -On a partial or empty read, unless the -.B -q -option is specified, a diagnostic message is printed. Then, the program exits -unless the +On a partial or empty read a diagnostic message is printed. Then, the program +exits unless the .B -n option is specified. @@ -128,20 +119,6 @@ option may be specified. In this event, the following format is used instead: {ASCII line feed} .RE -If the -.B -d -option is specified, debug information will be printed at the beginning of -execution. This output contains information regarding how the program was -invoked. The following example is the result of running the program with -.B -d -as the only argument: - -.RS -argv0=dj -in= ibs=1024 skip=0 align=ff count=0 -out= obs=1024 seek=0 debug= 3 noerror=0 -.RE - In non-recoverable errors that don\(cqt pertain to the read-write cycle, a diagnostic message is printed and the program exits with the appropriate .BR sysexits.h (3) diff --git a/src/dj.c b/src/dj.c index 8a6732c..27c160a 100644 --- a/src/dj.c +++ b/src/dj.c @@ -59,14 +59,6 @@ struct Io{ /* pointer to chosen formatting */ /* (-H) */ static char *fmt_output; /* fmt_asv (default) or fmt_human (-H) */ -/* (-dq) */ static char debug; /* - * -d increments dj -qq | 0 - no diagnostic output whatsoever - * -q decrements dj -q | 1 - typical output without - * | notifications on partial reads or - * | writes - * dj | 2 - typical output (default) - * dj -d | 3 - verbose status messages */ - /* (-n) */ static char noerror; /* 0 - exits on partial reads or writes * (default) * 1 - retries on partial reads/writes @@ -84,7 +76,6 @@ static int write_flags = O_WRONLY | O_CREAT; /* dd(1). */ #define setdefaults do{ \ align = -1; \ count = 0; \ - debug = 2; \ fmt_output = fmt_asv; \ noerror = 0; \ ep[0].fl = read_flags; \ @@ -284,14 +275,13 @@ oserr(char *s){ } /* Prints statistics regarding the use of dj, particularly partially and - * completely read and written records, accessing debug, ep, and fmt_output. */ + * completely read and written records, accessing ep and fmt_output. */ static void output(void){ - if(debug >= 1) - fprintf(stderr, fmt_output, - ep[0].rec, ep[0].prec, ep[1].rec, ep[1].prec, - ep[0].bytes, ep[1].bytes); + fprintf(stderr, fmt_output, + ep[0].rec, ep[0].prec, ep[1].rec, ep[1].prec, + ep[0].bytes, ep[1].bytes); return; } @@ -342,10 +332,8 @@ int main(int argc, char *argv[]){ terminate(ep); return oserr(optarg); case 'A': align = '\0'; break; - case 'd': ++debug; break; case 'n': noerror = 1; break; case 'H': fmt_output = fmt_human; break; - case 'q': --debug; break; case 'a': if(optarg[0] != '\0' && optarg[1] == '\0'){ align = optarg[0]; @@ -367,15 +355,6 @@ int main(int argc, char *argv[]){ } } - if(debug >= 3) - fprintf(stderr, - "argv0=%s\n" - "in=%s\tibs=%d\tskip=%ld\talign=%hhx\tcount=%d\n" - "out=%s\tobs=%d\tseek=%ld\tdebug=%2d\tnoerror=%d\n", - program_name, - ep[0].fn, ep[0].bs, ep[0].seek, align, count, - ep[1].fn, ep[1].bs, ep[1].seek, debug, noerror); - if(argc > optind){ terminate(ep); return usage(); @@ -404,10 +383,8 @@ int main(int argc, char *argv[]){ break; else if(ep[0].bufuse < ep[0].bs){ ++ep[0].prec; - if(debug >= 2){ - fprintf(stderr, "%s: Partial read:\n\t", program_name); - output(); - } + fprintf(stderr, "%s: Partial read:\n\t", program_name); + output(); if(!noerror) count = 1; if(align >= 0) @@ -432,10 +409,8 @@ int main(int argc, char *argv[]){ break; }else if(c > ep[1].bufuse && ep[1].bufuse > 0){ ep[1].prec += 1; - if(debug >= 2){ - fprintf(stderr, "%s: Partial write:\n\t", program_name); - output(); - } + fprintf(stderr, "%s: Partial write:\n\t", program_name); + output(); if(!noerror) count = 1; }else if(ep[1].bufuse == 0 && c < ep[1].bs) From 95f7992e0fbdbabac78c397c357523e85c2cc576 Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 26 Jun 2024 11:39:34 -0600 Subject: [PATCH 121/343] dj(1): fix usage text to be consistent with man page --- src/dj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dj.c b/src/dj.c index 27c160a..d4462e8 100644 --- a/src/dj.c +++ b/src/dj.c @@ -303,7 +303,7 @@ parse(char *s){ static int usage(void){ - fprintf(stderr, "Usage: %s (-AdfHqQ) (-a [byte]) (-c [count])\n" + fprintf(stderr, "Usage: %s (-AHn) (-a [byte]) (-c [count])\n" "\t(-i [input file]) (-b [input block size]) (-s [input offset])\n" "\t(-o [output file]) (-B [output block size]) (-S [output offset])\n", program_name); From 45a880455d440deb05034f7562cb756eae5287d7 Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 26 Jun 2024 12:22:33 -0600 Subject: [PATCH 122/343] dj(1): refactor to build again and to get rid of globals --- src/dj.c | 81 +++++++++++++++++++++++--------------------------------- 1 file changed, 33 insertions(+), 48 deletions(-) diff --git a/src/dj.c b/src/dj.c index d4462e8..e41f350 100644 --- a/src/dj.c +++ b/src/dj.c @@ -25,6 +25,8 @@ #include /* EX_OK, EX_USAGE */ #include /* close(2), getopt(3), lseek(2), read(2), write(2), * optarg, optind, STDIN_FILENO, STDOUT_FILENO */ +#include /* S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, + S_IWUSR */ extern int errno; /* dj uses two structures that respectively correspond to the reading and @@ -41,47 +43,17 @@ struct Io{ int prec; /* partial records processed */ int rec; /* records processed */ long seek; /* bytes to seek/skip (will be 0 after skippage) (-sS) */ -} ep[2]; /* "engineered pipe"; also "extended play", for the deejay */ +}; -/* Additionally, the following global variables are used to store user options. - */ +/* To be assigned to main:fmt_output and used with output(). */ +static char *fmt_asv = "%d\037%d\036%d\037%d\035%d\036%d\034"; +static char *fmt_human = "%d+%d > %d+%d; %d > %d\n"; -/* (-a) */ static int align; /* Only the lower 8b are used but align is - * negative if no alignment is being done. */ - -/* (-c) */ static int count; /* 0 if dj(1) runs until no more reads are - * possible. */ - -/* ASCII field separator delimited statistics */ - static char *fmt_asv = "%d\037%d\036%d\037%d\035%d\036%d\034"; -/* human-readable statistics */ - static char *fmt_human = "%d+%d > %d+%d; %d > %d\n"; -/* pointer to chosen formatting */ -/* (-H) */ static char *fmt_output; /* fmt_asv (default) or fmt_human (-H) */ - -/* (-n) */ static char noerror; /* 0 - exits on partial reads or writes - * (default) - * 1 - retries on partial reads/writes - * (-n) */ - -/* Non-configurable defaults. */ -#define bs_default 1024 /* GNU dd(1) default; twice POSIX but a neat 2^10 */ static char *program_name = ""; static char *stdin_name = ""; static char *stdout_name = ""; -static int read_flags = O_RDONLY; /* These flags are consistent with Busybox */ -static int write_flags = O_WRONLY | O_CREAT; /* dd(1). */ - -/* Macro to set defaults for user-configurable options. */ -#define setdefaults do{ \ - align = -1; \ - count = 0; \ - fmt_output = fmt_asv; \ - noerror = 0; \ - ep[0].fl = read_flags; \ - Io_setdefaults(&ep[0]); \ - ep[1].fl = write_flags; \ - Io_setdefaults(&ep[1]); }while(0) +static int read_flags = O_RDONLY; /* Consistent with Busybox dd(1). */ +static int write_flags = O_WRONLY | O_CREAT; #define MIN(a, b) (((a) < (b)) ? (a) : (b)) @@ -238,7 +210,7 @@ Io_read(struct Io *io){ static struct Io * Io_setdefaults(struct Io *io){ - io->bs = bs_default; + io->bs = 1024 /* bytes; 1 KiB */; /* GNU dd(1) default; POSIX says 512B */ io->buf = NULL; io->bytes = 0; io->fd = (io->fl == read_flags) ? STDIN_FILENO : STDOUT_FILENO; @@ -275,13 +247,13 @@ oserr(char *s){ } /* Prints statistics regarding the use of dj, particularly partially and - * completely read and written records, accessing ep and fmt_output. */ + * completely read and written records. */ static void -output(void){ +output(struct Io io[2], char *fmt){ - fprintf(stderr, fmt_output, - ep[0].rec, ep[0].prec, ep[1].rec, ep[1].prec, - ep[0].bytes, ep[1].bytes); + fprintf(stderr, fmt, + io[0].rec, io[0].prec, io[1].rec, io[1].prec, + io[0].bytes, io[1].bytes); return; } @@ -312,14 +284,27 @@ usage(void){ } int main(int argc, char *argv[]){ + int align; /* low 8b used, negative if no alignment is being done */ + int count; /* 0 if dj(1) runs until no more reads are possible */ + struct Io ep[2]; /* "engineered pipe"; also "extended play", for the DJ */ + char *fmt_output; /* fmt_asv (default) or fmt_human (-H) */ + char noerror; /* 0=exits (default) 1=retries on partial reads or writes */ int c; int i; - setdefaults; + /* Set defaults. */ + align = -1; + count = 0; + fmt_output = fmt_asv; + noerror = 0; + ep[0].fl = read_flags; + Io_setdefaults(&ep[0]); + ep[1].fl = write_flags; + Io_setdefaults(&ep[1]); if(argc > 0){ program_name = argv[0]; - while((c = getopt(argc, argv, "a:Ab:B:c:di:hHnqs:S:o:")) != -1) + while((c = getopt(argc, argv, "a:Ab:B:c:i:hHns:S:o:")) != -1) switch(c){ case 'i': case 'o': i = (c == 'o'); @@ -369,7 +354,7 @@ int main(int argc, char *argv[]){ }else if(ep[i].seek > 0) switch(Io_fdseek(&ep[i])){ case EX_OK: - output(); + output(ep, fmt_output); terminate(ep); return EX_OK; } @@ -384,7 +369,7 @@ int main(int argc, char *argv[]){ else if(ep[0].bufuse < ep[0].bs){ ++ep[0].prec; fprintf(stderr, "%s: Partial read:\n\t", program_name); - output(); + output(ep, fmt_output); if(!noerror) count = 1; if(align >= 0) @@ -410,7 +395,7 @@ int main(int argc, char *argv[]){ }else if(c > ep[1].bufuse && ep[1].bufuse > 0){ ep[1].prec += 1; fprintf(stderr, "%s: Partial write:\n\t", program_name); - output(); + output(ep, fmt_output); if(!noerror) count = 1; }else if(ep[1].bufuse == 0 && c < ep[1].bs) @@ -420,7 +405,7 @@ int main(int argc, char *argv[]){ }while(ep[0].bufuse > 0); }while(count == 0 || --count > 0); - output(); + output(ep, fmt_output); terminate(ep); return EX_OK; From 66f54982320eb6ca2f47da26c8dac78aaf4aaecc Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 26 Jun 2024 12:40:36 -0600 Subject: [PATCH 123/343] dj(1): refactor Io_fdseek --- src/dj.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/dj.c b/src/dj.c index e41f350..7c0b7c3 100644 --- a/src/dj.c +++ b/src/dj.c @@ -156,18 +156,15 @@ Io_fdopen(struct Io *io, char *fn){ return fd; } -/* Seeks io->seek bytes through *io's file descriptor, (counter-intuitively) - * returning -1 if successful and a sysexits.h exit code if an unrecoverable - * error occurred. io->buf will be cleared of useful bytes and io->seek will - * be set to zero to indicate the seek occurred. */ -static int +/* Seeks io->seek bytes through *io's file descriptor, subtracting the number + * of sought bytes from io->seek. This procedure leaves garbage in io->buf. */ +static void Io_fdseek(struct Io *io){ - int (*op)(int, void *, size_t); - if(!fdisstd(io->fd) && lseek(io->fd, io->seek, SEEK_SET) != -1) - return -1; + if(io->seek != 0 + || (!fdisstd(io->fd) && lseek(io->fd, io->seek, SEEK_SET) != -1)) + return; - /* repeated code to get the condition out of the loop */ if(io->fl == write_flags){ memset(io->buf, '\0', io->bs); /* We're going to cheat and use bufuse as the retval for write(2), @@ -186,12 +183,11 @@ Io_fdseek(struct Io *io){ /* second chance */ io->bufuse = read(io->fd, io->buf, MIN(io->bs, io->seek)); }while((io->seek -= io->bufuse) > 0 && io->bufuse != 0); - }else - return EX_SOFTWARE; + } io->bufuse = 0; - return -1; + return; } /* Reads io->bs bytes from *io's file descriptor into io->buf, storing the @@ -352,11 +348,10 @@ int main(int argc, char *argv[]){ terminate(ep); return EX_OSERR; }else if(ep[i].seek > 0) - switch(Io_fdseek(&ep[i])){ - case EX_OK: - output(ep, fmt_output); + Io_fdseek(&ep[i]); + if(ep[i].seek > 0){ terminate(ep); - return EX_OK; + return oserr(ep[i].fn); } } From b70b356ce5ec6a78f029a8db0df6b5a3d3944827 Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 26 Jun 2024 12:45:50 -0600 Subject: [PATCH 124/343] dj(1): remove Io_buffree --- src/dj.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/dj.c b/src/dj.c index 7c0b7c3..01832a8 100644 --- a/src/dj.c +++ b/src/dj.c @@ -67,8 +67,8 @@ static int write_flags = O_WRONLY | O_CREAT; * particular io[2] used in main. Error conditions are not checked because this * is only used when the program is about to terminate (hence its name). */ #define terminate(io) do{ \ - Io_buffree(&(io)[0]); \ - Io_buffree(&(io)[1]); \ + free((io[0]).buf); \ + free((io[1]).buf); \ Io_fdclose(&(io)[0]); \ Io_fdclose(&(io)[1]); }while(0) @@ -79,15 +79,6 @@ Io_bufalloc(struct Io *io){ return (io->buf = malloc(io->bs * (sizeof *io->buf))); } -/* Frees *io's buffer. Returns io. */ -static struct Io * -Io_buffree(struct Io *io){ - - free(io->buf); - - return io; -} - /* Fills the unused portion of io's buffer with padding, updating io->bufuse. * Returns io. */ static struct Io * From e65f6b650df5323d66ec94e3b8fe5b792f6e5fb5 Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 26 Jun 2024 13:41:24 -0600 Subject: [PATCH 125/343] dj(1): more refactor (get rid of ep pun) --- src/dj.c | 101 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 52 insertions(+), 49 deletions(-) diff --git a/src/dj.c b/src/dj.c index 01832a8..af842a4 100644 --- a/src/dj.c +++ b/src/dj.c @@ -156,6 +156,9 @@ Io_fdseek(struct Io *io){ || (!fdisstd(io->fd) && lseek(io->fd, io->seek, SEEK_SET) != -1)) return; + if(io->fl == write_flags) + memset(io->buf, '\0', io->bs); + if(io->fl == write_flags){ memset(io->buf, '\0', io->bs); /* We're going to cheat and use bufuse as the retval for write(2), @@ -273,7 +276,7 @@ usage(void){ int main(int argc, char *argv[]){ int align; /* low 8b used, negative if no alignment is being done */ int count; /* 0 if dj(1) runs until no more reads are possible */ - struct Io ep[2]; /* "engineered pipe"; also "extended play", for the DJ */ + struct Io io[2]; char *fmt_output; /* fmt_asv (default) or fmt_human (-H) */ char noerror; /* 0=exits (default) 1=retries on partial reads or writes */ int c; @@ -284,10 +287,10 @@ int main(int argc, char *argv[]){ count = 0; fmt_output = fmt_asv; noerror = 0; - ep[0].fl = read_flags; - Io_setdefaults(&ep[0]); - ep[1].fl = write_flags; - Io_setdefaults(&ep[1]); + io[0].fl = read_flags; + Io_setdefaults(&io[0]); + io[1].fl = write_flags; + Io_setdefaults(&io[1]); if(argc > 0){ program_name = argv[0]; @@ -296,12 +299,12 @@ int main(int argc, char *argv[]){ case 'i': case 'o': i = (c == 'o'); if(optarg[0] == '-' && optarg[1] == '\0'){ /* optarg == "-" */ - ep[i].fd = (i == 0) ? STDIN_FILENO : STDOUT_FILENO; - ep[i].fn = (i == 0) ? stdin_name : stdout_name; + io[i].fd = (i == 0) ? STDIN_FILENO : STDOUT_FILENO; + io[i].fn = (i == 0) ? stdin_name : stdout_name; break; - }else if(Io_fdopen(&ep[i], optarg) != -1) + }else if(Io_fdopen(&io[i], optarg) != -1) break; - terminate(ep); + terminate(io); return oserr(optarg); case 'A': align = '\0'; break; case 'n': noerror = 1; break; @@ -317,82 +320,82 @@ int main(int argc, char *argv[]){ break; i = isupper(c); c = tolower(c); - if((c == 'b' && (ep[i].bs = parse(optarg)) > 0) - || (c == 's' && (ep[i].seek = parse(optarg)) >= 0)) + if((c == 'b' && (io[i].bs = parse(optarg)) > 0) + || (c == 's' && (io[i].seek = parse(optarg)) >= 0)) break; /* FALLTHROUGH */ default: - terminate(ep); + terminate(io); return usage(); } } if(argc > optind){ - terminate(ep); + terminate(io); return usage(); } - for(i = 0; i <= 1; ++i){ - if(Io_bufalloc(&ep[i]) == NULL){ + for(i = 0; i < 2; ++i){ + if(Io_bufalloc(&io[i]) == NULL){ fprintf(stderr, "%s: Failed to allocate %d bytes\n", - program_name, ep[i].bs); - terminate(ep); + program_name, io[i].bs); + terminate(io); return EX_OSERR; - }else if(ep[i].seek > 0) - Io_fdseek(&ep[i]); - if(ep[i].seek > 0){ - terminate(ep); - return oserr(ep[i].fn); + }else if(io[i].seek > 0) + Io_fdseek(&io[i]); + if(io[i].seek > 0){ + terminate(io); + return oserr(io[i].fn); } } do{ /* read */ - Io_read(&ep[0]); - if(!noerror && ep[0].bufuse == 0) - Io_read(&ep[0]); /* second chance */ - if(ep[0].bufuse == 0) /* that's all she wrote */ + Io_read(&io[0]); + if(!noerror && io[0].bufuse == 0) + Io_read(&io[0]); /* second chance */ + if(io[0].bufuse == 0) /* that's all she wrote */ break; - else if(ep[0].bufuse < ep[0].bs){ - ++ep[0].prec; + else if(io[0].bufuse < io[0].bs){ + ++io[0].prec; fprintf(stderr, "%s: Partial read:\n\t", program_name); - output(ep, fmt_output); + output(io, fmt_output); if(!noerror) count = 1; if(align >= 0) - Io_bufrpad(&ep[0], align); + Io_bufrpad(&io[0], align); }else - ++ep[0].rec; + ++io[0].rec; /* write */ - do{ if(ep[1].bs > ep[0].bs){ /* io[1].bs > io[0].bs */ - Io_bufxapp(&ep[1], &ep[0]); - if(ep[0].bs + ep[1].bufuse <= ep[1].bs && count != 1) + do{ if(io[1].bs > io[0].bs){ /* io[1].bs > io[0].bs */ + Io_bufxapp(&io[1], &io[0]); + if(io[0].bs + io[1].bufuse <= io[1].bs && count != 1) continue; /* we could write more */ }else - Io_bufxfer(&ep[1], &ep[0], MIN(ep[0].bufuse, ep[1].bs)); + Io_bufxfer(&io[1], &io[0], MIN(io[0].bufuse, io[1].bs)); - c = ep[1].bufuse; - Io_write(&ep[1]); - if(!noerror && ep[1].bufuse == c) - Io_write(&ep[1]); /* second chance */ - if(c == ep[1].bufuse){ /* no more love */ + c = io[1].bufuse; + Io_write(&io[1]); + if(!noerror && io[1].bufuse == c) + Io_write(&io[1]); /* second chance */ + if(c == io[1].bufuse){ /* no more love */ count = 1; break; - }else if(c > ep[1].bufuse && ep[1].bufuse > 0){ - ep[1].prec += 1; + }else if(c > io[1].bufuse && io[1].bufuse > 0){ + io[1].prec += 1; fprintf(stderr, "%s: Partial write:\n\t", program_name); - output(ep, fmt_output); + output(io, fmt_output); if(!noerror) count = 1; - }else if(ep[1].bufuse == 0 && c < ep[1].bs) - ++ep[1].prec; + }else if(io[1].bufuse == 0 && c < io[1].bs) + ++io[1].prec; else - ++ep[1].rec; - }while(ep[0].bufuse > 0); + ++io[1].rec; + }while(io[0].bufuse > 0); }while(count == 0 || --count > 0); - output(ep, fmt_output); - terminate(ep); + output(io, fmt_output); + terminate(io); return EX_OK; } From fb74e7bef036d266b34fc93621d6889bfa31b61d Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 26 Jun 2024 13:45:36 -0600 Subject: [PATCH 126/343] dj(1), dj.1: Remove -A (use -a "\0") (see #101) --- docs/dj.1 | 10 +++------- src/dj.c | 7 +++---- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 5de56eb..1494827 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -11,7 +11,7 @@ dj \(en disk jockey .SH SYNOPSIS dj -.RB ( -AHn ) +.RB ( -Hn ) .RB ( -a .RB [ byte ]) .RB ( -c @@ -67,12 +67,8 @@ Seeks a number of bytes through the output before starting to write from the input. If the output is a stream, null characters are printed. .IP \fB-a\fP Accepts a single literal byte with which the input buffer is padded in the event -of an incomplete read from the input file. -.IP \fB-A\fP -Specifying this option pads the input buffer with null bytes in the event of an -incomplete read. This is equivalent to specifying -.B -a -with a null byte instead of a character. +of an incomplete read from the input file. If the option argument is empty, the +null byte is used. .IP \fB-c\fP Specifies a number of reads to make. The default is 0, in which case the input is read until a partial or empty read is made. diff --git a/src/dj.c b/src/dj.c index af842a4..b45513e 100644 --- a/src/dj.c +++ b/src/dj.c @@ -265,7 +265,7 @@ parse(char *s){ static int usage(void){ - fprintf(stderr, "Usage: %s (-AHn) (-a [byte]) (-c [count])\n" + fprintf(stderr, "Usage: %s (-Hn) (-a [byte]) (-c [count])\n" "\t(-i [input file]) (-b [input block size]) (-s [input offset])\n" "\t(-o [output file]) (-B [output block size]) (-S [output offset])\n", program_name); @@ -294,7 +294,7 @@ int main(int argc, char *argv[]){ if(argc > 0){ program_name = argv[0]; - while((c = getopt(argc, argv, "a:Ab:B:c:i:hHns:S:o:")) != -1) + while((c = getopt(argc, argv, "a:b:B:c:i:hHns:S:o:")) != -1) switch(c){ case 'i': case 'o': i = (c == 'o'); @@ -306,11 +306,10 @@ int main(int argc, char *argv[]){ break; terminate(io); return oserr(optarg); - case 'A': align = '\0'; break; case 'n': noerror = 1; break; case 'H': fmt_output = fmt_human; break; case 'a': - if(optarg[0] != '\0' && optarg[1] == '\0'){ + if(optarg[0] == '\0' || optarg[1] == '\0'){ align = optarg[0]; break; } From 2cfae0e8d7595964a492bf03f601512f0c7d15be Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 26 Jun 2024 15:15:37 -0600 Subject: [PATCH 127/343] dj(1): refactor (remove Io_setdefaults and other stuff) --- src/dj.c | 66 ++++++++++++++++++++++++-------------------------------- 1 file changed, 28 insertions(+), 38 deletions(-) diff --git a/src/dj.c b/src/dj.c index b45513e..5632645 100644 --- a/src/dj.c +++ b/src/dj.c @@ -16,7 +16,6 @@ * along with this program. If not, see https://www.gnu.org/licenses/. */ -#include /* isupper(3), tolower(3) */ #include /* errno */ #include /* open(2) */ #include /* fprintf(3), stderr */ @@ -29,6 +28,8 @@ S_IWUSR */ extern int errno; +char *program_name = "dj"; + /* dj uses two structures that respectively correspond to the reading and * writing ends of its jockeyed "pipe". User-configurable members are noted * with their relevant options. */ @@ -49,9 +50,9 @@ struct Io{ static char *fmt_asv = "%d\037%d\036%d\037%d\035%d\036%d\034"; static char *fmt_human = "%d+%d > %d+%d; %d > %d\n"; -static char *program_name = ""; static char *stdin_name = ""; static char *stdout_name = ""; + static int read_flags = O_RDONLY; /* Consistent with Busybox dd(1). */ static int write_flags = O_WRONLY | O_CREAT; @@ -195,23 +196,6 @@ Io_read(struct Io *io){ return io; } -/* Sets the variables in a struct *io to the defaults. Identifies the read/ - * write ends of the "pipe" by checking io->fl. Returns io. */ -static struct Io * -Io_setdefaults(struct Io *io){ - - io->bs = 1024 /* bytes; 1 KiB */; /* GNU dd(1) default; POSIX says 512B */ - io->buf = NULL; - io->bytes = 0; - io->fd = (io->fl == read_flags) ? STDIN_FILENO : STDOUT_FILENO; - io->fn = (io->fl == read_flags) ? stdin_name : stdout_name; - io->prec = 0; - io->rec = 0; - io->seek = 0; - - return io; -} - /* Writes io->bufuse units from io->buf to io->fd, permuting any unwritten * bytes to the start of io->buf and updating io->bufuse. If io->bufuse doesn't * change, errno will probably be set. Returns io. */ @@ -263,12 +247,12 @@ parse(char *s){ } static int -usage(void){ +usage(char *s){ fprintf(stderr, "Usage: %s (-Hn) (-a [byte]) (-c [count])\n" "\t(-i [input file]) (-b [input block size]) (-s [input offset])\n" "\t(-o [output file]) (-B [output block size]) (-S [output offset])\n", - program_name); + s); return EX_USAGE; } @@ -276,31 +260,37 @@ usage(void){ int main(int argc, char *argv[]){ int align; /* low 8b used, negative if no alignment is being done */ int count; /* 0 if dj(1) runs until no more reads are possible */ + char *fmt_output; /* == fmt_asv (default) or fmt_human (-H) */ + size_t i; /* side of io being modified */ struct Io io[2]; - char *fmt_output; /* fmt_asv (default) or fmt_human (-H) */ char noerror; /* 0=exits (default) 1=retries on partial reads or writes */ - int c; - int i; /* Set defaults. */ align = -1; count = 0; fmt_output = fmt_asv; noerror = 0; - io[0].fl = read_flags; - Io_setdefaults(&io[0]); - io[1].fl = write_flags; - Io_setdefaults(&io[1]); + for(i = 0; i < 2; ++i){ + io[i].bs = 1024 /* 1 KiB */; /* GNU dd(1) default; POSIX says 512B */ + io[i].bytes = 0; + io[i].fd = i ? STDIN_FILENO : STDOUT_FILENO; + io[i].fn = i ? stdin_name : stdout_name; + io[i].fl = i ? read_flags : write_flags; + io[i].prec = 0; + io[i].rec = 0; + io[i].seek = 0; + } if(argc > 0){ + int c; + program_name = argv[0]; while((c = getopt(argc, argv, "a:b:B:c:i:hHns:S:o:")) != -1) switch(c){ - case 'i': case 'o': - i = (c == 'o'); + case 'i': case 'o': i = (c == 'o') if(optarg[0] == '-' && optarg[1] == '\0'){ /* optarg == "-" */ - io[i].fd = (i == 0) ? STDIN_FILENO : STDOUT_FILENO; - io[i].fn = (i == 0) ? stdin_name : stdout_name; + io[i].fd = i ? STDIN_FILENO : STDOUT_FILENO; + io[i].fn = i ? stdin_name : stdout_name; break; }else if(Io_fdopen(&io[i], optarg) != -1) break; @@ -314,24 +304,24 @@ int main(int argc, char *argv[]){ break; } /* FALLTHROUGH */ - case 'c': case 'b': case 's': case 'B': case 'S': + case 'c': case 'b': case 's': case 'B': case 'S': /* numbers */ if(c == 'c' && (count = parse(optarg)) >= 0) break; - i = isupper(c); - c = tolower(c); + i = (c >= 'A' && c <= 'Z'); /* uppercase changes output */ + c &= 0x20 /* 0b 0010 0000 */; /* (ASCII) make lowercase */ if((c == 'b' && (io[i].bs = parse(optarg)) > 0) || (c == 's' && (io[i].seek = parse(optarg)) >= 0)) break; /* FALLTHROUGH */ default: terminate(io); - return usage(); + return usage(program_name); } } if(argc > optind){ terminate(io); - return usage(); + return usage(program_name); } for(i = 0; i < 2; ++i){ @@ -366,7 +356,7 @@ int main(int argc, char *argv[]){ ++io[0].rec; /* write */ - do{ if(io[1].bs > io[0].bs){ /* io[1].bs > io[0].bs */ + do{ if(io[1].bs > io[0].bs){ Io_bufxapp(&io[1], &io[0]); if(io[0].bs + io[1].bufuse <= io[1].bs && count != 1) continue; /* we could write more */ From 3a66022c6d735a3def3e52f4883178dfafe6d24f Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 26 Jun 2024 15:28:02 -0600 Subject: [PATCH 128/343] dj(1): more refactor (get rid of the c scratch variable, use scoping) --- src/dj.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/dj.c b/src/dj.c index 5632645..a9e7cdf 100644 --- a/src/dj.c +++ b/src/dj.c @@ -287,7 +287,7 @@ int main(int argc, char *argv[]){ program_name = argv[0]; while((c = getopt(argc, argv, "a:b:B:c:i:hHns:S:o:")) != -1) switch(c){ - case 'i': case 'o': i = (c == 'o') + case 'i': case 'o': i = (c == 'o'); if(optarg[0] == '-' && optarg[1] == '\0'){ /* optarg == "-" */ io[i].fd = i ? STDIN_FILENO : STDOUT_FILENO; io[i].fn = i ? stdin_name : stdout_name; @@ -356,27 +356,30 @@ int main(int argc, char *argv[]){ ++io[0].rec; /* write */ - do{ if(io[1].bs > io[0].bs){ + do{ + int t; + + if(io[1].bs > io[0].bs){ Io_bufxapp(&io[1], &io[0]); if(io[0].bs + io[1].bufuse <= io[1].bs && count != 1) continue; /* we could write more */ }else Io_bufxfer(&io[1], &io[0], MIN(io[0].bufuse, io[1].bs)); - c = io[1].bufuse; + t = io[1].bufuse; Io_write(&io[1]); - if(!noerror && io[1].bufuse == c) + if(!noerror && io[1].bufuse == t) Io_write(&io[1]); /* second chance */ - if(c == io[1].bufuse){ /* no more love */ + if(t == io[1].bufuse){ /* no more love */ count = 1; break; - }else if(c > io[1].bufuse && io[1].bufuse > 0){ + }else if(t > io[1].bufuse && io[1].bufuse > 0){ io[1].prec += 1; fprintf(stderr, "%s: Partial write:\n\t", program_name); output(io, fmt_output); if(!noerror) count = 1; - }else if(io[1].bufuse == 0 && c < io[1].bs) + }else if(io[1].bufuse == 0 && t < io[1].bs) ++io[1].prec; else ++io[1].rec; From 2f87ad948f530f095b5821a9e60f4cd857df6a4e Mon Sep 17 00:00:00 2001 From: emma Date: Thu, 27 Jun 2024 14:04:31 -0600 Subject: [PATCH 129/343] strerror.rs(3), getopt.rs(3): renames --- Makefile | 14 +++++++------- src/{getopt.rs => libgetopt.rs} | 0 src/{strerror.rs => libstrerror.rs} | 0 3 files changed, 7 insertions(+), 7 deletions(-) rename src/{getopt.rs => libgetopt.rs} (100%) rename src/{strerror.rs => libstrerror.rs} (100%) diff --git a/Makefile b/Makefile index 2188b41..8109cd6 100644 --- a/Makefile +++ b/Makefile @@ -51,23 +51,23 @@ install: dist .PHONY: test test: build /tmp/getopt + /tmp/getopt tests/posix-compat.sh -/tmp/getopt: src/getopt.rs - $(RUSTC) --test -o /tmp/getopt src/getopt.rs - /tmp/getopt +/tmp/getopt: src/libgetopt.rs + $(RUSTC) --test -o /tmp/getopt src/libgetopt.rs .PHONY: rustlibs rustlibs: build/o/libsysexits.rlib build/o/libgetopt.rlib \ build/o/libstrerror.rlib -build/o/libgetopt.rlib: build src/getopt.rs +build/o/libgetopt.rlib: build src/libgetopt.rs $(RUSTC) $(RUSTFLAGS) --crate-type=lib --crate-name=getopt \ - -o $@ src/getopt.rs + -o $@ src/libgetopt.rs -build/o/libstrerror.rlib: build src/strerror.rs +build/o/libstrerror.rlib: build src/libstrerror.rs $(RUSTC) $(RUSTFLAGS) --crate-type=lib -o $@ \ - src/strerror.rs + src/libstrerror.rs # bandage solution until bindgen(1) gets stdin support build/o/libsysexits.rlib: build $(SYSEXITS)sysexits.h diff --git a/src/getopt.rs b/src/libgetopt.rs similarity index 100% rename from src/getopt.rs rename to src/libgetopt.rs diff --git a/src/strerror.rs b/src/libstrerror.rs similarity index 100% rename from src/strerror.rs rename to src/libstrerror.rs From d07bb7da416b7bbefaae1d9df7402e27a319fc80 Mon Sep 17 00:00:00 2001 From: DTB Date: Fri, 28 Jun 2024 08:33:31 -0600 Subject: [PATCH 130/343] swab(1): untested move to new getopt bindings --- src/swab.rs | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/swab.rs b/src/swab.rs index ca944d9..d997ddf 100644 --- a/src/swab.rs +++ b/src/swab.rs @@ -49,20 +49,16 @@ fn main() -> ExitCode { 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]); } - } + while let Some(opt) = argv.getopt("fw:") { + match opt.opt() { + Ok("f") => force = true, + Ok("w") => { + match arg.parse::() { + Ok(w) if w % 2 == 0 => { wordsize = w; () }, + _ => { return usage(&argv[0]); }, + } + }, + _ => { return usage(&argv[0]); } } } From 50bbee10a9b7403893dd64ae527fb852a70edfab Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 28 Jun 2024 10:22:20 -0600 Subject: [PATCH 131/343] libgetopt.rs(3): fixes typecasting for ARM devices --- src/libgetopt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libgetopt.rs b/src/libgetopt.rs index ee8cafa..8064c81 100644 --- a/src/libgetopt.rs +++ b/src/libgetopt.rs @@ -88,7 +88,7 @@ impl GetOpt for Vec { /* god knows what this does */ let boxed = Box::into_raw(c_strings.into_boxed_slice()); - let argv = boxed as *const *mut i8; + let argv = boxed as *const *mut c_char; /* operations are separated out so that everything lives long enough */ let opts = CString::new(optstring).unwrap().into_raw(); From e341c38cd63941e65ee32a91c9c9c653d4b761fb Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 29 Jun 2024 05:18:20 -0600 Subject: [PATCH 132/343] docs, src: updates usage text for utilities --- docs/dj.1 | 26 +++++++++----------------- docs/intcmp.1 | 4 +--- docs/mm.1 | 8 +++----- docs/npc.1 | 2 +- docs/scrut.1 | 4 ++-- docs/str.1 | 3 +-- docs/strcmp.1 | 3 +-- docs/swab.1 | 14 +++++--------- src/dj.c | 6 +++--- src/intcmp.c | 2 +- src/mm.c | 2 +- src/npc.c | 2 +- src/scrut.c | 2 +- src/str.c | 2 +- src/strcmp.c | 2 +- src/swab.rs | 2 +- 16 files changed, 33 insertions(+), 51 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 7031ccf..4b0b5b1 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -11,25 +11,17 @@ dj \(en disk jockey .SH SYNOPSIS dj -.RB ( -AdHnq ) -.RB ( -a -.RB [ byte ]) -.RB ( -c -.RB [ count ]) +.RB [ -AdHnq ] +.RB [ -a\ byte ] +.RB [ -c\ count ] -.RB ( -i -[\fBinput file\fP]) -.RB ( -b -[\fBinput block size\fP]) -.RB ( -s -[\fBinput offset\fP]) +.RB [ -i\ input_file ] +.RB [ -b\ input_block_size ] +.RB [ -s\ input_offset ] -.RB ( -o -[\fBoutput file\fP]) -.RB ( -B -[\fBoutput block size\fP]) -.RB ( -S -[\fBoutput offset\fP]) +.RB [ -o\ output_file ] +.RB [ -B\ output_block_size ] +.RB [ -S\ output_offset ] .\" .SH DESCRIPTION diff --git a/docs/intcmp.1 b/docs/intcmp.1 index 034a4fd..b90f23a 100644 --- a/docs/intcmp.1 +++ b/docs/intcmp.1 @@ -11,9 +11,7 @@ intcmp \(en compare integers .SH SYNOPSIS intcmp -.RB ( -egl ) -.RB [ integer ] -.RB [ integer... ] +.RB [ -egl ]\ integer\ integer... .SH DESCRIPTION Compare integers to each other. .\" diff --git a/docs/mm.1 b/docs/mm.1 index 2ff9f44..735f9df 100644 --- a/docs/mm.1 +++ b/docs/mm.1 @@ -10,11 +10,9 @@ mm \(en middleman .SH SYNOPSIS mm -.RB ( -aenu ) -.RB ( -i -.RB [ input ]) -.RB ( -o -.RB [ output ]) +.RB [ -aenu ] +.RB [ -i\ input ] +.RB [ -o\ output ] .\" .SH DESCRIPTION diff --git a/docs/npc.1 b/docs/npc.1 index 3e7af39..5acee9e 100644 --- a/docs/npc.1 +++ b/docs/npc.1 @@ -11,7 +11,7 @@ npc \(en show non-printing characters .SH SYNOPSIS npc -.RB ( -et ) +.RB [ -et ] .\" .SH DESCRIPTION diff --git a/docs/scrut.1 b/docs/scrut.1 index 56383b8..2b95bee 100644 --- a/docs/scrut.1 +++ b/docs/scrut.1 @@ -10,8 +10,8 @@ scrut \(en scrutinize file properties .SH SYNOPSIS scrut -.RB ( -LSbcdefgkprsuwx ) -.RB [ file... ] +.RB [ -LSbcdefgkprsuwx ] +.B file... .\" .SH DESCRIPTION diff --git a/docs/str.1 b/docs/str.1 index 22ffea1..1a4d8e4 100644 --- a/docs/str.1 +++ b/docs/str.1 @@ -11,8 +11,7 @@ str \(en test string arguments .SH SYNOPSIS str -.RB [ type ] -.RB [ string... ] +.B type string... .\" .SH DESCRIPTION diff --git a/docs/strcmp.1 b/docs/strcmp.1 index 0ad21b2..c99c8c8 100644 --- a/docs/strcmp.1 +++ b/docs/strcmp.1 @@ -11,8 +11,7 @@ strcmp \(en compare strings .SH SYNOPSIS strcmp -.RM [ string ] -.RB [ strings... ] +.B string string... .\" .SH DESCRIPTION diff --git a/docs/swab.1 b/docs/swab.1 index 72f0f19..e589c10 100644 --- a/docs/swab.1 +++ b/docs/swab.1 @@ -11,11 +11,8 @@ swab \(en swap bytes .SH SYNOPSIS swab -.RB ( -f ) -.RB ( -w -.R [ -.B word size -.R ]) +.RB [ -f ] +.RB [ -w\ word_size ] .\" .SH DESCRIPTION @@ -26,10 +23,9 @@ Swap the latter and former halves of a block of bytes. .IP \fB-f\fP Ignore SIGINT signal. .IP \fB-w\fP -Configures the word size; that is, the size in bytes of the block size -on which to operate. The default word size is 2. The word size must be -cleanly divisible by 2, otherwise the block of bytes being processed can\(cqt be -halved. +Configures the word size; that is, the size in bytes of the block size on which +to operate. The default word size is 2. The word size must be cleanly divisible +by 2, otherwise the block of bytes being processed can\(cqt be halved. .\" .SH EXAMPLES diff --git a/src/dj.c b/src/dj.c index 8a6732c..3885012 100644 --- a/src/dj.c +++ b/src/dj.c @@ -313,9 +313,9 @@ parse(char *s){ static int usage(void){ - fprintf(stderr, "Usage: %s (-AdfHqQ) (-a [byte]) (-c [count])\n" - "\t(-i [input file]) (-b [input block size]) (-s [input offset])\n" - "\t(-o [output file]) (-B [output block size]) (-S [output offset])\n", + fprintf(stderr, "Usage: %s [-AdfHqQ] [-a byte] [-c count]\n" + "\t[-i input_file] [-b input_block_size] [-s input_offset]\n" + "\t[-o output_file] [-B output_block_size] [-S output_offset]\n", program_name); return EX_USAGE; diff --git a/src/intcmp.c b/src/intcmp.c index 408474b..1fd278d 100644 --- a/src/intcmp.c +++ b/src/intcmp.c @@ -52,7 +52,7 @@ int main(int argc, char *argv[]){ if(optind + 2 /* ref cmp */ > argc){ usage: fprintf(stderr, - "Usage: %s (-eghl) [integer] [integer...]\n", + "Usage: %s [-eghl] integer integer...\n", argv[0] == NULL ? program_name : argv[0]); return EX_USAGE; } diff --git a/src/mm.c b/src/mm.c index dc337b7..e905b35 100644 --- a/src/mm.c +++ b/src/mm.c @@ -110,7 +110,7 @@ oserr(char *s, char *r){ * returns an exit status appropriate for a usage error. */ int usage(char *s){ - fprintf(stderr, "Usage: %s (-aenu) (-i [input])... (-o [output])...\n", s); + fprintf(stderr, "Usage: %s [-aenu] [-i input]... [-o output]...\n", s); return EX_USAGE; } diff --git a/src/npc.c b/src/npc.c index 8b97180..6b5e5f0 100644 --- a/src/npc.c +++ b/src/npc.c @@ -39,7 +39,7 @@ int main(int argc, char *argv[]){ } if(argc > optind){ -usage: fprintf(stderr, "Usage: %s (-eht)\n", argv[0]); +usage: fprintf(stderr, "Usage: %s [-eht]\n", argv[0]); return EX_USAGE; } diff --git a/src/scrut.c b/src/scrut.c index c5b675f..d85d243 100644 --- a/src/scrut.c +++ b/src/scrut.c @@ -66,7 +66,7 @@ int main(int argc, char *argv[]){ if(ops[i] == 'e') continue; else if(ops[i] == 'h'){ -usage: fprintf(stderr, "Usage: %s (-%s) [file...]\n", +usage: fprintf(stderr, "Usage: %s [-%s] file...\n", argv[0] == NULL ? program_name : argv[0], diff --git a/src/str.c b/src/str.c index ae03b1d..b4725eb 100644 --- a/src/str.c +++ b/src/str.c @@ -56,7 +56,7 @@ int main(int argc, char *argv[]){ goto pass; } - fprintf(stderr, "Usage: %s [type] [string...]\n", + fprintf(stderr, "Usage: %s type string...\n", argv[0] == NULL ? program_name : argv[0]); return EX_USAGE; diff --git a/src/strcmp.c b/src/strcmp.c index acb4946..33b73c2 100644 --- a/src/strcmp.c +++ b/src/strcmp.c @@ -8,7 +8,7 @@ int main(int argc, char *argv[]){ int i; if(argc < 3){ - fprintf(stderr, "Usage: %s [string] [string...]\n", + fprintf(stderr, "Usage: %s string string...\n", argv[0] == NULL ? program_name : argv[0]); return EX_USAGE; } diff --git a/src/swab.rs b/src/swab.rs index ca944d9..471f92b 100644 --- a/src/swab.rs +++ b/src/swab.rs @@ -35,7 +35,7 @@ fn oserr(s: &str, e: Error) -> ExitCode { } fn usage(s: &str) -> ExitCode { - eprintln!("Usage: {} (-f) (-w [wordsize])", s); + eprintln!("Usage: {} [-f] [-w word_size]", s); ExitCode::from(EX_USAGE as u8) } From 07a12ba81c29e06775eb129a187a4db358cac4a2 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 29 Jun 2024 05:28:23 -0600 Subject: [PATCH 133/343] docs, src: fixing man page and usage text readability --- docs/dj.1 | 28 ++++++++++++++-------------- docs/fop.1 | 2 +- docs/mm.1 | 4 ++-- docs/swab.1 | 2 +- src/dj.c | 4 ++-- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 4b0b5b1..43c2750 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -15,13 +15,13 @@ dj .RB [ -a\ byte ] .RB [ -c\ count ] -.RB [ -i\ input_file ] -.RB [ -b\ input_block_size ] -.RB [ -s\ input_offset ] +.RB [ -i\ file ] +.RB [ -b\ block_size ] +.RB [ -s\ offset ] -.RB [ -o\ output_file ] -.RB [ -B\ output_block_size ] -.RB [ -S\ output_offset ] +.RB [ -o\ file ] +.RB [ -B\ block_size ] +.RB [ -S\ offset ] .\" .SH DESCRIPTION @@ -39,25 +39,25 @@ immediately subsequent to the specified byte. .\" .SH OPTIONS -.IP \fB-i\fP +.IP \fB-i\fP\ \fIfile\fP Takes a file path as an argument and opens it for use as an input. -.IP \fB-b\fP +.IP \fB-b\fP\ \fIblock_size\fP Takes a numeric argument as the size in bytes of the input buffer, the default being 1024. -.IP \fB-s\fP +.IP \fB-s\fP\ \fIoffset\fP Takes a numeric argument as the number of bytes to skip into the input before starting to read. If the standard input is used, bytes read to this point are discarded. -.IP \fB-o\fP +.IP \fB-o\fP\ \fIfile\fP Takes a file path as an argument and opens it for use as an output. -.IP \fB-B\fP +.IP \fB-B\fP\ \fIblock_size\fP Does the same as .B -b but for the output buffer. -.IP \fB-S\fP +.IP \fB-S\fP\ \fIoffset\fP Seeks a number of bytes through the output before starting to write from the input. If the output is a stream, null characters are printed. -.IP \fB-a\fP +.IP \fB-a\fP\ \fIbyte\fP Accepts a single literal byte with which the input buffer is padded in the event of an incomplete read from the input file. .IP \fB-A\fP @@ -65,7 +65,7 @@ Specifying this option pads the input buffer with null bytes in the event of an incomplete read. This is equivalent to specifying .B -a with a null byte instead of a character. -.IP \fB-c\fP +.IP \fB-c\fP\ \fIcount\fP Specifies a number of reads to make. The default is 0, in which case the input is read until a partial or empty read is made. .IP \fB-d\fP diff --git a/docs/fop.1 b/docs/fop.1 index d777c68..b96033a 100644 --- a/docs/fop.1 +++ b/docs/fop.1 @@ -22,7 +22,7 @@ Performs operations on specified fields in data read from the standard input. .\" .SH OPTIONS -.IP \fB-d\fP +.IP \fB-d\fP\ \fIdelimiter\fP Sets a delimiter by which the input data will be split into fields. The default is an ASCII record separator. .\" diff --git a/docs/mm.1 b/docs/mm.1 index 735f9df..2916aa7 100644 --- a/docs/mm.1 +++ b/docs/mm.1 @@ -24,10 +24,10 @@ Catenate input files and write them to the start of each output file or stream. Opens subsequent outputs for appending rather than updating. .IP \fB-e\fP Use the standard error as an output. -.IP \fB-i\fP +.IP \fB-i\fP\ \fIinput\fP Opens a path as an input. If one or more of the input files is \(lq-\(rq or if no inputs are specified, the standard input shall be used. -.IP \fB-o\fP +.IP \fB-o\fP\ \fIoutput\fP Opens a path as an output. If one or more of the output files is \(lq-\(rq or if no outputs are specified, the standard output shall be used. .IP \fB-u\fP diff --git a/docs/swab.1 b/docs/swab.1 index e589c10..42eef95 100644 --- a/docs/swab.1 +++ b/docs/swab.1 @@ -22,7 +22,7 @@ Swap the latter and former halves of a block of bytes. .IP \fB-f\fP Ignore SIGINT signal. -.IP \fB-w\fP +.IP \fB-w\fP\ \fIword_size\fP Configures the word size; that is, the size in bytes of the block size on which to operate. The default word size is 2. The word size must be cleanly divisible by 2, otherwise the block of bytes being processed can\(cqt be halved. diff --git a/src/dj.c b/src/dj.c index 3885012..beafde8 100644 --- a/src/dj.c +++ b/src/dj.c @@ -314,8 +314,8 @@ static int usage(void){ fprintf(stderr, "Usage: %s [-AdfHqQ] [-a byte] [-c count]\n" - "\t[-i input_file] [-b input_block_size] [-s input_offset]\n" - "\t[-o output_file] [-B output_block_size] [-S output_offset]\n", + "\t[-i file] [-b block_size] [-s offset]\n" + "\t[-o file] [-B block_size] [-S offset]\n", program_name); return EX_USAGE; From 67b60e20cc8bb44dc8069a6b2538629f1bbc22ab Mon Sep 17 00:00:00 2001 From: DTB Date: Sat, 29 Jun 2024 05:55:29 -0600 Subject: [PATCH 134/343] dj.1: Man page fixes --- docs/dj.1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 1494827..8fd01f4 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH DJ 1 2024-06-17 "Bonsai Core Utilites 0.13.11" +.TH DJ 1 2024-06-29 "Harakit X.X.X" .SH NAME dj \(en disk jockey .\" @@ -73,7 +73,7 @@ null byte is used. Specifies a number of reads to make. The default is 0, in which case the input is read until a partial or empty read is made. .IP \fB-H\fP -Prints diagnostics messages in a human-readable manner as described in the +Prints diagnostic messages in a human-readable manner as described in the DIAGNOSTICS section. .IP \fB-n\fP Retries failed reads once before exiting. @@ -89,7 +89,7 @@ one or more of the input files is \(lq-\(rq. .\" .SH DIAGNOSTICS -On a partial or empty read a diagnostic message is printed. Then, the program +On a partial or empty read, a diagnostic message is printed. Then, the program exits unless the .B -n option is specified. From 6bd19c072d1bf1ab0b8d472c14df66c8b115d6b1 Mon Sep 17 00:00:00 2001 From: DTB Date: Fri, 28 Jun 2024 17:43:32 -0600 Subject: [PATCH 135/343] swab(1): fix some silly mistakes --- src/swab.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/swab.rs b/src/swab.rs index d997ddf..810a6cb 100644 --- a/src/swab.rs +++ b/src/swab.rs @@ -24,7 +24,7 @@ use std::{ }; extern crate getopt; -use getopt::{ Opt, Parser }; +use getopt::GetOpt; extern crate sysexits; use sysexits::{ EX_OK, EX_OSERR, EX_USAGE }; @@ -45,7 +45,6 @@ fn main() -> ExitCode { 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; @@ -53,11 +52,13 @@ fn main() -> ExitCode { match opt.opt() { Ok("f") => force = true, Ok("w") => { - match arg.parse::() { + if let Some(arg) = opt.arg() { + match opt.arg().parse::() { Ok(w) if w % 2 == 0 => { wordsize = w; () }, _ => { return usage(&argv[0]); }, } - }, + } + }, _ => { return usage(&argv[0]); } } } From 17455baeab063443a69d1e73848465ebdc25d254 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 29 Jun 2024 06:38:55 -0600 Subject: [PATCH 136/343] intcmp(1), npc(1): removes vestigial option --- src/intcmp.c | 2 +- src/npc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/intcmp.c b/src/intcmp.c index 1fd278d..d6dff0d 100644 --- a/src/intcmp.c +++ b/src/intcmp.c @@ -52,7 +52,7 @@ int main(int argc, char *argv[]){ if(optind + 2 /* ref cmp */ > argc){ usage: fprintf(stderr, - "Usage: %s [-eghl] integer integer...\n", + "Usage: %s [-egl] integer integer...\n", argv[0] == NULL ? program_name : argv[0]); return EX_USAGE; } diff --git a/src/npc.c b/src/npc.c index 6b5e5f0..1f96668 100644 --- a/src/npc.c +++ b/src/npc.c @@ -39,7 +39,7 @@ int main(int argc, char *argv[]){ } if(argc > optind){ -usage: fprintf(stderr, "Usage: %s [-eht]\n", argv[0]); +usage: fprintf(stderr, "Usage: %s [-et]\n", argv[0]); return EX_USAGE; } From cf5136d247dcb3329f5f4488d10258449423ae1e Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 29 Jun 2024 07:49:47 -0600 Subject: [PATCH 137/343] Makefile, swab(1): fixes swab build --- Makefile | 6 ++---- src/swab.rs | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 8109cd6..8a9e936 100644 --- a/Makefile +++ b/Makefile @@ -133,10 +133,8 @@ 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) --extern getopt=build/o/libgetopt.rlib \ - --extern sysexits=build/o/libsysexits.rlib \ - -o $@ src/swab.rs +build/bin/swab: src/swab.rs build rustlibs + $(RUSTC) $(RUSTFLAGS) $(RUSTLIBS) -o $@ src/swab.rs .PHONY: true true: build/bin/true diff --git a/src/swab.rs b/src/swab.rs index 810a6cb..d05b651 100644 --- a/src/swab.rs +++ b/src/swab.rs @@ -53,7 +53,7 @@ fn main() -> ExitCode { Ok("f") => force = true, Ok("w") => { if let Some(arg) = opt.arg() { - match opt.arg().parse::() { + match arg.parse::() { Ok(w) if w % 2 == 0 => { wordsize = w; () }, _ => { return usage(&argv[0]); }, } From 40984453e35c452c8ba71b98351a5d692055fc15 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 29 Jun 2024 08:01:33 -0600 Subject: [PATCH 138/343] Makefile: better leverage targets for sysexits build --- Makefile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 70f53b4..fb9aa5d 100644 --- a/Makefile +++ b/Makefile @@ -76,13 +76,14 @@ build/o/libstrerror.rlib: build src/libstrerror.rs $(RUSTC) $(RUSTFLAGS) --crate-type=lib -o $@ \ src/libstrerror.rs -# bandage solution until bindgen(1) gets stdin support -build/o/libsysexits.rlib: build $(SYSEXITS)sysexits.h - printf '\043define EXIT_FAILURE 1\n' | cat - $(SYSEXITS)sysexits.h \ - > build/include/sysexits.h +build/o/libsysexits.rlib: build/include/sysexits.h bindgen --default-macro-constant-type signed --use-core --formatter=none \ build/include/sysexits.h | $(RUSTC) $(RUSTFLAGS) --crate-type lib -o $@ - +# bandage solution until bindgen(1) gets stdin support +build/include/sysexits.h: build $(SYSEXITS)sysexits.h + printf '\043define EXIT_FAILURE 1\n' | cat - $(SYSEXITS)sysexits.h > $@ + .PHONY: dj dj: build/bin/dj build/bin/dj: src/dj.c build From 261c98ad1446c43e82076950eca0597274f9b211 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 29 Jun 2024 08:24:11 -0600 Subject: [PATCH 139/343] Makefile: docs no longer builds every invocation, normalize PREFIX for setting man dir --- Makefile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index fb9aa5d..99cda9f 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,10 @@ DESTDIR ?= dist PREFIX ?= /usr/local -MANDIR != [ $(PREFIX) = / ] && printf '/usr/share/man\n' \ +# normalized prefix +PREFIX_N != (test -d $(PREFIX) && [ '-' != $(PREFIX) ] \ + && CDPATH= cd -P -- $(PREFIX) && pwd -P) +MANDIR != [ $(PREFIX_N) = / ] && printf '/usr/share/man\n' \ || printf '/share/man\n' SYSEXITS != printf '\043include \n' | cpp -M - | sed 's/ /\n/g' \ | sed -n 's/sysexits\.h//p' || printf 'include\n' @@ -29,7 +32,7 @@ RUSTLIBS = --extern getopt=build/o/libgetopt.rlib \ CFLAGS += -I$(SYSEXITS) .PHONY: all -all: docs dj false fop hru intcmp mm npc rpn scrut str strcmp swab true +all: dj false fop hru intcmp mm npc rpn scrut str strcmp swab true # keep build/include until bindgen(1) has stdin support # https://github.com/rust-lang/rust-bindgen/issues/2703 @@ -40,7 +43,7 @@ build: clean: rm -rf build dist -dist: all +dist: all docs mkdir -p $(DESTDIR)/$(PREFIX)/bin $(DESTDIR)/$(PREFIX)/share/man/man1 cp build/bin/* $(DESTDIR)/$(PREFIX)/bin cp build/docs/*.1 $(DESTDIR)/$(PREFIX)/$(MANDIR)/man1 From e38ea5b35d74e79d427b0cc1c6d01f7a90eb7976 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 29 Jun 2024 08:36:12 -0600 Subject: [PATCH 140/343] Makefile: fixes dist --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 99cda9f..581d2a1 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ clean: rm -rf build dist dist: all docs - mkdir -p $(DESTDIR)/$(PREFIX)/bin $(DESTDIR)/$(PREFIX)/share/man/man1 + mkdir -p $(DESTDIR)/$(PREFIX)/bin $(DESTDIR)/$(PREFIX)/$(MANDIR)/man1 cp build/bin/* $(DESTDIR)/$(PREFIX)/bin cp build/docs/*.1 $(DESTDIR)/$(PREFIX)/$(MANDIR)/man1 From 6b28a12b731b06abc6691e325d95dbc17523d90a Mon Sep 17 00:00:00 2001 From: DTB Date: Sat, 29 Jun 2024 19:14:08 -0600 Subject: [PATCH 141/343] dj.1: last minute changes --- docs/dj.1 | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 8fd01f4..0e69afc 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -53,9 +53,9 @@ Takes a file path as an argument and opens it for use as an input. Takes a numeric argument as the size in bytes of the input buffer, the default being 1024. .IP \fB-s\fP -Takes a numeric argument as the number of bytes to skip into the input -before starting to read. If the standard input is used, bytes read to this point -are discarded. +Takes a numeric argument as the index of the byte at which reading will +commence; \(lqskips\(rq that number of bytes. If the standard input is used, +bytes read to this point are discarded. .IP \fB-o\fP Takes a file path as an argument and opens it for use as an output. .IP \fB-B\fP @@ -63,8 +63,9 @@ Does the same as .B -b but for the output buffer. .IP \fB-S\fP -Seeks a number of bytes through the output before starting to write from -the input. If the output is a stream, null characters are printed. +Takes a numeric argument as the index of the byte at which writing will +commence; \(lqseeks\(rq that number of bytes. If the standard output is used, +null characters are printed. .IP \fB-a\fP Accepts a single literal byte with which the input buffer is padded in the event of an incomplete read from the input file. If the option argument is empty, the @@ -81,11 +82,11 @@ Retries failed reads once before exiting. .SH STANDARD INPUT The standard input shall be used as an input if no inputs are specified or if -one or more of the input files is \(lq-\(rq. +input file is \(lq-\(rq. .\" .SH STANDARD OUTPUT The standard output shall be used as an output if no inputs are specified or if -one or more of the input files is \(lq-\(rq. +the output file is \(lq-\(rq. .\" .SH DIAGNOSTICS @@ -129,9 +130,7 @@ is specified along with the option and a count, actual byte output is the product of the count and the input block size and therefore may be lower than expected. If the .B -a -or -.B -A -options are specified, this could make written data nonsensical. +option is specified, this could make written data nonsensical. .\" .SH CAVEATS From 984c1c1f9a02033fcf6e6bf3782868aa75118dd2 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 30 Jun 2024 21:21:02 -0600 Subject: [PATCH 142/343] Makefile: fixes portability issue --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 581d2a1..5e2c70d 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ PREFIX_N != (test -d $(PREFIX) && [ '-' != $(PREFIX) ] \ && CDPATH= cd -P -- $(PREFIX) && pwd -P) MANDIR != [ $(PREFIX_N) = / ] && printf '/usr/share/man\n' \ || printf '/share/man\n' -SYSEXITS != printf '\043include \n' | cpp -M - | sed 's/ /\n/g' \ +SYSEXITS != printf '\043include \n' | cpp -M - | tr ' ' '\n' \ | sed -n 's/sysexits\.h//p' || printf 'include\n' CC ?= cc From 064abb82a6f3e4973f3332937c1a9057e7798fd4 Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 3 Jul 2024 13:50:24 -0600 Subject: [PATCH 143/343] dj(1): fix option parsing regression --- src/dj.c | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/src/dj.c b/src/dj.c index d9c38eb..f7e4e9b 100644 --- a/src/dj.c +++ b/src/dj.c @@ -19,7 +19,7 @@ #include /* errno */ #include /* open(2) */ #include /* fprintf(3), stderr */ -#include /* free(3), malloc(3), strtol(3), size_t */ +#include /* malloc(3), strtol(3), size_t */ #include /* memcpy(3), memmove(3), memset(3) */ #include /* EX_OK, EX_USAGE */ #include /* close(2), getopt(3), lseek(2), read(2), write(2), @@ -64,15 +64,6 @@ static int write_flags = O_WRONLY | O_CREAT; || (fd) == STDOUT_FILENO \ || (fd) == STDERR_FILENO) -/* Macro to call the cleanup functions that operate on struct io on the - * particular io[2] used in main. Error conditions are not checked because this - * is only used when the program is about to terminate (hence its name). */ -#define terminate(io) do{ \ - free((io[0]).buf); \ - free((io[1]).buf); \ - Io_fdclose(&(io)[0]); \ - Io_fdclose(&(io)[1]); }while(0) - /* Allocates *io's buffer. Returns NULL if unsuccessful. */ static void * Io_bufalloc(struct Io *io){ @@ -121,15 +112,6 @@ Io_bufxfer(struct Io *dest, struct Io *src, int n){ return dest; } -/* Closes io->fn and returns -1 on error, otherwise io->fd. */ -static int -Io_fdclose(struct Io *io){ - - return fdisstd(io->fd) - ? 0 - : close(io->fd); -} - /* Opens io->fn and saves the file descriptor into io->fd. Returns io->fd, * which will be -1 if an error occured. */ static int @@ -140,7 +122,7 @@ Io_fdopen(struct Io *io, char *fn){ /* these are the flags used by touch(1p) */ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) != -1 - && Io_fdclose(io) == 0){ + && (fdisstd(io->fd) || close(io->fd) == 0)){ io->fd = fd; io->fn = fn; } @@ -294,7 +276,6 @@ int main(int argc, char *argv[]){ break; }else if(Io_fdopen(&io[i], optarg) != -1) break; - terminate(io); return oserr(optarg); case 'n': noerror = 1; break; case 'H': fmt_output = fmt_human; break; @@ -308,19 +289,18 @@ int main(int argc, char *argv[]){ if(c == 'c' && (count = parse(optarg)) >= 0) break; i = (c >= 'A' && c <= 'Z'); /* uppercase changes output */ - c &= 0x20 /* 0b 0010 0000 */; /* (ASCII) make lowercase */ + c |= 0x20 /* 0b 0010 0000 */; /* (ASCII) make lowercase */ if((c == 'b' && (io[i].bs = parse(optarg)) > 0) || (c == 's' && (io[i].seek = parse(optarg)) >= 0)) break; /* FALLTHROUGH */ default: - terminate(io); return usage(program_name); } } + if(argc > optind){ - terminate(io); return usage(program_name); } @@ -328,12 +308,10 @@ int main(int argc, char *argv[]){ if(Io_bufalloc(&io[i]) == NULL){ fprintf(stderr, "%s: Failed to allocate %d bytes\n", program_name, io[i].bs); - terminate(io); return EX_OSERR; }else if(io[i].seek > 0) Io_fdseek(&io[i]); if(io[i].seek > 0){ - terminate(io); return oserr(io[i].fn); } } @@ -387,7 +365,6 @@ int main(int argc, char *argv[]){ }while(count == 0 || --count > 0); output(io, fmt_output); - terminate(io); return EX_OK; } From 1cf67af28179d46b6da387afb691944cc5637d85 Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 3 Jul 2024 14:22:23 -0600 Subject: [PATCH 144/343] dj(1): add a ton of assertions, fix if statement, fix io[i] mixups --- src/dj.c | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/src/dj.c b/src/dj.c index f7e4e9b..e5f276b 100644 --- a/src/dj.c +++ b/src/dj.c @@ -16,6 +16,7 @@ * along with this program. If not, see https://www.gnu.org/licenses/. */ +#include /* assert(3) */ #include /* errno */ #include /* open(2) */ #include /* fprintf(3), stderr */ @@ -68,14 +69,18 @@ static int write_flags = O_WRONLY | O_CREAT; static void * Io_bufalloc(struct Io *io){ - return (io->buf = malloc(io->bs * (sizeof *io->buf))); + return io != NULL + ? (io->buf = malloc(io->bs * (sizeof *io->buf))) + : NULL; } /* Fills the unused portion of io's buffer with padding, updating io->bufuse. * Returns io. */ static struct Io * Io_bufrpad(struct Io *io, int padding){ - + + assert(io != NULL); + memset(io->buf + io->bufuse, padding, io->bs - io->bufuse); io->bufuse = io->bs; @@ -90,6 +95,8 @@ static struct Io* Io_bufxapp(struct Io *dest, struct Io *src){ int n; + assert(dest != NULL && src != NULL); + n = MIN(src->bufuse, dest->bs - dest->bufuse); memcpy(dest->buf + dest->bufuse, src->buf, n); dest->bufuse += n; @@ -106,6 +113,8 @@ Io_bufxapp(struct Io *dest, struct Io *src){ static struct Io* Io_bufxfer(struct Io *dest, struct Io *src, int n){ + assert(dest != NULL && src != NULL); + memcpy(dest->buf, src->buf, (dest->bufuse = n)); memmove(src->buf, src->buf + n, (src->bufuse -= n)); @@ -117,7 +126,9 @@ Io_bufxfer(struct Io *dest, struct Io *src, int n){ static int Io_fdopen(struct Io *io, char *fn){ int fd; - + + assert(io != NULL); + if((fd = open(fn, io->fl, /* these are the flags used by touch(1p) */ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) @@ -134,8 +145,15 @@ Io_fdopen(struct Io *io, char *fn){ * of sought bytes from io->seek. This procedure leaves garbage in io->buf. */ static void Io_fdseek(struct Io *io){ - - if(io->seek != 0 + + assert(io != NULL); + assert(io->fd != STDIN_FILENO || io->fl == read_flags); + assert(io->fd != STDOUT_FILENO || io->fl == write_flags); + assert(io->fd != STDERR_FILENO || io->fl == write_flags); + + printf("%s\n", io->fn); + + if(io->seek == 0 || (!fdisstd(io->fd) && lseek(io->fd, io->seek, SEEK_SET) != -1)) return; @@ -160,7 +178,8 @@ Io_fdseek(struct Io *io){ /* second chance */ io->bufuse = read(io->fd, io->buf, MIN(io->bs, io->seek)); }while((io->seek -= io->bufuse) > 0 && io->bufuse != 0); - } + }else + assert(0); /* UNREACHABLE */ io->bufuse = 0; @@ -255,9 +274,9 @@ int main(int argc, char *argv[]){ for(i = 0; i < 2; ++i){ io[i].bs = 1024 /* 1 KiB */; /* GNU dd(1) default; POSIX says 512B */ io[i].bytes = 0; - io[i].fd = i ? STDIN_FILENO : STDOUT_FILENO; - io[i].fn = i ? stdin_name : stdout_name; - io[i].fl = i ? read_flags : write_flags; + io[i].fd = i == 0 ? STDIN_FILENO : STDOUT_FILENO; + io[i].fn = i == 0 ? stdin_name : stdout_name; + io[i].fl = i == 0 ? read_flags : write_flags; io[i].prec = 0; io[i].rec = 0; io[i].seek = 0; @@ -271,8 +290,8 @@ int main(int argc, char *argv[]){ switch(c){ case 'i': case 'o': i = (c == 'o'); if(optarg[0] == '-' && optarg[1] == '\0'){ /* optarg == "-" */ - io[i].fd = i ? STDIN_FILENO : STDOUT_FILENO; - io[i].fn = i ? stdin_name : stdout_name; + io[i].fd = i == 0 ? STDIN_FILENO : STDOUT_FILENO; + io[i].fn = i == 0 ? stdin_name : stdout_name; break; }else if(Io_fdopen(&io[i], optarg) != -1) break; @@ -309,11 +328,12 @@ int main(int argc, char *argv[]){ fprintf(stderr, "%s: Failed to allocate %d bytes\n", program_name, io[i].bs); return EX_OSERR; - }else if(io[i].seek > 0) + }else if(io[i].seek > 0){ Io_fdseek(&io[i]); if(io[i].seek > 0){ return oserr(io[i].fn); } + } } do{ /* read */ From 76252305f990c960de08d6793da96a2f0e3a2765 Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 3 Jul 2024 14:46:56 -0600 Subject: [PATCH 145/343] dj(1): remove Io_bufalloc --- src/dj.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/dj.c b/src/dj.c index e5f276b..2e565ce 100644 --- a/src/dj.c +++ b/src/dj.c @@ -65,15 +65,6 @@ static int write_flags = O_WRONLY | O_CREAT; || (fd) == STDOUT_FILENO \ || (fd) == STDERR_FILENO) -/* Allocates *io's buffer. Returns NULL if unsuccessful. */ -static void * -Io_bufalloc(struct Io *io){ - - return io != NULL - ? (io->buf = malloc(io->bs * (sizeof *io->buf))) - : NULL; -} - /* Fills the unused portion of io's buffer with padding, updating io->bufuse. * Returns io. */ static struct Io * @@ -324,7 +315,7 @@ int main(int argc, char *argv[]){ } for(i = 0; i < 2; ++i){ - if(Io_bufalloc(&io[i]) == NULL){ + if((io[i].buf = malloc(io[i].bs * (sizeof *(io[i].buf)))) == NULL){ fprintf(stderr, "%s: Failed to allocate %d bytes\n", program_name, io[i].bs); return EX_OSERR; From aff658d611e7b221a58b3177f34c7bd5c323d725 Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 3 Jul 2024 14:50:50 -0600 Subject: [PATCH 146/343] dj(1): remove debugging vestige, reflow output into printio --- src/dj.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/dj.c b/src/dj.c index 2e565ce..a20b472 100644 --- a/src/dj.c +++ b/src/dj.c @@ -47,7 +47,7 @@ struct Io{ long seek; /* bytes to seek/skip (will be 0 after skippage) (-sS) */ }; -/* To be assigned to main:fmt_output and used with output(). */ +/* To be assigned to main:fmt and used with printio(). */ static char *fmt_asv = "%d\037%d\036%d\037%d\035%d\036%d\034"; static char *fmt_human = "%d+%d > %d+%d; %d > %d\n"; @@ -142,8 +142,6 @@ Io_fdseek(struct Io *io){ assert(io->fd != STDOUT_FILENO || io->fl == write_flags); assert(io->fd != STDERR_FILENO || io->fl == write_flags); - printf("%s\n", io->fn); - if(io->seek == 0 || (!fdisstd(io->fd) && lseek(io->fd, io->seek, SEEK_SET) != -1)) return; @@ -215,7 +213,7 @@ oserr(char *s){ /* Prints statistics regarding the use of dj, particularly partially and * completely read and written records. */ static void -output(struct Io io[2], char *fmt){ +printio(char *fmt, struct Io io[2]){ fprintf(stderr, fmt, io[0].rec, io[0].prec, io[1].rec, io[1].prec, @@ -252,7 +250,7 @@ usage(char *s){ int main(int argc, char *argv[]){ int align; /* low 8b used, negative if no alignment is being done */ int count; /* 0 if dj(1) runs until no more reads are possible */ - char *fmt_output; /* == fmt_asv (default) or fmt_human (-H) */ + char *fmt; /* == fmt_asv (default) or fmt_human (-H) */ size_t i; /* side of io being modified */ struct Io io[2]; char noerror; /* 0=exits (default) 1=retries on partial reads or writes */ @@ -260,7 +258,7 @@ int main(int argc, char *argv[]){ /* Set defaults. */ align = -1; count = 0; - fmt_output = fmt_asv; + fmt = fmt_asv; noerror = 0; for(i = 0; i < 2; ++i){ io[i].bs = 1024 /* 1 KiB */; /* GNU dd(1) default; POSIX says 512B */ @@ -288,7 +286,7 @@ int main(int argc, char *argv[]){ break; return oserr(optarg); case 'n': noerror = 1; break; - case 'H': fmt_output = fmt_human; break; + case 'H': fmt = fmt_human; break; case 'a': if(optarg[0] == '\0' || optarg[1] == '\0'){ align = optarg[0]; @@ -298,7 +296,7 @@ int main(int argc, char *argv[]){ case 'c': case 'b': case 's': case 'B': case 'S': /* numbers */ if(c == 'c' && (count = parse(optarg)) >= 0) break; - i = (c >= 'A' && c <= 'Z'); /* uppercase changes output */ + i = (c >= 'A' && c <= 'Z'); c |= 0x20 /* 0b 0010 0000 */; /* (ASCII) make lowercase */ if((c == 'b' && (io[i].bs = parse(optarg)) > 0) || (c == 's' && (io[i].seek = parse(optarg)) >= 0)) @@ -336,7 +334,7 @@ int main(int argc, char *argv[]){ else if(io[0].bufuse < io[0].bs){ ++io[0].prec; fprintf(stderr, "%s: Partial read:\n\t", program_name); - output(io, fmt_output); + printio(fmt, io); if(!noerror) count = 1; if(align >= 0) @@ -365,7 +363,7 @@ int main(int argc, char *argv[]){ }else if(t > io[1].bufuse && io[1].bufuse > 0){ io[1].prec += 1; fprintf(stderr, "%s: Partial write:\n\t", program_name); - output(io, fmt_output); + printio(fmt, io); if(!noerror) count = 1; }else if(io[1].bufuse == 0 && t < io[1].bs) @@ -375,7 +373,7 @@ int main(int argc, char *argv[]){ }while(io[0].bufuse > 0); }while(count == 0 || --count > 0); - output(io, fmt_output); + printio(fmt, io); return EX_OK; } From 6548a448c74d7d226091eff9570dbd34e5f01255 Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 3 Jul 2024 15:44:42 -0600 Subject: [PATCH 147/343] dj(1): fix potential skip/seek bug in non-std io --- src/dj.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/dj.c b/src/dj.c index a20b472..41fd65f 100644 --- a/src/dj.c +++ b/src/dj.c @@ -133,7 +133,9 @@ Io_fdopen(struct Io *io, char *fn){ } /* Seeks io->seek bytes through *io's file descriptor, subtracting the number - * of sought bytes from io->seek. This procedure leaves garbage in io->buf. */ + * of sought bytes from io->seek. This procedure leaves garbage in io->buf. + * Read/written bytes here aren't counted in the statistics because successful + * seeking is guaranteed. */ static void Io_fdseek(struct Io *io){ @@ -143,8 +145,10 @@ Io_fdseek(struct Io *io){ assert(io->fd != STDERR_FILENO || io->fl == write_flags); if(io->seek == 0 - || (!fdisstd(io->fd) && lseek(io->fd, io->seek, SEEK_SET) != -1)) + || (!fdisstd(io->fd) && lseek(io->fd, io->seek, SEEK_SET) != -1)){ + io->seek = 0; return; + } if(io->fl == write_flags) memset(io->buf, '\0', io->bs); From 3897f44cf8c4379067316415459d2449f014ea70 Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 3 Jul 2024 15:46:11 -0600 Subject: [PATCH 148/343] dj(1): prefix getopt optstring with : --- src/dj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dj.c b/src/dj.c index 41fd65f..f938ca9 100644 --- a/src/dj.c +++ b/src/dj.c @@ -279,7 +279,7 @@ int main(int argc, char *argv[]){ int c; program_name = argv[0]; - while((c = getopt(argc, argv, "a:b:B:c:i:hHns:S:o:")) != -1) + while((c = getopt(argc, argv, ":a:b:B:c:i:hHns:S:o:")) != -1) switch(c){ case 'i': case 'o': i = (c == 'o'); if(optarg[0] == '-' && optarg[1] == '\0'){ /* optarg == "-" */ From 66ca4b9a120a8ce4d6e704d0330f9713194b865c Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 3 Jul 2024 15:47:48 -0600 Subject: [PATCH 149/343] dj(1): remove unnecessary stderr checks --- src/dj.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/dj.c b/src/dj.c index f938ca9..8c9f327 100644 --- a/src/dj.c +++ b/src/dj.c @@ -59,11 +59,8 @@ static int write_flags = O_WRONLY | O_CREAT; #define MIN(a, b) (((a) < (b)) ? (a) : (b)) -/* Macro to check if fd is a std* file, e.g. stdin. */ -#define fdisstd(fd) \ - ((fd) == STDIN_FILENO \ - || (fd) == STDOUT_FILENO \ - || (fd) == STDERR_FILENO) +/* Macro to check if fd is stdin or stdout */ +#define fdisstd(fd) ((fd) == STDIN_FILENO || (fd) == STDOUT_FILENO) /* Fills the unused portion of io's buffer with padding, updating io->bufuse. * Returns io. */ @@ -142,7 +139,6 @@ Io_fdseek(struct Io *io){ assert(io != NULL); assert(io->fd != STDIN_FILENO || io->fl == read_flags); assert(io->fd != STDOUT_FILENO || io->fl == write_flags); - assert(io->fd != STDERR_FILENO || io->fl == write_flags); if(io->seek == 0 || (!fdisstd(io->fd) && lseek(io->fd, io->seek, SEEK_SET) != -1)){ From 944feef43465caf4ffafc8106373bfbd0d9a090f Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 3 Jul 2024 16:07:02 -0600 Subject: [PATCH 150/343] dj(1): Refactor out Io_fdseek entirely --- src/dj.c | 93 +++++++++++++++++++++++++------------------------------- 1 file changed, 42 insertions(+), 51 deletions(-) diff --git a/src/dj.c b/src/dj.c index 8c9f327..96085e3 100644 --- a/src/dj.c +++ b/src/dj.c @@ -129,52 +129,6 @@ Io_fdopen(struct Io *io, char *fn){ return fd; } -/* Seeks io->seek bytes through *io's file descriptor, subtracting the number - * of sought bytes from io->seek. This procedure leaves garbage in io->buf. - * Read/written bytes here aren't counted in the statistics because successful - * seeking is guaranteed. */ -static void -Io_fdseek(struct Io *io){ - - assert(io != NULL); - assert(io->fd != STDIN_FILENO || io->fl == read_flags); - assert(io->fd != STDOUT_FILENO || io->fl == write_flags); - - if(io->seek == 0 - || (!fdisstd(io->fd) && lseek(io->fd, io->seek, SEEK_SET) != -1)){ - io->seek = 0; - return; - } - - if(io->fl == write_flags) - memset(io->buf, '\0', io->bs); - - if(io->fl == write_flags){ - memset(io->buf, '\0', io->bs); - /* We're going to cheat and use bufuse as the retval for write(2), - * which is fine because it'll be zeroed as this function returns - * anyway. */ - do{ - if((io->bufuse = write(io->fd, io->buf, MIN(io->bs, io->seek))) - == 0) - /* second chance */ - io->bufuse = write(io->fd, io->buf, MIN(io->bs, io->seek)); - }while((io->seek -= io->bufuse) > 0 && io->bufuse != 0); - }else if(io->fl == read_flags){ - do{ - if((io->bufuse = read(io->fd, io->buf, MIN(io->bs, io->seek))) - == 0) - /* second chance */ - io->bufuse = read(io->fd, io->buf, MIN(io->bs, io->seek)); - }while((io->seek -= io->bufuse) > 0 && io->bufuse != 0); - }else - assert(0); /* UNREACHABLE */ - - io->bufuse = 0; - - return; -} - /* Reads io->bs bytes from *io's file descriptor into io->buf, storing the * number of read bytes in io->bufuse and updating io->bytes. If io->bufuse is * 0, errno will probably be set. Returns io. */ @@ -307,24 +261,61 @@ int main(int argc, char *argv[]){ } } + assert(io->fd != STDIN_FILENO || io->fl == read_flags); + assert(io->fd != STDOUT_FILENO || io->fl == write_flags); if(argc > optind){ return usage(program_name); } for(i = 0; i < 2; ++i){ + /* buffer allocation */ if((io[i].buf = malloc(io[i].bs * (sizeof *(io[i].buf)))) == NULL){ fprintf(stderr, "%s: Failed to allocate %d bytes\n", program_name, io[i].bs); return EX_OSERR; - }else if(io[i].seek > 0){ - Io_fdseek(&io[i]); - if(io[i].seek > 0){ - return oserr(io[i].fn); - } } + /* easy seeking */ + if(!fdisstd(io[i].fd) && lseek(io[i].fd, io[i].seek, SEEK_SET) != -1) + io[i].seek = 0; } + /* hard skipping */ + if(io[0].seek > 0){ + do{ + if((io[0].bufuse = read( + io[0].fd, io[0].buf, MIN(io[0].bs, io[0].seek))) + == 0) + /* second chance */ + io->bufuse = read( + io[0].fd, io[0].buf, MIN(io[0].bs, io[0].seek)); + }while((io[0].seek -= io[0].bufuse) > 0 && io[0].bufuse != 0); + io[0].bufuse = 0; + } + + /* hard seeking */ + if(io[1].seek > 0){ + memset(io[1].buf, '\0', io[1].bs); + /* We're going to cheat and use bufuse as the retval for write(2), + * which is fine because it'll be zeroed as this function returns + * anyway. */ + do{ + if((io[1].bufuse = write( + io[1].fd, io[1].buf, MIN(io[1].bs, io[1].seek))) + == 0) + /* second chance */ + io[1].bufuse = write( + io[1].fd, io[1].buf, MIN(io[1].bs, io[1].seek)); + }while((io[1].seek -= io[1].bufuse) > 0 && io[1].bufuse != 0); + io[1].bufuse = 0; + } + + /* Sought bytes aren't counted in the statistics because successful seeking + * is guaranteed here. */ + for(i = 0; i < 2; ++i) + if(io[i].seek > 0) + return oserr(io[i].fn); + do{ /* read */ Io_read(&io[0]); if(!noerror && io[0].bufuse == 0) From 7fe122ac3b5ee858007c74879f8ee5b4362ec530 Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 3 Jul 2024 16:13:20 -0600 Subject: [PATCH 151/343] dj.1: clarify skip/seek behavior with regards to statistics output --- docs/dj.1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/dj.1 b/docs/dj.1 index 38b8034..dd293f2 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -35,7 +35,9 @@ respectively. This language is inherited from the utility and used here to decrease ambiguity. When seeking or skipping to a byte, writing or reading starts at the byte -immediately subsequent to the specified byte. +immediately subsequent to the specified byte. Seeks and skips aren\(cqt counted +in the output statistics because they're guaranteed to succeed (or the utility +will exit unsuccessfully). .\" .SH OPTIONS From f4b97be1f12d1e212218a4c4e152fb5ca76b7f8c Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 3 Jul 2024 17:50:04 -0600 Subject: [PATCH 152/343] dj(1): iron out Io_bufxapp --- src/dj.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/src/dj.c b/src/dj.c index 96085e3..3421292 100644 --- a/src/dj.c +++ b/src/dj.c @@ -75,25 +75,6 @@ Io_bufrpad(struct Io *io, int padding){ return io; } -/* Copies from the buffer in src as much as possible to the free space in the - * dest buffer, removing the copied units from src and permuting the remaining - * units in the src buffer to the start of the buffer, modifying both the src - * and dest bufuse and returning dest. */ -static struct Io* -Io_bufxapp(struct Io *dest, struct Io *src){ - int n; - - assert(dest != NULL && src != NULL); - - n = MIN(src->bufuse, dest->bs - dest->bufuse); - memcpy(dest->buf + dest->bufuse, src->buf, n); - dest->bufuse += n; - memmove(src->buf, src->buf + n, src->bs - n); - src->bufuse -= n; - - return dest; -} - /* Copies from the buffer in src to the buffer in dest no more than n units, * removing the copied units from src and permuting the remaining units in the * src buffer to the start of the buffer, modifying both the src and dest @@ -338,7 +319,16 @@ int main(int argc, char *argv[]){ int t; if(io[1].bs > io[0].bs){ - Io_bufxapp(&io[1], &io[0]); + int n; + + /* copy from ibuf as much as possible to the obuf */ + memcpy(io[1].buf + io[1].bufuse, io[0].buf, + (n = MIN(io[0].bufuse, io[1].bs - io[1].bufuse))); + io[1].bufuse += n; + /* permute out the copied units */ + memmove(io[0].buf, io[0].buf + n, io[0].bs - n); + io[0].bufuse -= n; + if(io[0].bs + io[1].bufuse <= io[1].bs && count != 1) continue; /* we could write more */ }else From 2167f35f588c4f87635060b60f8f30192cfe3a47 Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 3 Jul 2024 17:59:21 -0600 Subject: [PATCH 153/343] dj(1): fix segfault when bses are mismatched --- src/dj.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/dj.c b/src/dj.c index 3421292..17c1d59 100644 --- a/src/dj.c +++ b/src/dj.c @@ -35,15 +35,15 @@ char *program_name = "dj"; * writing ends of its jockeyed "pipe". User-configurable members are noted * with their relevant options. */ struct Io{ - int bs; /* buffer size (-bB) */ + int bs; /* buffer size (-bB) */ size_t bufuse; /* buffer usage */ char *buf; /* buffer */ - int bytes; /* bytes processed */ + size_t bytes; /* bytes processed */ int fd; /* file descriptor */ int fl; /* file opening flags */ char *fn; /* file name (may be stdin_name or stdout_name) (-io) */ - int prec; /* partial records processed */ - int rec; /* records processed */ + size_t prec; /* partial records processed */ + size_t rec; /* records processed */ long seek; /* bytes to seek/skip (will be 0 after skippage) (-sS) */ }; @@ -197,6 +197,7 @@ int main(int argc, char *argv[]){ noerror = 0; for(i = 0; i < 2; ++i){ io[i].bs = 1024 /* 1 KiB */; /* GNU dd(1) default; POSIX says 512B */ + io[i].bufuse = 0; io[i].bytes = 0; io[i].fd = i == 0 ? STDIN_FILENO : STDOUT_FILENO; io[i].fn = i == 0 ? stdin_name : stdout_name; From adda0d95807085c3685c71accd4bcb4bd4963fc9 Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 3 Jul 2024 18:30:54 -0600 Subject: [PATCH 154/343] dj.1: elaborate on skip/seek behavior, provide another example --- docs/dj.1 | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 5 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index dd293f2..09f40c9 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH DJ 1 2024-06-29 "Harakit X.X.X" +.TH DJ 1 2024-07-03 "Harakit X.X.X" .SH NAME dj \(en disk jockey .\" @@ -34,10 +34,17 @@ respectively. This language is inherited from the .BR dd (1p) utility and used here to decrease ambiguity. -When seeking or skipping to a byte, writing or reading starts at the byte -immediately subsequent to the specified byte. Seeks and skips aren\(cqt counted -in the output statistics because they're guaranteed to succeed (or the utility -will exit unsuccessfully). +The offset used when skipping or seeking refers to how many bytes are skipped +or sought. Running +.BR dj (1) +with a skip offset of 1 skips one byte into the input and reads from the second +byte onwards. A programmer may think of a file as a zero-indexed array of +bytes; in this analogy, the offset given is the index of the byte at which to +start reading or writing. + +Seeks and skips aren\(cqt counted in the output statistics because they're +guaranteed to succeed (or the utility will exit unsuccessfully, before it has +written any data). .\" .SH OPTIONS @@ -82,6 +89,54 @@ input file is \(lq-\(rq. The standard output shall be used as an output if no inputs are specified or if the output file is \(lq-\(rq. .\" +.SH EXAMPLES + +The following +.BR sh (1p) +line: + +.RS +printf 'Hello, world!\(rsn' | dj -c 1 -b 7 -s 7 2>/dev/null +.RE + +Produces the following output: + +.RS +world! +.RE + +The following +.BR sh (1p) +lines run sequentially: + +.RS +tr '\(rs0' 0 Date: Wed, 3 Jul 2024 18:44:42 -0600 Subject: [PATCH 155/343] dj(1): clean up some stray ends --- src/dj.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/dj.c b/src/dj.c index 17c1d59..ac52883 100644 --- a/src/dj.c +++ b/src/dj.c @@ -22,7 +22,7 @@ #include /* fprintf(3), stderr */ #include /* malloc(3), strtol(3), size_t */ #include /* memcpy(3), memmove(3), memset(3) */ -#include /* EX_OK, EX_USAGE */ +#include /* EX_OK, EX_OSERR, EX_USAGE */ #include /* close(2), getopt(3), lseek(2), read(2), write(2), * optarg, optind, STDIN_FILENO, STDOUT_FILENO */ #include /* S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, @@ -246,9 +246,8 @@ int main(int argc, char *argv[]){ assert(io->fd != STDIN_FILENO || io->fl == read_flags); assert(io->fd != STDOUT_FILENO || io->fl == write_flags); - if(argc > optind){ + if(argc > optind) return usage(program_name); - } for(i = 0; i < 2; ++i){ /* buffer allocation */ From b74160fa4e4af5604bb7a3c5278c2b3982094b23 Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 3 Jul 2024 19:04:01 -0600 Subject: [PATCH 156/343] dj(1): remove Io_bufxfer --- src/dj.c | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/src/dj.c b/src/dj.c index ac52883..22c46a7 100644 --- a/src/dj.c +++ b/src/dj.c @@ -75,21 +75,6 @@ Io_bufrpad(struct Io *io, int padding){ return io; } -/* Copies from the buffer in src to the buffer in dest no more than n units, - * removing the copied units from src and permuting the remaining units in the - * src buffer to the start of the buffer, modifying both the src and dest - * bufuse and returning dest. */ -static struct Io* -Io_bufxfer(struct Io *dest, struct Io *src, int n){ - - assert(dest != NULL && src != NULL); - - memcpy(dest->buf, src->buf, (dest->bufuse = n)); - memmove(src->buf, src->buf + n, (src->bufuse -= n)); - - return dest; -} - /* Opens io->fn and saves the file descriptor into io->fd. Returns io->fd, * which will be -1 if an error occured. */ static int @@ -318,10 +303,18 @@ int main(int argc, char *argv[]){ do{ int t; - if(io[1].bs > io[0].bs){ + if(io[0].bs <= io[1].bs){ int n; - /* copy from ibuf as much as possible to the obuf */ + /* saturate obuf */ + memcpy(io[1].buf, io[0].buf, + (io[1].bufuse = (n = MIN(io[0].bufuse, io[1].bs)))); + /* permute the copied units out of ibuf */ + memmove(io[0].buf, io[0].buf + n, (io[0].bufuse -= n)); + }else /* if(io[0].bs < io[1].bs) */ { + int n; + + /* drain what we can from ibuf */ memcpy(io[1].buf + io[1].bufuse, io[0].buf, (n = MIN(io[0].bufuse, io[1].bs - io[1].bufuse))); io[1].bufuse += n; @@ -330,9 +323,8 @@ int main(int argc, char *argv[]){ io[0].bufuse -= n; if(io[0].bs + io[1].bufuse <= io[1].bs && count != 1) - continue; /* we could write more */ - }else - Io_bufxfer(&io[1], &io[0], MIN(io[0].bufuse, io[1].bs)); + continue; /* obuf not saturated - we could write more */ + } t = io[1].bufuse; Io_write(&io[1]); From 2b593559afc64ad2a7f80bed0511e19250ade41d Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 3 Jul 2024 19:06:59 -0600 Subject: [PATCH 157/343] dj(1): remove Io_bufrpad --- src/dj.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/src/dj.c b/src/dj.c index 22c46a7..6815a82 100644 --- a/src/dj.c +++ b/src/dj.c @@ -62,19 +62,6 @@ static int write_flags = O_WRONLY | O_CREAT; /* Macro to check if fd is stdin or stdout */ #define fdisstd(fd) ((fd) == STDIN_FILENO || (fd) == STDOUT_FILENO) -/* Fills the unused portion of io's buffer with padding, updating io->bufuse. - * Returns io. */ -static struct Io * -Io_bufrpad(struct Io *io, int padding){ - - assert(io != NULL); - - memset(io->buf + io->bufuse, padding, io->bs - io->bufuse); - io->bufuse = io->bs; - - return io; -} - /* Opens io->fn and saves the file descriptor into io->fd. Returns io->fd, * which will be -1 if an error occured. */ static int @@ -294,8 +281,12 @@ int main(int argc, char *argv[]){ printio(fmt, io); if(!noerror) count = 1; - if(align >= 0) - Io_bufrpad(&io[0], align); + if(align >= 0){ + /* fill the rest of the ibuf with padding */ + memset(io[0].buf + io[0].bufuse, align, + io[0].bs - io[0].bufuse); + io->bufuse = io->bs; + } }else ++io[0].rec; From 5b1d4fef8828a6057183b95d3828564b4f1811c8 Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 3 Jul 2024 19:22:34 -0600 Subject: [PATCH 158/343] dj(1): remove Io_fdopen --- src/dj.c | 47 +++++++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/src/dj.c b/src/dj.c index 6815a82..974bcf0 100644 --- a/src/dj.c +++ b/src/dj.c @@ -62,26 +62,6 @@ static int write_flags = O_WRONLY | O_CREAT; /* Macro to check if fd is stdin or stdout */ #define fdisstd(fd) ((fd) == STDIN_FILENO || (fd) == STDOUT_FILENO) -/* Opens io->fn and saves the file descriptor into io->fd. Returns io->fd, - * which will be -1 if an error occured. */ -static int -Io_fdopen(struct Io *io, char *fn){ - int fd; - - assert(io != NULL); - - if((fd = open(fn, io->fl, - /* these are the flags used by touch(1p) */ - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) - != -1 - && (fdisstd(io->fd) || close(io->fd) == 0)){ - io->fd = fd; - io->fn = fn; - } - - return fd; -} - /* Reads io->bs bytes from *io's file descriptor into io->buf, storing the * number of read bytes in io->bufuse and updating io->bytes. If io->bufuse is * 0, errno will probably be set. Returns io. */ @@ -155,12 +135,12 @@ usage(char *s){ } int main(int argc, char *argv[]){ - int align; /* low 8b used, negative if no alignment is being done */ - int count; /* 0 if dj(1) runs until no more reads are possible */ - char *fmt; /* == fmt_asv (default) or fmt_human (-H) */ - size_t i; /* side of io being modified */ - struct Io io[2]; + int align; /* low 8b used, negative if no alignment is being done */ + int count; /* 0 if dj(1) runs until no more reads are possible */ + char *fmt; /* == fmt_asv (default) or fmt_human (-H) */ + size_t i; /* side of io being modified */ char noerror; /* 0=exits (default) 1=retries on partial reads or writes */ + struct Io io[2]; /* Set defaults. */ align = -1; @@ -190,10 +170,21 @@ int main(int argc, char *argv[]){ io[i].fd = i == 0 ? STDIN_FILENO : STDOUT_FILENO; io[i].fn = i == 0 ? stdin_name : stdout_name; break; - }else if(Io_fdopen(&io[i], optarg) != -1) - break; + }else{ + int fd; + + if((fd = open(optarg, io[i].fl, /* touch(1p) flags */ + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP + | S_IROTH | S_IWOTH)) + != -1 + && (fdisstd(io[i].fd) || close(io[i].fd) == 0)){ + io[i].fd = fd; + io[i].fn = optarg; + break; + } + } return oserr(optarg); - case 'n': noerror = 1; break; + case 'n': noerror = 1; break; case 'H': fmt = fmt_human; break; case 'a': if(optarg[0] == '\0' || optarg[1] == '\0'){ From cc645613888960c2784bcfe5c2a90ce17fe6b2bc Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 3 Jul 2024 20:52:41 -0600 Subject: [PATCH 159/343] dj(1): only include sysexits if they aren't defined --- src/dj.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/dj.c b/src/dj.c index 974bcf0..5a095ed 100644 --- a/src/dj.c +++ b/src/dj.c @@ -22,7 +22,9 @@ #include /* fprintf(3), stderr */ #include /* malloc(3), strtol(3), size_t */ #include /* memcpy(3), memmove(3), memset(3) */ -#include /* EX_OK, EX_OSERR, EX_USAGE */ +#if !defined EX_OK || !defined EX_OSERR || !defined EX_USAGE +# include +#endif #include /* close(2), getopt(3), lseek(2), read(2), write(2), * optarg, optind, STDIN_FILENO, STDOUT_FILENO */ #include /* S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, From 4004a4a0068f173059ed59c5ac6aba10ec0c6ce6 Mon Sep 17 00:00:00 2001 From: DTB Date: Thu, 4 Jul 2024 18:41:20 -0600 Subject: [PATCH 160/343] dj(1): use the retvals of Io_read and Io_write --- src/dj.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/dj.c b/src/dj.c index 5a095ed..fa3d46a 100644 --- a/src/dj.c +++ b/src/dj.c @@ -263,8 +263,7 @@ int main(int argc, char *argv[]){ return oserr(io[i].fn); do{ /* read */ - Io_read(&io[0]); - if(!noerror && io[0].bufuse == 0) + if(Io_read(&io[0])->bufuse == 0 && !noerror) Io_read(&io[0]); /* second chance */ if(io[0].bufuse == 0) /* that's all she wrote */ break; @@ -311,8 +310,7 @@ int main(int argc, char *argv[]){ } t = io[1].bufuse; - Io_write(&io[1]); - if(!noerror && io[1].bufuse == t) + if(Io_write(&io[1])->bufuse == t && !noerror) Io_write(&io[1]); /* second chance */ if(t == io[1].bufuse){ /* no more love */ count = 1; From f49a2d2eb8ec3aed83434f164477ff422b3b6b98 Mon Sep 17 00:00:00 2001 From: DTB Date: Thu, 4 Jul 2024 19:21:40 -0600 Subject: [PATCH 161/343] dj(1): move prec and rec adjustment into Io_read --- src/dj.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/dj.c b/src/dj.c index fa3d46a..9aed880 100644 --- a/src/dj.c +++ b/src/dj.c @@ -65,13 +65,24 @@ static int write_flags = O_WRONLY | O_CREAT; #define fdisstd(fd) ((fd) == STDIN_FILENO || (fd) == STDOUT_FILENO) /* Reads io->bs bytes from *io's file descriptor into io->buf, storing the - * number of read bytes in io->bufuse and updating io->bytes. If io->bufuse is - * 0, errno will probably be set. Returns io. */ + * number of read bytes in io->bufuse and updating io->bytes. If the buf isn't + * saturated but is still read into, io->prec will be incremented. If the buf + * is saturated, io->rec will be incremented. If io->bufuse is 0, errno will + * probably be set. Returns io. */ static struct Io * Io_read(struct Io *io){ io->bytes += (io->bufuse = read(io->fd, io->buf, io->bs)); + assert(io->bufuse <= io->bs); + + if(io->bufuse != 0){ + if(io->bufuse < io->bs) + ++io->prec; + else /* if(io->bufuse == io->bs) */ + ++io->rec; + } + return io; } @@ -267,8 +278,8 @@ int main(int argc, char *argv[]){ Io_read(&io[0]); /* second chance */ if(io[0].bufuse == 0) /* that's all she wrote */ break; - else if(io[0].bufuse < io[0].bs){ - ++io[0].prec; + + if(io[0].bufuse < io[0].bs){ fprintf(stderr, "%s: Partial read:\n\t", program_name); printio(fmt, io); if(!noerror) @@ -279,8 +290,7 @@ int main(int argc, char *argv[]){ io[0].bs - io[0].bufuse); io->bufuse = io->bs; } - }else - ++io[0].rec; + } /* write */ do{ From fc0d9e374bb36198c812bab561b894672ca11fa2 Mon Sep 17 00:00:00 2001 From: DTB Date: Thu, 4 Jul 2024 19:23:09 -0600 Subject: [PATCH 162/343] dj(1): make printio fprintio --- src/dj.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/dj.c b/src/dj.c index 9aed880..b81deeb 100644 --- a/src/dj.c +++ b/src/dj.c @@ -113,9 +113,9 @@ oserr(char *s){ /* Prints statistics regarding the use of dj, particularly partially and * completely read and written records. */ static void -printio(char *fmt, struct Io io[2]){ +fprintio(FILE *stream, char *fmt, struct Io io[2]){ - fprintf(stderr, fmt, + fprintf(stream, fmt, io[0].rec, io[0].prec, io[1].rec, io[1].prec, io[0].bytes, io[1].bytes); @@ -281,7 +281,7 @@ int main(int argc, char *argv[]){ if(io[0].bufuse < io[0].bs){ fprintf(stderr, "%s: Partial read:\n\t", program_name); - printio(fmt, io); + fprintio(stderr, fmt, io); if(!noerror) count = 1; if(align >= 0){ @@ -328,7 +328,7 @@ int main(int argc, char *argv[]){ }else if(t > io[1].bufuse && io[1].bufuse > 0){ io[1].prec += 1; fprintf(stderr, "%s: Partial write:\n\t", program_name); - printio(fmt, io); + fprintio(stderr, fmt, io); if(!noerror) count = 1; }else if(io[1].bufuse == 0 && t < io[1].bs) @@ -338,7 +338,7 @@ int main(int argc, char *argv[]){ }while(io[0].bufuse > 0); }while(count == 0 || --count > 0); - printio(fmt, io); + fprintio(stderr, fmt, io); return EX_OK; } From f8c0e0570c8896d2e29f0b8bddf2b44c771ba962 Mon Sep 17 00:00:00 2001 From: DTB Date: Thu, 4 Jul 2024 19:36:32 -0600 Subject: [PATCH 163/343] dj(1): make Io_write handle prec and rec --- src/dj.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/dj.c b/src/dj.c index b81deeb..4feae19 100644 --- a/src/dj.c +++ b/src/dj.c @@ -72,30 +72,34 @@ static int write_flags = O_WRONLY | O_CREAT; static struct Io * Io_read(struct Io *io){ + assert(io->bs > 0); + io->bytes += (io->bufuse = read(io->fd, io->buf, io->bs)); assert(io->bufuse <= io->bs); - if(io->bufuse != 0){ - if(io->bufuse < io->bs) - ++io->prec; - else /* if(io->bufuse == io->bs) */ - ++io->rec; - } + io->prec += (0 < io->bufuse && io->bufuse < io->bs); + io->rec += (io->bufuse == io->bs); return io; } -/* Writes io->bufuse units from io->buf to io->fd, permuting any unwritten +/* Writes io->bufuse (>0) units from io->buf to io->fd, permuting any unwritten * bytes to the start of io->buf and updating io->bufuse. If io->bufuse doesn't * change, errno will probably be set. Returns io. */ static struct Io * Io_write(struct Io *io){ int t; + assert(io->bufuse > 0); + assert(io->bufuse <= io->bs); + if((t = write(io->fd, io->buf, io->bufuse)) > 0) memmove(io->buf, io->buf + t, (io->bufuse -= t)); + io->bytes += t; + io->prec += (t > 0 && io->bufuse > 0); + io->rec += (t > 0 && io->bufuse == 0); return io; } @@ -322,19 +326,17 @@ int main(int argc, char *argv[]){ t = io[1].bufuse; if(Io_write(&io[1])->bufuse == t && !noerror) Io_write(&io[1]); /* second chance */ - if(t == io[1].bufuse){ /* no more love */ + if(io[1].bufuse == t){ /* no more love */ count = 1; break; - }else if(t > io[1].bufuse && io[1].bufuse > 0){ - io[1].prec += 1; + } + + if(0 < io[1].bufuse && io[1].bufuse < t){ fprintf(stderr, "%s: Partial write:\n\t", program_name); fprintio(stderr, fmt, io); if(!noerror) count = 1; - }else if(io[1].bufuse == 0 && t < io[1].bs) - ++io[1].prec; - else - ++io[1].rec; + } }while(io[0].bufuse > 0); }while(count == 0 || --count > 0); From 8c33f0116c33834a8ffba6f934cdd99a1cb8453e Mon Sep 17 00:00:00 2001 From: DTB Date: Thu, 4 Jul 2024 19:45:53 -0600 Subject: [PATCH 164/343] dj(1): move open(2) flags, remove unnecessary comments --- src/dj.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/dj.c b/src/dj.c index 4feae19..d5f209c 100644 --- a/src/dj.c +++ b/src/dj.c @@ -56,6 +56,9 @@ static char *fmt_human = "%d+%d > %d+%d; %d > %d\n"; static char *stdin_name = ""; static char *stdout_name = ""; + +static int creat_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH + | S_IWOTH; /* Consistent with touch(1p). */ static int read_flags = O_RDONLY; /* Consistent with Busybox dd(1). */ static int write_flags = O_WRONLY | O_CREAT; @@ -64,11 +67,6 @@ static int write_flags = O_WRONLY | O_CREAT; /* Macro to check if fd is stdin or stdout */ #define fdisstd(fd) ((fd) == STDIN_FILENO || (fd) == STDOUT_FILENO) -/* Reads io->bs bytes from *io's file descriptor into io->buf, storing the - * number of read bytes in io->bufuse and updating io->bytes. If the buf isn't - * saturated but is still read into, io->prec will be incremented. If the buf - * is saturated, io->rec will be incremented. If io->bufuse is 0, errno will - * probably be set. Returns io. */ static struct Io * Io_read(struct Io *io){ @@ -84,9 +82,6 @@ Io_read(struct Io *io){ return io; } -/* Writes io->bufuse (>0) units from io->buf to io->fd, permuting any unwritten - * bytes to the start of io->buf and updating io->bufuse. If io->bufuse doesn't - * change, errno will probably be set. Returns io. */ static struct Io * Io_write(struct Io *io){ int t; @@ -190,10 +185,7 @@ int main(int argc, char *argv[]){ }else{ int fd; - if((fd = open(optarg, io[i].fl, /* touch(1p) flags */ - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP - | S_IROTH | S_IWOTH)) - != -1 + if((fd = open(optarg, io[i].fl, creat_mode)) != -1 && (fdisstd(io[i].fd) || close(io[i].fd) == 0)){ io[i].fd = fd; io[i].fn = optarg; From fe175cab191af00bac56042f338ad3f46f5ff617 Mon Sep 17 00:00:00 2001 From: DTB Date: Thu, 4 Jul 2024 20:00:40 -0600 Subject: [PATCH 165/343] dj(1): add a variable for skipping in the main loop --- src/dj.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/dj.c b/src/dj.c index d5f209c..9fb55ca 100644 --- a/src/dj.c +++ b/src/dj.c @@ -269,22 +269,29 @@ int main(int argc, char *argv[]){ if(io[i].seek > 0) return oserr(io[i].fn); - do{ /* read */ - if(Io_read(&io[0])->bufuse == 0 && !noerror) - Io_read(&io[0]); /* second chance */ - if(io[0].bufuse == 0) /* that's all she wrote */ - break; + do{ + { /* read */ + static char skipping = 0; - if(io[0].bufuse < io[0].bs){ - fprintf(stderr, "%s: Partial read:\n\t", program_name); - fprintio(stderr, fmt, io); - if(!noerror) - count = 1; - if(align >= 0){ - /* fill the rest of the ibuf with padding */ - memset(io[0].buf + io[0].bufuse, align, - io[0].bs - io[0].bufuse); - io->bufuse = io->bs; + if(io[0].seek > 0) + skipping = 1; + + if(Io_read(&io[0])->bufuse == 0 && !noerror) + Io_read(&io[0]); /* second chance */ + if(io[0].bufuse == 0) /* that's all she wrote */ + break; + + if(io[0].bufuse < io[0].bs){ + fprintf(stderr, "%s: Partial read:\n\t", program_name); + fprintio(stderr, fmt, io); + if(!noerror) + count = 1; + if(align >= 0){ + /* fill the rest of the ibuf with padding */ + memset(io[0].buf + io[0].bufuse, align, + io[0].bs - io[0].bufuse); + io->bufuse = io->bs; + } } } From 1fab60d77939f151627c23f5715fb41633f4ab15 Mon Sep 17 00:00:00 2001 From: DTB Date: Thu, 4 Jul 2024 20:05:18 -0600 Subject: [PATCH 166/343] dj(1): no more pointer arithmetic --- src/dj.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/dj.c b/src/dj.c index 9fb55ca..e3972aa 100644 --- a/src/dj.c +++ b/src/dj.c @@ -90,7 +90,7 @@ Io_write(struct Io *io){ assert(io->bufuse <= io->bs); if((t = write(io->fd, io->buf, io->bufuse)) > 0) - memmove(io->buf, io->buf + t, (io->bufuse -= t)); + memmove(io->buf, &(io->buf)[t], (io->bufuse -= t)); io->bytes += t; io->prec += (t > 0 && io->bufuse > 0); @@ -288,7 +288,7 @@ int main(int argc, char *argv[]){ count = 1; if(align >= 0){ /* fill the rest of the ibuf with padding */ - memset(io[0].buf + io[0].bufuse, align, + memset(&(io[0].buf)[io[0].bufuse], align, io[0].bs - io[0].bufuse); io->bufuse = io->bs; } @@ -306,16 +306,16 @@ int main(int argc, char *argv[]){ memcpy(io[1].buf, io[0].buf, (io[1].bufuse = (n = MIN(io[0].bufuse, io[1].bs)))); /* permute the copied units out of ibuf */ - memmove(io[0].buf, io[0].buf + n, (io[0].bufuse -= n)); + memmove(io[0].buf, &(io[0].buf)[n], (io[0].bufuse -= n)); }else /* if(io[0].bs < io[1].bs) */ { int n; /* drain what we can from ibuf */ - memcpy(io[1].buf + io[1].bufuse, io[0].buf, + memcpy(&(io[1].buf)[io[1].bufuse], io[0].buf, (n = MIN(io[0].bufuse, io[1].bs - io[1].bufuse))); io[1].bufuse += n; /* permute out the copied units */ - memmove(io[0].buf, io[0].buf + n, io[0].bs - n); + memmove(io[0].buf, &{io[0].buf)[n], io[0].bs - n); io[0].bufuse -= n; if(io[0].bs + io[1].bufuse <= io[1].bs && count != 1) From 9f420131ee591ad97847cc1599c05fbd8b2e0203 Mon Sep 17 00:00:00 2001 From: DTB Date: Thu, 4 Jul 2024 20:16:54 -0600 Subject: [PATCH 167/343] dj(1): more work adapting hard skipping to the main loop --- src/dj.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/dj.c b/src/dj.c index e3972aa..aee9c38 100644 --- a/src/dj.c +++ b/src/dj.c @@ -270,23 +270,27 @@ int main(int argc, char *argv[]){ return oserr(io[i].fn); do{ + assert(io[0].bufuse == 0); + { /* read */ static char skipping = 0; + int t; if(io[0].seek > 0) skipping = 1; - if(Io_read(&io[0])->bufuse == 0 && !noerror) + t = io[0].bufuse; + if(Io_read(&io[0])->bufuse == t && !noerror) Io_read(&io[0]); /* second chance */ - if(io[0].bufuse == 0) /* that's all she wrote */ + if(io[0].bufuse == t) /* that's all she wrote */ break; - if(io[0].bufuse < io[0].bs){ + if(/* t < io[0].bufuse && */ io[0].bufuse < io[0].bs){ fprintf(stderr, "%s: Partial read:\n\t", program_name); fprintio(stderr, fmt, io); if(!noerror) count = 1; - if(align >= 0){ + if(!skipping && align >= 0){ /* fill the rest of the ibuf with padding */ memset(&(io[0].buf)[io[0].bufuse], align, io[0].bs - io[0].bufuse); @@ -315,7 +319,7 @@ int main(int argc, char *argv[]){ (n = MIN(io[0].bufuse, io[1].bs - io[1].bufuse))); io[1].bufuse += n; /* permute out the copied units */ - memmove(io[0].buf, &{io[0].buf)[n], io[0].bs - n); + memmove(io[0].buf, &(io[0].buf)[n], io[0].bs - n); io[0].bufuse -= n; if(io[0].bs + io[1].bufuse <= io[1].bs && count != 1) @@ -330,7 +334,7 @@ int main(int argc, char *argv[]){ break; } - if(0 < io[1].bufuse && io[1].bufuse < t){ + if(0 < io[1].bufuse /* && io[1].bufuse < t */){ fprintf(stderr, "%s: Partial write:\n\t", program_name); fprintio(stderr, fmt, io); if(!noerror) From 906eb92f5a59995a5b5a977ee2667b9a47b3ddec Mon Sep 17 00:00:00 2001 From: DTB Date: Thu, 4 Jul 2024 20:27:31 -0600 Subject: [PATCH 168/343] dj(1): (broken) move hard skipping to the main loop --- src/dj.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/dj.c b/src/dj.c index aee9c38..7b3bb0a 100644 --- a/src/dj.c +++ b/src/dj.c @@ -72,7 +72,8 @@ Io_read(struct Io *io){ assert(io->bs > 0); - io->bytes += (io->bufuse = read(io->fd, io->buf, io->bs)); + io->bytes += (io->bufuse = read(io->fd, &(io->buf)[io->bufuse], + io->bs - io->bufuse)); assert(io->bufuse <= io->bs); @@ -233,19 +234,6 @@ int main(int argc, char *argv[]){ io[i].seek = 0; } - /* hard skipping */ - if(io[0].seek > 0){ - do{ - if((io[0].bufuse = read( - io[0].fd, io[0].buf, MIN(io[0].bs, io[0].seek))) - == 0) - /* second chance */ - io->bufuse = read( - io[0].fd, io[0].buf, MIN(io[0].bs, io[0].seek)); - }while((io[0].seek -= io[0].bufuse) > 0 && io[0].bufuse != 0); - io[0].bufuse = 0; - } - /* hard seeking */ if(io[1].seek > 0){ memset(io[1].buf, '\0', io[1].bs); @@ -265,9 +253,8 @@ int main(int argc, char *argv[]){ /* Sought bytes aren't counted in the statistics because successful seeking * is guaranteed here. */ - for(i = 0; i < 2; ++i) - if(io[i].seek > 0) - return oserr(io[i].fn); + if(io[1].seek > 0) + return oserr(io[1].fn); do{ assert(io[0].bufuse == 0); @@ -279,6 +266,9 @@ int main(int argc, char *argv[]){ if(io[0].seek > 0) skipping = 1; + if(skipping && io[0].seek < io[0].bs) + io[0].bufuse = io[0].bs - io[0].seek; + t = io[0].bufuse; if(Io_read(&io[0])->bufuse == t && !noerror) Io_read(&io[0]); /* second chance */ @@ -297,6 +287,13 @@ int main(int argc, char *argv[]){ io->bufuse = io->bs; } } + + if(skipping){ + skipping = (io[0].seek -= io[0].bufuse - t) > 0; + io[0].bufuse = 0; + count += (count != 0); + continue; + } } /* write */ From 9e8b82c4bbf402c5caec14c0dd4a74acf8ccf35e Mon Sep 17 00:00:00 2001 From: DTB Date: Thu, 4 Jul 2024 20:47:30 -0600 Subject: [PATCH 169/343] dj(1): fix inaccurate statistics after Io_read and Io_write --- src/dj.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/dj.c b/src/dj.c index 7b3bb0a..e65274a 100644 --- a/src/dj.c +++ b/src/dj.c @@ -69,16 +69,19 @@ static int write_flags = O_WRONLY | O_CREAT; static struct Io * Io_read(struct Io *io){ + int t; assert(io->bs > 0); + assert(io->bufuse < io->bs); - io->bytes += (io->bufuse = read(io->fd, &(io->buf)[io->bufuse], + io->bufuse += (t = read(io->fd, &(io->buf)[io->bufuse], io->bs - io->bufuse)); assert(io->bufuse <= io->bs); - io->prec += (0 < io->bufuse && io->bufuse < io->bs); - io->rec += (io->bufuse == io->bs); + io->bytes += t; + io->prec += (0 < io->bufuse && io->bufuse < io->bs); + io->rec += (io->bufuse == io->bs); return io; } @@ -94,8 +97,8 @@ Io_write(struct Io *io){ memmove(io->buf, &(io->buf)[t], (io->bufuse -= t)); io->bytes += t; - io->prec += (t > 0 && io->bufuse > 0); - io->rec += (t > 0 && io->bufuse == 0); + io->prec += (0 < io->bufuse && 0 < t); + io->rec += (io->bufuse == 0 && 0 < t); return io; } From 571796fe0d6ae440ff849f6a6ccbbba5e7760dd0 Mon Sep 17 00:00:00 2001 From: DTB Date: Thu, 4 Jul 2024 21:05:15 -0600 Subject: [PATCH 170/343] dj.1: update man page to match behavior --- docs/dj.1 | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 09f40c9..4c60ff7 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -42,9 +42,9 @@ byte onwards. A programmer may think of a file as a zero-indexed array of bytes; in this analogy, the offset given is the index of the byte at which to start reading or writing. -Seeks and skips aren\(cqt counted in the output statistics because they're -guaranteed to succeed (or the utility will exit unsuccessfully, before it has -written any data). +Seeks aren\(cqt counted in the output statistics because they\(cqre guaranteed +to succeed (or the utility will exit unsuccessfully, before it has written any +data). .\" .SH OPTIONS @@ -185,9 +185,19 @@ option is specified, this could make written data nonsensical. Existing files are not truncated on ouput and are instead overwritten. -Many lowercase options have capitalized variants and vice-versa which can be -confusing. Capitalized options tend to affect output or are more intense -versions of lowercase options. +The options +.B -b +and +.B -B +could be confused for each other, and so could +.B -s +and +.BR -S . +The lowercase option affects input and the capitalized option affects output. + +The discarded but read bytes skipped while processing irregular files, such as +streams, are reported in the diagnostic output. Bytes skipped while processing +regular files are not reported, as the bytes weren\(cqt read. .\" .SH RATIONALE @@ -208,3 +218,4 @@ Copyright \(co 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later .\" .SH SEE ALSO .BR dd (1p) +.BR lseek (3p) From 6ed7089b25852f41f882f4a42829e22f107259d3 Mon Sep 17 00:00:00 2001 From: DTB Date: Thu, 4 Jul 2024 21:32:05 -0600 Subject: [PATCH 171/343] dj(1): statistics now track hard seeks --- docs/dj.1 | 11 ++++------- src/dj.c | 36 ++++++++++++++---------------------- 2 files changed, 18 insertions(+), 29 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 4c60ff7..d358e3f 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -41,10 +41,6 @@ with a skip offset of 1 skips one byte into the input and reads from the second byte onwards. A programmer may think of a file as a zero-indexed array of bytes; in this analogy, the offset given is the index of the byte at which to start reading or writing. - -Seeks aren\(cqt counted in the output statistics because they\(cqre guaranteed -to succeed (or the utility will exit unsuccessfully, before it has written any -data). .\" .SH OPTIONS @@ -195,9 +191,10 @@ and .BR -S . The lowercase option affects input and the capitalized option affects output. -The discarded but read bytes skipped while processing irregular files, such as -streams, are reported in the diagnostic output. Bytes skipped while processing -regular files are not reported, as the bytes weren\(cqt read. +The skipped or sought bytes while processing irregular files, such as streams, +are reported in the diagnostic output, because they were actually read or +written. This is as opposed to bytes skipped while processing regular files, +which are not reported. .\" .SH RATIONALE diff --git a/src/dj.c b/src/dj.c index e65274a..08df495 100644 --- a/src/dj.c +++ b/src/dj.c @@ -56,7 +56,6 @@ static char *fmt_human = "%d+%d > %d+%d; %d > %d\n"; static char *stdin_name = ""; static char *stdout_name = ""; - static int creat_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; /* Consistent with touch(1p). */ static int read_flags = O_RDONLY; /* Consistent with Busybox dd(1). */ @@ -239,37 +238,29 @@ int main(int argc, char *argv[]){ /* hard seeking */ if(io[1].seek > 0){ - memset(io[1].buf, '\0', io[1].bs); - /* We're going to cheat and use bufuse as the retval for write(2), - * which is fine because it'll be zeroed as this function returns - * anyway. */ + size_t t; do{ - if((io[1].bufuse = write( - io[1].fd, io[1].buf, MIN(io[1].bs, io[1].seek))) - == 0) - /* second chance */ - io[1].bufuse = write( - io[1].fd, io[1].buf, MIN(io[1].bs, io[1].seek)); - }while((io[1].seek -= io[1].bufuse) > 0 && io[1].bufuse != 0); + memset(io[1].buf, '\0', + (t = io[1].bufuse = MIN(io[1].bs, io[1].seek))); + if(Io_write(&io[1])->bufuse == t && !noerror) + Io_write(&io[1]); /* second chance */ + }while((io[1].seek -= (t - io[1].bufuse)) > 0 && io[1].bufuse != t); io[1].bufuse = 0; } - /* Sought bytes aren't counted in the statistics because successful seeking - * is guaranteed here. */ - if(io[1].seek > 0) + if(io[1].seek > 0){ + fprintio(stderr, fmt, io); return oserr(io[1].fn); + } do{ assert(io[0].bufuse == 0); { /* read */ - static char skipping = 0; + char skipping; int t; - if(io[0].seek > 0) - skipping = 1; - - if(skipping && io[0].seek < io[0].bs) + if((skipping = (io[0].seek > 0)) && io[0].seek < io[0].bs) io[0].bufuse = io[0].bs - io[0].seek; t = io[0].bufuse; @@ -279,11 +270,13 @@ int main(int argc, char *argv[]){ break; if(/* t < io[0].bufuse && */ io[0].bufuse < io[0].bs){ + assert(!skipping); + fprintf(stderr, "%s: Partial read:\n\t", program_name); fprintio(stderr, fmt, io); if(!noerror) count = 1; - if(!skipping && align >= 0){ + if(align >= 0){ /* fill the rest of the ibuf with padding */ memset(&(io[0].buf)[io[0].bufuse], align, io[0].bs - io[0].bufuse); @@ -292,7 +285,6 @@ int main(int argc, char *argv[]){ } if(skipping){ - skipping = (io[0].seek -= io[0].bufuse - t) > 0; io[0].bufuse = 0; count += (count != 0); continue; From abfe7046e77a3103f01f9b1f7ae9dddf082062ef Mon Sep 17 00:00:00 2001 From: DTB Date: Fri, 5 Jul 2024 08:02:09 -0600 Subject: [PATCH 172/343] dj(1): fix some type issues --- src/dj.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/dj.c b/src/dj.c index 08df495..2be2ecb 100644 --- a/src/dj.c +++ b/src/dj.c @@ -73,15 +73,16 @@ Io_read(struct Io *io){ assert(io->bs > 0); assert(io->bufuse < io->bs); - io->bufuse += (t = read(io->fd, &(io->buf)[io->bufuse], - io->bs - io->bufuse)); + if((t = read(io->fd, &(io->buf)[io->bufuse], io->bs - io->bufuse)) < 0) + t = 0; + + io->bufuse += t; + io->bytes += t; + io->prec += (0 < io->bufuse && io->bufuse < io->bs); + io->rec += (io->bufuse == io->bs); assert(io->bufuse <= io->bs); - io->bytes += t; - io->prec += (0 < io->bufuse && io->bufuse < io->bs); - io->rec += (io->bufuse == io->bs); - return io; } @@ -96,8 +97,8 @@ Io_write(struct Io *io){ memmove(io->buf, &(io->buf)[t], (io->bufuse -= t)); io->bytes += t; - io->prec += (0 < io->bufuse && 0 < t); - io->rec += (io->bufuse == 0 && 0 < t); + io->prec += (t > 0 && io->bufuse > 0); + io->rec += (t > 0 && io->bufuse == 0); return io; } @@ -258,8 +259,9 @@ int main(int argc, char *argv[]){ { /* read */ char skipping; - int t; + size_t t; + /* hack to intentionally get a partial read from Io_read */ if((skipping = (io[0].seek > 0)) && io[0].seek < io[0].bs) io[0].bufuse = io[0].bs - io[0].seek; @@ -270,8 +272,6 @@ int main(int argc, char *argv[]){ break; if(/* t < io[0].bufuse && */ io[0].bufuse < io[0].bs){ - assert(!skipping); - fprintf(stderr, "%s: Partial read:\n\t", program_name); fprintio(stderr, fmt, io); if(!noerror) From bab3cdd90e8ef97a4aa71593edf67c4bb8fa4c09 Mon Sep 17 00:00:00 2001 From: DTB Date: Sun, 7 Jul 2024 18:14:48 -0600 Subject: [PATCH 173/343] dj(1): Io_write: don't add to bufuse --- src/dj.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/dj.c b/src/dj.c index 2be2ecb..4dc4842 100644 --- a/src/dj.c +++ b/src/dj.c @@ -93,7 +93,9 @@ Io_write(struct Io *io){ assert(io->bufuse > 0); assert(io->bufuse <= io->bs); - if((t = write(io->fd, io->buf, io->bufuse)) > 0) + if((t = write(io->fd, io->buf, io->bufuse)) < 0) + t = 0; + else if(t > 0) memmove(io->buf, &(io->buf)[t], (io->bufuse -= t)); io->bytes += t; @@ -268,6 +270,7 @@ int main(int argc, char *argv[]){ t = io[0].bufuse; if(Io_read(&io[0])->bufuse == t && !noerror) Io_read(&io[0]); /* second chance */ + assert(io[0].bufuse >= t); if(io[0].bufuse == t) /* that's all she wrote */ break; @@ -321,6 +324,7 @@ int main(int argc, char *argv[]){ t = io[1].bufuse; if(Io_write(&io[1])->bufuse == t && !noerror) Io_write(&io[1]); /* second chance */ + assert(io[1].bufuse <= t); if(io[1].bufuse == t){ /* no more love */ count = 1; break; From cf744efc1b13d7482c2f234c9f05490e443bb8f3 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 7 Jul 2024 18:21:48 -0600 Subject: [PATCH 174/343] swab(1): fixes not using strerror(3) --- src/swab.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/swab.rs b/src/swab.rs index e723819..5942c38 100644 --- a/src/swab.rs +++ b/src/swab.rs @@ -29,8 +29,11 @@ use getopt::GetOpt; extern crate sysexits; use sysexits::{ EX_OK, EX_OSERR, EX_USAGE }; +extern crate strerror; +use strerror::StrError; + fn oserr(s: &str, e: Error) -> ExitCode { - eprintln!("{}: {}", s, e); + eprintln!("{}: {}", s, e.strerror()); ExitCode::from(EX_OSERR as u8) } From 45329ccb8cd9fe1118ec7c4d3854cb584d52ddad Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 7 Jul 2024 19:19:38 -0600 Subject: [PATCH 175/343] tests/README: initial commit; tests/posix_env, tests/test.sh: updated to match README --- tests/README | 60 +++++++++++++++++++++++++++++++++++++++++++ tests/posix/posix_env | 2 ++ tests/test.sh | 6 +++-- 3 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 tests/README diff --git a/tests/README b/tests/README new file mode 100644 index 0000000..ee370b8 --- /dev/null +++ b/tests/README @@ -0,0 +1,60 @@ +The testing suite contains two main trees (plus translations for strings used in +the shell scripts): the Bonsai tree and the POSIX tree: + +. +├── bonsai +│   ├── test_env +│   ├── dj.sh +│   ├── false.sh +│   ├── fop.sh +│   ├── hru.sh +│   ├── intcmp.sh +│   ├── mm.sh +│   ├── strcmp.sh +│   └── true.sh +├── locales +│   ├── en_US.UTF-8 +│   └── tok +├── posix +│   ├── bin +│   │   ├── cat +│   │   ├── false +│   │   └── true +│   └── posix_env +├── README +└── test.sh + +The Bonsai tree tests the functionality of Harakit utilities for regressions and +other issues relating to compliance to our standards of practice. + +The POSIX tree tests the use of Harakit utilities in place of the standard usage +of POSIX utilities. These scripts test the ability of Harakit to comply to POSIX +standards using its native utilities in shell scripts as a compatibility shim. +Each shell script in the top directory should contain a set of tests for each +POSIX utility and be named for that utility. The bin directory should contain +a set of shim scripts which will be imported into the path as POSIX utilities. +Each test will compare the behavior of the shim script to the real utility on +the system. + +Currently, due to the limitations of POSIX shell quoting, a subset of argument +parsing is supported: arguments containing characters from POSIX’s Portable +Filename Character Set [0]. + +The bonsai/test_env and posix/posix_env files contain prerequisite shared +environments for each of the tests. These scripts both contain lines which set +the shell to write all commands run in them (-x) and to fail if any command +fails (-e). See set(1p) for more information. + +Both sets of tests also inherit the environment set by the test.sh script, which +sets the $BIN environment variable to the bin directory at the root of the +project for easy and idiomatic access to the built Harakit binaries. When +calling the POSIX test scripts, test.sh also sets the variable $realutil to be +the absolute path to the currently tested utility’s counterpart on the system. + +[0] + +-- +Copyright © 2024 Emma Tebibyte + +This work is licensed under CC BY-SA 4.0. To view a copy of this license, visit +. diff --git a/tests/posix/posix_env b/tests/posix/posix_env index 56c5701..b436601 100644 --- a/tests/posix/posix_env +++ b/tests/posix/posix_env @@ -1,3 +1,5 @@ #!/bin/sh +set -ex + PATH="$PWD/bin:$PATH" diff --git a/tests/test.sh b/tests/test.sh index 61bb814..bc68c65 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -28,9 +28,11 @@ for script in tests/bonsai/*.sh; do printf '\n' done -for test in tests/posix/*.sh; do +for test_util in tests/posix/*.sh; do + realutil="$(command -v "$(printf '%s\n' "$test" | sed 's/\.sh$//g')")" + export realutil export PATH="$BIN:$PATH" printf '%s: %s: %s\n' "$0" "$test" "$TEST_STR" - "$utility" + "$test_util" printf '\n' done From 691e94c0c1542a3cdbe6f683e42e8854b5485bbc Mon Sep 17 00:00:00 2001 From: DTB Date: Sun, 7 Jul 2024 20:33:54 -0600 Subject: [PATCH 176/343] dj(1): error reporting more of the time --- src/dj.c | 49 +++++++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/src/dj.c b/src/dj.c index 4dc4842..88c3979 100644 --- a/src/dj.c +++ b/src/dj.c @@ -37,17 +37,18 @@ char *program_name = "dj"; * writing ends of its jockeyed "pipe". User-configurable members are noted * with their relevant options. */ struct Io{ - int bs; /* buffer size (-bB) */ + char *buf; /* buffer */ + char *fn; /* file name (-io) */ + size_t bs; /* buffer size (-bB) */ size_t bufuse; /* buffer usage */ - char *buf; /* buffer */ - size_t bytes; /* bytes processed */ - int fd; /* file descriptor */ - int fl; /* file opening flags */ - char *fn; /* file name (may be stdin_name or stdout_name) (-io) */ - size_t prec; /* partial records processed */ - size_t rec; /* records processed */ - long seek; /* bytes to seek/skip (will be 0 after skippage) (-sS) */ -}; + size_t bytes; /* bytes processed */ + size_t prec; /* partial records processed */ + size_t rec; /* records processed */ + long seek; /* remaining bytes to seek/skip (-sS) */ + int fd; /* file descriptor */ + int fl; /* file opening flags */ + char error: 1; /* (bool) error status */ +}; /* To be assigned to main:fmt and used with printio(). */ static char *fmt_asv = "%d\037%d\036%d\037%d\035%d\036%d\034"; @@ -73,8 +74,10 @@ Io_read(struct Io *io){ assert(io->bs > 0); assert(io->bufuse < io->bs); - if((t = read(io->fd, &(io->buf)[io->bufuse], io->bs - io->bufuse)) < 0) + if((t = read(io->fd, &(io->buf)[io->bufuse], io->bs - io->bufuse)) < 0){ + io->error = 1; t = 0; + } io->bufuse += t; io->bytes += t; @@ -93,9 +96,10 @@ Io_write(struct Io *io){ assert(io->bufuse > 0); assert(io->bufuse <= io->bs); - if((t = write(io->fd, io->buf, io->bufuse)) < 0) + if((t = write(io->fd, io->buf, io->bufuse)) < 0){ + io->error = 1; t = 0; - else if(t > 0) + }else if(t > 0) memmove(io->buf, &(io->buf)[t], (io->bufuse -= t)); io->bytes += t; @@ -158,20 +162,21 @@ int main(int argc, char *argv[]){ char *fmt; /* == fmt_asv (default) or fmt_human (-H) */ size_t i; /* side of io being modified */ char noerror; /* 0=exits (default) 1=retries on partial reads or writes */ - struct Io io[2]; + struct Io io[2 /* { in, out } */]; /* Set defaults. */ align = -1; count = 0; fmt = fmt_asv; noerror = 0; - for(i = 0; i < 2; ++i){ + for(i = 0; i < (sizeof io) / (sizeof *io); ++i){ io[i].bs = 1024 /* 1 KiB */; /* GNU dd(1) default; POSIX says 512B */ io[i].bufuse = 0; io[i].bytes = 0; io[i].fd = i == 0 ? STDIN_FILENO : STDOUT_FILENO; io[i].fn = i == 0 ? stdin_name : stdout_name; io[i].fl = i == 0 ? read_flags : write_flags; + io[i].error = 0; io[i].prec = 0; io[i].rec = 0; io[i].seek = 0; @@ -227,10 +232,10 @@ int main(int argc, char *argv[]){ if(argc > optind) return usage(program_name); - for(i = 0; i < 2; ++i){ + for(i = 0; i < (sizeof io) / (sizeof *io); ++i){ /* buffer allocation */ if((io[i].buf = malloc(io[i].bs * (sizeof *(io[i].buf)))) == NULL){ - fprintf(stderr, "%s: Failed to allocate %d bytes\n", + fprintf(stderr, "%s: Failed to allocate %zd bytes\n", program_name, io[i].bs); return EX_OSERR; } @@ -245,7 +250,7 @@ int main(int argc, char *argv[]){ do{ memset(io[1].buf, '\0', (t = io[1].bufuse = MIN(io[1].bs, io[1].seek))); - if(Io_write(&io[1])->bufuse == t && !noerror) + if(Io_write(&io[1])->bufuse == t && !noerror && !io[1].error) Io_write(&io[1]); /* second chance */ }while((io[1].seek -= (t - io[1].bufuse)) > 0 && io[1].bufuse != t); io[1].bufuse = 0; @@ -268,7 +273,7 @@ int main(int argc, char *argv[]){ io[0].bufuse = io[0].bs - io[0].seek; t = io[0].bufuse; - if(Io_read(&io[0])->bufuse == t && !noerror) + if(Io_read(&io[0])->bufuse == t && !noerror && io[0].error) Io_read(&io[0]); /* second chance */ assert(io[0].bufuse >= t); if(io[0].bufuse == t) /* that's all she wrote */ @@ -322,7 +327,7 @@ int main(int argc, char *argv[]){ } t = io[1].bufuse; - if(Io_write(&io[1])->bufuse == t && !noerror) + if(Io_write(&io[1])->bufuse == t && !noerror && !io[1].error) Io_write(&io[1]); /* second chance */ assert(io[1].bufuse <= t); if(io[1].bufuse == t){ /* no more love */ @@ -341,5 +346,9 @@ int main(int argc, char *argv[]){ fprintio(stderr, fmt, io); + for(i = 0; i < (sizeof io) / (sizeof *io); ++i) + if(io[i].error) + return oserr(io[i].fn); + return EX_OK; } From 5d5a6d2172a5e33399fe143265a205b5f7ffdffb Mon Sep 17 00:00:00 2001 From: DTB Date: Sun, 7 Jul 2024 21:13:44 -0600 Subject: [PATCH 177/343] dj(1): fix retvals --- src/dj.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/dj.c b/src/dj.c index 88c3979..8fe1af3 100644 --- a/src/dj.c +++ b/src/dj.c @@ -45,9 +45,9 @@ struct Io{ size_t prec; /* partial records processed */ size_t rec; /* records processed */ long seek; /* remaining bytes to seek/skip (-sS) */ + int error; /* errno */ int fd; /* file descriptor */ int fl; /* file opening flags */ - char error: 1; /* (bool) error status */ }; /* To be assigned to main:fmt and used with printio(). */ @@ -75,7 +75,7 @@ Io_read(struct Io *io){ assert(io->bufuse < io->bs); if((t = read(io->fd, &(io->buf)[io->bufuse], io->bs - io->bufuse)) < 0){ - io->error = 1; + io->error = errno; t = 0; } @@ -97,7 +97,7 @@ Io_write(struct Io *io){ assert(io->bufuse <= io->bs); if((t = write(io->fd, io->buf, io->bufuse)) < 0){ - io->error = 1; + io->error = errno; t = 0; }else if(t > 0) memmove(io->buf, &(io->buf)[t], (io->bufuse -= t)); @@ -109,13 +109,9 @@ Io_write(struct Io *io){ return io; } -/* Prints an error message suitable for the event of an operating system error, - * with the error itself to be described in the string s. */ static int -oserr(char *s){ - - fprintf(stderr, "%s: %s: %s\n", program_name, s, strerror(errno)); - +oserr(char *e, int n){ + fprintf(stderr, "%s: %s: %s\n", program_name, e, strerror(n)); return EX_OSERR; } @@ -203,7 +199,7 @@ int main(int argc, char *argv[]){ break; } } - return oserr(optarg); + return oserr(optarg, errno); case 'n': noerror = 1; break; case 'H': fmt = fmt_human; break; case 'a': @@ -250,15 +246,17 @@ int main(int argc, char *argv[]){ do{ memset(io[1].buf, '\0', (t = io[1].bufuse = MIN(io[1].bs, io[1].seek))); - if(Io_write(&io[1])->bufuse == t && !noerror && !io[1].error) + if(Io_write(&io[1])->bufuse == t && !noerror && io[1].error == 0) Io_write(&io[1]); /* second chance */ + if(io[1].error != 0) + return oserr(io[1].fn, io[1].error); }while((io[1].seek -= (t - io[1].bufuse)) > 0 && io[1].bufuse != t); io[1].bufuse = 0; } if(io[1].seek > 0){ fprintio(stderr, fmt, io); - return oserr(io[1].fn); + return oserr(io[1].fn, errno); } do{ @@ -273,7 +271,7 @@ int main(int argc, char *argv[]){ io[0].bufuse = io[0].bs - io[0].seek; t = io[0].bufuse; - if(Io_read(&io[0])->bufuse == t && !noerror && io[0].error) + if(Io_read(&io[0])->bufuse == t && !noerror && io[0].error == 0) Io_read(&io[0]); /* second chance */ assert(io[0].bufuse >= t); if(io[0].bufuse == t) /* that's all she wrote */ @@ -327,7 +325,7 @@ int main(int argc, char *argv[]){ } t = io[1].bufuse; - if(Io_write(&io[1])->bufuse == t && !noerror && !io[1].error) + if(Io_write(&io[1])->bufuse == t && !noerror && io[1].error == 0) Io_write(&io[1]); /* second chance */ assert(io[1].bufuse <= t); if(io[1].bufuse == t){ /* no more love */ @@ -348,7 +346,7 @@ int main(int argc, char *argv[]){ for(i = 0; i < (sizeof io) / (sizeof *io); ++i) if(io[i].error) - return oserr(io[i].fn); + return oserr(io[i].fn, io[i].error); return EX_OK; } From a141b952935a8ba07768dd17473564e9604ae0d3 Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 8 Jul 2024 11:30:21 -0600 Subject: [PATCH 178/343] swab(1): remove -f --- docs/swab.1 | 3 --- src/swab.rs | 9 +++------ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/docs/swab.1 b/docs/swab.1 index 42eef95..7c50b15 100644 --- a/docs/swab.1 +++ b/docs/swab.1 @@ -11,7 +11,6 @@ swab \(en swap bytes .SH SYNOPSIS swab -.RB [ -f ] .RB [ -w\ word_size ] .\" .SH DESCRIPTION @@ -20,8 +19,6 @@ Swap the latter and former halves of a block of bytes. .\" .SH OPTIONS -.IP \fB-f\fP -Ignore SIGINT signal. .IP \fB-w\fP\ \fIword_size\fP Configures the word size; that is, the size in bytes of the block size on which to operate. The default word size is 2. The word size must be cleanly divisible diff --git a/src/swab.rs b/src/swab.rs index 5942c38..3bb40a5 100644 --- a/src/swab.rs +++ b/src/swab.rs @@ -18,7 +18,7 @@ use std::{ env::args, - io::{ stdin, stdout, Error, ErrorKind, Read, Write }, + io::{ stdin, stdout, Error, Read, Write }, process::ExitCode, vec::Vec }; @@ -38,7 +38,7 @@ fn oserr(s: &str, e: Error) -> ExitCode { } fn usage(s: &str) -> ExitCode { - eprintln!("Usage: {} [-f] [-w word_size]", s); + eprintln!("Usage: {} [-w word_size]", s); ExitCode::from(EX_USAGE as u8) } @@ -48,12 +48,10 @@ fn main() -> ExitCode { let mut input = stdin(); let mut output = stdout().lock(); - let mut force = false; let mut wordsize: usize = 2; - while let Some(opt) = argv.getopt("fw:") { + while let Some(opt) = argv.getopt("w:") { match opt.opt() { - Ok("f") => force = true, Ok("w") => { if let Some(arg) = opt.arg() { match arg.parse::() { @@ -83,7 +81,6 @@ fn main() -> ExitCode { break oserr(&argv[0], e) } }, - Err(e) if e.kind() == ErrorKind::Interrupted && force => continue, Err(e) => break oserr(&argv[0], e) } } From 35d54d84b0cc7675e72927b9c9513d4344c4f2cd Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 8 Jul 2024 11:31:35 -0600 Subject: [PATCH 179/343] swab(1): don't use the getopt error message --- src/swab.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/swab.rs b/src/swab.rs index 3bb40a5..7889a59 100644 --- a/src/swab.rs +++ b/src/swab.rs @@ -50,7 +50,7 @@ fn main() -> ExitCode { let mut wordsize: usize = 2; - while let Some(opt) = argv.getopt("w:") { + while let Some(opt) = argv.getopt(":w:") { match opt.opt() { Ok("w") => { if let Some(arg) = opt.arg() { From 1fd768057cd0c4fc6ed47e1a9b77ffed2fe608e9 Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 8 Jul 2024 11:45:01 -0600 Subject: [PATCH 180/343] swab(1): don't accept positional arguments --- src/swab.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/swab.rs b/src/swab.rs index 7889a59..5b4c173 100644 --- a/src/swab.rs +++ b/src/swab.rs @@ -48,7 +48,8 @@ fn main() -> ExitCode { let mut input = stdin(); let mut output = stdout().lock(); - let mut wordsize: usize = 2; + let mut optind: usize = 1; // argv[0] + let mut wordsize: usize = 2; // Equivalent to dd(1p). while let Some(opt) = argv.getopt(":w:") { match opt.opt() { @@ -59,11 +60,16 @@ fn main() -> ExitCode { _ => { return usage(&argv[0]); }, } } + optind = opt.ind(); }, _ => { return usage(&argv[0]); } } } + if optind < argv.len() { + return usage(&argv[0]); + } + buf.resize(wordsize, 0); loop { From ca6865688ad7c9dadc796f1ab3e9a5f249fe6284 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 8 Jul 2024 13:22:38 -0600 Subject: [PATCH 181/343] swab(1): updates getopt usage --- src/swab.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/swab.rs b/src/swab.rs index 5b4c173..8573cea 100644 --- a/src/swab.rs +++ b/src/swab.rs @@ -1,5 +1,6 @@ /* * Copyright (c) 2024 DTB + * Copyright (c) 2024 Emma Tebibyte * SPDX-License-Identifier: AGPL-3.0-or-later * * This program is free software: you can redistribute it and/or modify it under @@ -54,12 +55,10 @@ fn main() -> ExitCode { while let Some(opt) = argv.getopt(":w:") { match opt.opt() { Ok("w") => { - if let Some(arg) = opt.arg() { - match arg.parse::() { - Ok(w) if w % 2 == 0 => { wordsize = w; () }, + match opt.arg().unwrap().parse::() { + Ok(w) if w % 2 == 0 => { wordsize = w; }, _ => { return usage(&argv[0]); }, } - } optind = opt.ind(); }, _ => { return usage(&argv[0]); } From b7bc1f16ad4047e6eeb1d48c3d1066b69b0b5d3a Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 8 Jul 2024 14:34:42 -0600 Subject: [PATCH 182/343] swab(1): use the getopt error message --- src/swab.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/swab.rs b/src/swab.rs index 8573cea..dd5b464 100644 --- a/src/swab.rs +++ b/src/swab.rs @@ -52,7 +52,7 @@ fn main() -> ExitCode { let mut optind: usize = 1; // argv[0] let mut wordsize: usize = 2; // Equivalent to dd(1p). - while let Some(opt) = argv.getopt(":w:") { + while let Some(opt) = argv.getopt("w:") { match opt.opt() { Ok("w") => { match opt.arg().unwrap().parse::() { From aa819cabc242697fda8bc61ad89bd2c0a1b30396 Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 8 Jul 2024 22:24:18 -0600 Subject: [PATCH 183/343] tests: bonsai/npc.sh: initial arg parsing tests --- tests/bonsai/npc.sh | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100755 tests/bonsai/npc.sh diff --git a/tests/bonsai/npc.sh b/tests/bonsai/npc.sh new file mode 100755 index 0000000..aa66b4f --- /dev/null +++ b/tests/bonsai/npc.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# Copyright (c) 2024 DTB +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +. tests/bonsai/test_env + +! npc -h + +# arg parsing +npc -e /dev/null \ +# | xargs "$BIN"/intcmp -e 8 \ +# && i="$(printf '20 + %s\n' "$i" | bc)" +#done From 94873a2ddca6fab4cf2a89f553f39cecc427f141 Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 8 Jul 2024 22:25:18 -0600 Subject: [PATCH 184/343] tests: bonsai/dj.sh: iron out some existing tests --- tests/bonsai/dj.sh | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/tests/bonsai/dj.sh b/tests/bonsai/dj.sh index 8016ec3..9919d60 100755 --- a/tests/bonsai/dj.sh +++ b/tests/bonsai/dj.sh @@ -11,17 +11,19 @@ ! dj -h -# This test is theoretically Linux-dependent; write(2) should return -1 on -# error. -# Right now dj(1) interprets the return value of write(2) as the amount of -# bytes written. This can decrement the stored quantity of bytes written, -# which is an int, so doesn't underflow but goes negative. dj(1) tries to -# again to write(2) if an error occurs in which no bytes are written, so in -# total two write(2)s are attempted and so the written byte quantity is -2. -# This is a bug and will change, but for now is at least documented. -dj -Hi /dev/zero -o /dev/full \ - | xargs -I out "$BIN/strcmp" '1+0 > 0+0; 1024 > -2' out +# Linux has a /dev/full pseudodevice useful for testing errors. +case "$(uname)" in +Linux) + dj -Hi /dev/zero -o /dev/full 2>&1 \ + | xargs -I out "$BIN"/strcmp '1+0 > 0+0; 1024 > 0' out + ;; +esac # Read nothing from /dev/null, write nothing to /dev/null. -dj -Hi /dev/null -o /dev/null \ - | xargs -I out "$BIN/strcmp" '0+0 > 0+0; 0 > 0' out +dj -Hi /dev/null -o /dev/null 2>&1 \ + | xargs -I out "$BIN"/strcmp '0+0 > 0+0; 0 > 0' out + +# Test skipping stdin. +#dd count=1 bs=1024 /dev/null \ +# | dj -H -s 24 -o /dev/null 2>&1 \ +# | xargs -I out "$BIN"/strcmp '1+0 > 1+0; 1024 > 1000' out From 0df2c9f56696fb16695c77665654d287eb90298e Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 8 Jul 2024 22:48:16 -0600 Subject: [PATCH 185/343] dj(1): fix infiniskipping --- src/dj.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/dj.c b/src/dj.c index 8fe1af3..e36623e 100644 --- a/src/dj.c +++ b/src/dj.c @@ -263,11 +263,11 @@ int main(int argc, char *argv[]){ assert(io[0].bufuse == 0); { /* read */ - char skipping; + long skipping; size_t t; /* hack to intentionally get a partial read from Io_read */ - if((skipping = (io[0].seek > 0)) && io[0].seek < io[0].bs) + if((skipping = MIN(io[0].seek, io[0].bs)) > 0) io[0].bufuse = io[0].bs - io[0].seek; t = io[0].bufuse; @@ -290,7 +290,8 @@ int main(int argc, char *argv[]){ } } - if(skipping){ + if(skipping > 0){ + io[0].seek -= skipping; io[0].bufuse = 0; count += (count != 0); continue; From 8f8de5de2b8e7f59c73a3506f4360071ddae8ae5 Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 8 Jul 2024 22:53:44 -0600 Subject: [PATCH 186/343] dj(1): fix io[0].bufuse underflow --- src/dj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dj.c b/src/dj.c index e36623e..3b5bc5f 100644 --- a/src/dj.c +++ b/src/dj.c @@ -268,7 +268,7 @@ int main(int argc, char *argv[]){ /* hack to intentionally get a partial read from Io_read */ if((skipping = MIN(io[0].seek, io[0].bs)) > 0) - io[0].bufuse = io[0].bs - io[0].seek; + io[0].bufuse = io[0].bs - (size_t)skipping; t = io[0].bufuse; if(Io_read(&io[0])->bufuse == t && !noerror && io[0].error == 0) From 6cf7fd979416ddac9c4e58ae1ac4336b95232118 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 12 Jul 2024 15:23:57 -0600 Subject: [PATCH 187/343] dj(1): reformatting --- src/dj.c | 233 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 135 insertions(+), 98 deletions(-) diff --git a/src/dj.c b/src/dj.c index 3b5bc5f..9edee0f 100644 --- a/src/dj.c +++ b/src/dj.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2024 DTB + * Copyright (c) 2024 Emma Tebibyte * SPDX-License-Identifier: AGPL-3.0-or-later * * This program is free software: you can redistribute it and/or modify it under @@ -27,8 +28,8 @@ #endif #include /* close(2), getopt(3), lseek(2), read(2), write(2), * optarg, optind, STDIN_FILENO, STDOUT_FILENO */ -#include /* S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, - S_IWUSR */ +#include /* S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR */ + extern int errno; char *program_name = "dj"; @@ -36,7 +37,7 @@ char *program_name = "dj"; /* dj uses two structures that respectively correspond to the reading and * writing ends of its jockeyed "pipe". User-configurable members are noted * with their relevant options. */ -struct Io{ +struct Io { char *buf; /* buffer */ char *fn; /* file name (-io) */ size_t bs; /* buffer size (-bB) */ @@ -67,14 +68,13 @@ static int write_flags = O_WRONLY | O_CREAT; /* Macro to check if fd is stdin or stdout */ #define fdisstd(fd) ((fd) == STDIN_FILENO || (fd) == STDOUT_FILENO) -static struct Io * -Io_read(struct Io *io){ +static struct Io * Io_read(struct Io *io) { int t; assert(io->bs > 0); assert(io->bufuse < io->bs); - if((t = read(io->fd, &(io->buf)[io->bufuse], io->bs - io->bufuse)) < 0){ + if ((t = read(io->fd, &(io->buf)[io->bufuse], io->bs - io->bufuse)) < 0) { io->error = errno; t = 0; } @@ -89,17 +89,16 @@ Io_read(struct Io *io){ return io; } -static struct Io * -Io_write(struct Io *io){ +static struct Io * Io_write(struct Io *io) { int t; assert(io->bufuse > 0); assert(io->bufuse <= io->bs); - if((t = write(io->fd, io->buf, io->bufuse)) < 0){ + if ((t = write(io->fd, io->buf, io->bufuse)) < 0) { io->error = errno; t = 0; - }else if(t > 0) + } else if (t > 0) memmove(io->buf, &(io->buf)[t], (io->bufuse -= t)); io->bytes += t; @@ -109,20 +108,24 @@ Io_write(struct Io *io){ return io; } -static int -oserr(char *e, int n){ +static int oserr(char *e, int n) { fprintf(stderr, "%s: %s: %s\n", program_name, e, strerror(n)); return EX_OSERR; } /* Prints statistics regarding the use of dj, particularly partially and * completely read and written records. */ -static void -fprintio(FILE *stream, char *fmt, struct Io io[2]){ - - fprintf(stream, fmt, - io[0].rec, io[0].prec, io[1].rec, io[1].prec, - io[0].bytes, io[1].bytes); +static void fprintio(FILE *stream, char *fmt, struct Io io[2]) { + fprintf( + stream, + fmt, + io[0].rec, + io[0].prec, + io[1].rec, + io[1].prec, + io[0].bytes, + io[1].bytes + ); return; } @@ -130,8 +133,7 @@ fprintio(FILE *stream, char *fmt, struct Io io[2]){ /* Parses the string s to an integer, returning either the integer or in the * case of an error a negative integer. This is used for argument parsing * (e.g. -B [int]) in dj and no negative integer would be valid anyway. */ -static long -parse(char *s){ +static long parse(char *s){ long r; errno = 0; @@ -141,18 +143,17 @@ parse(char *s){ : -1; } -static int -usage(char *s){ - - fprintf(stderr, "Usage: %s [-Hn] [-a byte] [-c count]\n" +static int usage(char *s){ + fprintf( + stderr, "Usage: %s [-Hn] [-a byte] [-c count]\n" "\t[-i file] [-b block_size] [-s offset]\n" - "\t[-o file] [-B block_size] [-S offset]\n", - program_name); + "\t[-o file] [-B block_size] [-S offset]\n", program_name + ); return EX_USAGE; } -int main(int argc, char *argv[]){ +int main(int argc, char *argv[]) { int align; /* low 8b used, negative if no alignment is being done */ int count; /* 0 if dj(1) runs until no more reads are possible */ char *fmt; /* == fmt_asv (default) or fmt_human (-H) */ @@ -165,7 +166,7 @@ int main(int argc, char *argv[]){ count = 0; fmt = fmt_asv; noerror = 0; - for(i = 0; i < (sizeof io) / (sizeof *io); ++i){ + for (i = 0; i < (sizeof io) / (sizeof *io); ++i) { io[i].bs = 1024 /* 1 KiB */; /* GNU dd(1) default; POSIX says 512B */ io[i].bufuse = 0; io[i].bytes = 0; @@ -178,119 +179,144 @@ int main(int argc, char *argv[]){ io[i].seek = 0; } - if(argc > 0){ - int c; + if (!argc < 0) { usage(program_name); } - program_name = argv[0]; - while((c = getopt(argc, argv, ":a:b:B:c:i:hHns:S:o:")) != -1) - switch(c){ - case 'i': case 'o': i = (c == 'o'); - if(optarg[0] == '-' && optarg[1] == '\0'){ /* optarg == "-" */ + int c; + + program_name = argv[0]; + while ((c = getopt(argc, argv, "a:b:B:c:i:hHns:S:o:")) != -1) { + switch (c) { + case 'i': case 'o': /* input, output */ + i = (c == 'o'); + + /* optarg == "-" (stdin/stdout) */ + if (optarg[0] == '-' && optarg[1] == '\0') { io[i].fd = i == 0 ? STDIN_FILENO : STDOUT_FILENO; io[i].fn = i == 0 ? stdin_name : stdout_name; break; - }else{ + } else { int fd; - if((fd = open(optarg, io[i].fl, creat_mode)) != -1 - && (fdisstd(io[i].fd) || close(io[i].fd) == 0)){ + if (( + fd = open(optarg, io[i].fl, creat_mode)) != -1 + && (fdisstd(io[i].fd) || close(io[i].fd) == 0 + )) { io[i].fd = fd; io[i].fn = optarg; break; } } - return oserr(optarg, errno); - case 'n': noerror = 1; break; - case 'H': fmt = fmt_human; break; - case 'a': - if(optarg[0] == '\0' || optarg[1] == '\0'){ + + return oserr(optarg, errno); /* break; */ + case 'n': noerror = 1; break; /* retry failed reads once */ + case 'H': fmt = fmt_human; break; /* human-readable output */ + case 'a': /* input buffer padding */ + if (optarg[0] == '\0' || optarg[1] == '\0') { align = optarg[0]; break; } /* FALLTHROUGH */ - case 'c': case 'b': case 's': case 'B': case 'S': /* numbers */ - if(c == 'c' && (count = parse(optarg)) >= 0) - break; + case 'c': /* number of reads */ + case 'b': case 'B': /* input/output block size */ + case 's': case 'S': /* (s)kip/(S)eek in input/output */ + if (c == 'c' && (count = parse(optarg)) >= 0) { break; } + i = (c >= 'A' && c <= 'Z'); - c |= 0x20 /* 0b 0010 0000 */; /* (ASCII) make lowercase */ - if((c == 'b' && (io[i].bs = parse(optarg)) > 0) - || (c == 's' && (io[i].seek = parse(optarg)) >= 0)) - break; + c |= 0b00100000; /* (ASCII) make lowercase */ + + if(( + c == 'b' && (io[i].bs = parse(optarg)) > 0) + || (c == 's' && (io[i].seek = parse(optarg)) >= 0 + )) { break; } + /* FALLTHROUGH */ default: return usage(program_name); - } + } } assert(io->fd != STDIN_FILENO || io->fl == read_flags); assert(io->fd != STDOUT_FILENO || io->fl == write_flags); - if(argc > optind) - return usage(program_name); + if (argc > optind) { return usage(program_name); } - for(i = 0; i < (sizeof io) / (sizeof *io); ++i){ + for (i = 0; i < (sizeof io) / (sizeof *io); ++i) { /* buffer allocation */ - if((io[i].buf = malloc(io[i].bs * (sizeof *(io[i].buf)))) == NULL){ + if ((io[i].buf = malloc(io[i].bs * (sizeof *(io[i].buf)))) == NULL) { fprintf(stderr, "%s: Failed to allocate %zd bytes\n", program_name, io[i].bs); return EX_OSERR; } + /* easy seeking */ - if(!fdisstd(io[i].fd) && lseek(io[i].fd, io[i].seek, SEEK_SET) != -1) + if (!fdisstd(io[i].fd) && lseek(io[i].fd, io[i].seek, SEEK_SET) != -1) { io[i].seek = 0; + } } /* hard seeking */ - if(io[1].seek > 0){ + if (io[1].seek > 0) { size_t t; - do{ - memset(io[1].buf, '\0', - (t = io[1].bufuse = MIN(io[1].bs, io[1].seek))); - if(Io_write(&io[1])->bufuse == t && !noerror && io[1].error == 0) + + do { + memset( + io[1].buf, '\0', + (t = io[1].bufuse = MIN(io[1].bs, io[1].seek)) + ); + + if (Io_write(&io[1])->bufuse == t && !noerror && io[1].error == 0) { Io_write(&io[1]); /* second chance */ - if(io[1].error != 0) - return oserr(io[1].fn, io[1].error); - }while((io[1].seek -= (t - io[1].bufuse)) > 0 && io[1].bufuse != t); + } + if (io[1].error != 0) { return oserr(io[1].fn, io[1].error); } + } while ((io[1].seek -= (t - io[1].bufuse)) > 0 && io[1].bufuse != t); + io[1].bufuse = 0; } - if(io[1].seek > 0){ + if (io[1].seek > 0) { fprintio(stderr, fmt, io); return oserr(io[1].fn, errno); } - do{ + do { /* while(count == 0 || --count > 0); */ assert(io[0].bufuse == 0); { /* read */ long skipping; - size_t t; /* hack to intentionally get a partial read from Io_read */ - if((skipping = MIN(io[0].seek, io[0].bs)) > 0) + if ((skipping = MIN(io[0].seek, io[0].bs)) > 0) { io[0].bufuse = io[0].bs - (size_t)skipping; + } - t = io[0].bufuse; - if(Io_read(&io[0])->bufuse == t && !noerror && io[0].error == 0) + size_t t = io[0].bufuse; + if (Io_read(&io[0])->bufuse == t && !noerror && io[0].error == 0) { Io_read(&io[0]); /* second chance */ - assert(io[0].bufuse >= t); - if(io[0].bufuse == t) /* that's all she wrote */ - break; + } - if(/* t < io[0].bufuse && */ io[0].bufuse < io[0].bs){ + assert(io[0].bufuse >= t); + + if (io[0].bufuse == t) /* that's all she wrote */ { break; } + + if (/* t < io[0].bufuse && */ io[0].bufuse < io[0].bs) { fprintf(stderr, "%s: Partial read:\n\t", program_name); fprintio(stderr, fmt, io); - if(!noerror) - count = 1; - if(align >= 0){ + + if (!noerror) { count = 1; } + + if (align >= 0) { /* fill the rest of the ibuf with padding */ - memset(&(io[0].buf)[io[0].bufuse], align, - io[0].bs - io[0].bufuse); + memset( + &(io[0].buf)[io[0].bufuse], + align, + io[0].bs - io[0].bufuse + ); + io->bufuse = io->bs; } } - if(skipping > 0){ + if (skipping > 0) { io[0].seek -= skipping; io[0].bufuse = 0; count += (count != 0); @@ -299,55 +325,66 @@ int main(int argc, char *argv[]){ } /* write */ - do{ + do { /* while(io[0].bufuse > 0); */ int t; - if(io[0].bs <= io[1].bs){ + if (io[0].bs <= io[1].bs) { int n; /* saturate obuf */ - memcpy(io[1].buf, io[0].buf, - (io[1].bufuse = (n = MIN(io[0].bufuse, io[1].bs)))); + memcpy( + io[1].buf, io[0].buf, + (io[1].bufuse = (n = MIN(io[0].bufuse, io[1].bs))) + ); /* permute the copied units out of ibuf */ memmove(io[0].buf, &(io[0].buf)[n], (io[0].bufuse -= n)); - }else /* if(io[0].bs < io[1].bs) */ { + } else /* if(io[0].bs < io[1].bs) */ { int n; /* drain what we can from ibuf */ - memcpy(&(io[1].buf)[io[1].bufuse], io[0].buf, - (n = MIN(io[0].bufuse, io[1].bs - io[1].bufuse))); + memcpy( + &(io[1].buf)[io[1].bufuse], io[0].buf, + (n = MIN(io[0].bufuse, io[1].bs - io[1].bufuse)) + ); + io[1].bufuse += n; + /* permute out the copied units */ memmove(io[0].buf, &(io[0].buf)[n], io[0].bs - n); + io[0].bufuse -= n; - if(io[0].bs + io[1].bufuse <= io[1].bs && count != 1) + if(io[0].bs + io[1].bufuse <= io[1].bs && count != 1) { continue; /* obuf not saturated - we could write more */ + } } t = io[1].bufuse; - if(Io_write(&io[1])->bufuse == t && !noerror && io[1].error == 0) + if (Io_write(&io[1])->bufuse == t && !noerror && io[1].error == 0) { Io_write(&io[1]); /* second chance */ + } + assert(io[1].bufuse <= t); - if(io[1].bufuse == t){ /* no more love */ + + if (io[1].bufuse == t) { /* no more love */ count = 1; break; } - if(0 < io[1].bufuse /* && io[1].bufuse < t */){ + if (0 < io[1].bufuse /* && io[1].bufuse < t */) { fprintf(stderr, "%s: Partial write:\n\t", program_name); fprintio(stderr, fmt, io); - if(!noerror) - count = 1; + + if(!noerror) { count = 1; } } - }while(io[0].bufuse > 0); - }while(count == 0 || --count > 0); + } while(io[0].bufuse > 0); + } while(count == 0 || --count > 0); fprintio(stderr, fmt, io); - for(i = 0; i < (sizeof io) / (sizeof *io); ++i) - if(io[i].error) - return oserr(io[i].fn, io[i].error); + for (i = 0; i < (sizeof io) / (sizeof *io); ++i) { + if (io[i].error) { return oserr(io[i].fn, io[i].error); } + } return EX_OK; } From db0dd02d558b001c22ace501712dd8ab97ab7398 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 12 Jul 2024 15:32:30 -0600 Subject: [PATCH 188/343] dj(1): more formatting --- src/dj.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/dj.c b/src/dj.c index 9edee0f..c0ae9cc 100644 --- a/src/dj.c +++ b/src/dj.c @@ -138,9 +138,7 @@ static long parse(char *s){ errno = 0; r = strtol(s, &s, 0); - return (*s == '\0' /* no chars left unparsed */ && errno == 0) - ? r - : -1; + return (*s == '\0' && errno == 0) ? r : -1; /* no chars left unparsed */ } static int usage(char *s){ @@ -197,10 +195,10 @@ int main(int argc, char *argv[]) { } else { int fd; - if (( - fd = open(optarg, io[i].fl, creat_mode)) != -1 - && (fdisstd(io[i].fd) || close(io[i].fd) == 0 - )) { + if ( + (fd = open(optarg, io[i].fl, creat_mode)) != -1 + && (fdisstd(io[i].fd) || close(io[i].fd) == 0) + ) { io[i].fd = fd; io[i].fn = optarg; break; @@ -224,10 +222,10 @@ int main(int argc, char *argv[]) { i = (c >= 'A' && c <= 'Z'); c |= 0b00100000; /* (ASCII) make lowercase */ - if(( - c == 'b' && (io[i].bs = parse(optarg)) > 0) - || (c == 's' && (io[i].seek = parse(optarg)) >= 0 - )) { break; } + if ( + (c == 'b' && (io[i].bs = parse(optarg)) > 0) + || (c == 's' && (io[i].seek = parse(optarg)) >= 0) + ) { break; } /* FALLTHROUGH */ default: @@ -243,8 +241,10 @@ int main(int argc, char *argv[]) { for (i = 0; i < (sizeof io) / (sizeof *io); ++i) { /* buffer allocation */ if ((io[i].buf = malloc(io[i].bs * (sizeof *(io[i].buf)))) == NULL) { - fprintf(stderr, "%s: Failed to allocate %zd bytes\n", - program_name, io[i].bs); + fprintf( + stderr, "%s: Failed to allocate %zd bytes\n", + program_name, io[i].bs + ); return EX_OSERR; } From 1ad411488250ff93713f8f5461cb5e6e38c64689 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 12 Jul 2024 15:42:24 -0600 Subject: [PATCH 189/343] dj(1): remove unnecessary macros --- src/dj.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/dj.c b/src/dj.c index c0ae9cc..a36123e 100644 --- a/src/dj.c +++ b/src/dj.c @@ -23,9 +23,7 @@ #include /* fprintf(3), stderr */ #include /* malloc(3), strtol(3), size_t */ #include /* memcpy(3), memmove(3), memset(3) */ -#if !defined EX_OK || !defined EX_OSERR || !defined EX_USAGE -# include -#endif +#include #include /* close(2), getopt(3), lseek(2), read(2), write(2), * optarg, optind, STDIN_FILENO, STDOUT_FILENO */ #include /* S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR */ From acc3cf3e90c353461fa45612c64c4ea51eadf760 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 12 Jul 2024 15:43:00 -0600 Subject: [PATCH 190/343] swab(1): formatting, remove gotos --- src/npc.c | 51 +++++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/src/npc.c b/src/npc.c index 1f96668..d17f258 100644 --- a/src/npc.c +++ b/src/npc.c @@ -22,7 +22,12 @@ #include /* getopt(3) */ #include -int main(int argc, char *argv[]){ +int usage(char *s) { + fprintf(stderr, "Usage: %s [-et]\n", s); + return EX_USAGE; +} + +int main(int argc, char *argv[]) { int c; char showend; char showtab; @@ -30,32 +35,30 @@ int main(int argc, char *argv[]){ showend = 0; showtab = 0; - if(argc > 0) - while((c = getopt(argc, argv, "et")) != -1) - switch(c){ - case 'e': showend = 1; break; - case 't': showtab = 1; break; - default: goto usage; - } + if(!argc > 0) { usage(argv[0]); } - if(argc > optind){ -usage: fprintf(stderr, "Usage: %s [-et]\n", argv[0]); - return EX_USAGE; + while ((c = getopt(argc, argv, "et")) != -1) { + switch(c){ + case 'e': showend = 1; break; + case 't': showtab = 1; break; + default: return usage(argv[0]); + } } - while((c = getc(stdin)) != EOF){ - if((c & 0x80) != 0) - fputs("M-", stdout); - switch(c ^ 0x80 /* 0b 1000 0000 */){ - case 0x7f: fputs("^?", stdout); - break; - case '\n': if(showend) - putc('$', stdout); - default: - if(c >= ' ' || c == '\n' || (!showtab && c == '\t')) - putc(c, stdout); - else - fprintf(stdout, "^%c", c + '@'); + if(argc > optind) { return usage(argv[0]); } + + while ((c = getc(stdin)) != EOF) { + if ((c & 0x80) != 0) { fputs("M-", stdout); } + + switch (c ^ 0b10000000) { + case 0x7f: fputs("^?", stdout); break; + case '\n': if (showend) { putc('$', stdout); } + default: + if(c >= ' ' || c == '\n' || (!showtab && c == '\t')) { + putc(c, stdout); + } else { + fprintf(stdout, "^%c", c + '@'); + } } } From 9cfc48c96020b0d36ef05cae7b79179698e678e5 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 12 Jul 2024 15:54:30 -0600 Subject: [PATCH 191/343] intcmp(1): formatting, removed gotos --- src/intcmp.c | 70 ++++++++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/src/intcmp.c b/src/intcmp.c index d6dff0d..ce4a5e0 100644 --- a/src/intcmp.c +++ b/src/intcmp.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2023 DTB + * Copyright (c) 2024 Emma Tebibyte * SPDX-License-Identifier: AGPL-3.0-or-later * * This program is free software: you can redistribute it and/or modify it under @@ -22,16 +23,24 @@ #include /* getopt(3), optind */ #include -/* 0b00? */ /* Equal | -e | 0b001 | 1 */ -#define EQUAL 0x01 /* Greater | -g | 0b010 | 2 */ -/* 0b0?0 */ /* Greater or Equal | -ge | 0b011 | 3 */ -#define GREATER 0x02 /* Less | -l | 0b100 | 4 */ -/* 0b?00 */ /* Less or Equal | -le | 0b101 | 5 */ -#define LESS 0x04 /* Inequal (Greater or Less) | -gl | 0b110 | 6 */ +/* 0b00? */ /* Equal | -e | 0b001 | 1 */ +#define EQUAL 0x01 /* Greater | -g | 0b010 | 2 */ +/* 0b0?0 */ /* Greater or Equal | -ge | 0b011 | 3 */ +#define GREATER 0x02 /* Lesser | -l | 0b100 | 4 */ +/* 0b?00 */ /* Lesser or Equal | -le | 0b101 | 5 */ +#define LESSER 0x04 /* Inequal (Greater or Lesser) | -gl | 0b110 | 6 */ static char *program_name = "intcmp"; -int main(int argc, char *argv[]){ +int usage(char *s) { + fprintf( + stderr, "Usage: %s [-egl] integer integer...\n", + s == NULL ? program_name : s + ); + return EX_USAGE; +} + +int main(int argc, char *argv[]) { int c; size_t i; unsigned char mode; @@ -39,44 +48,41 @@ int main(int argc, char *argv[]){ mode = 0; - if(argc < 3) - goto usage; + if(argc < 3) { return usage(argv[0]); } - while((c = getopt(argc, argv, "egl")) != -1) + while ((c = getopt(argc, argv, "egl")) != -1) { switch(c){ - case 'e': mode |= EQUAL; break; - case 'g': mode |= GREATER; break; - case 'l': mode |= LESS; break; - default: goto usage; + case 'e': mode |= EQUAL; break; + case 'g': mode |= GREATER; break; + case 'l': mode |= LESSER; break; + default: return usage(argv[0]); } - - if(optind + 2 /* ref cmp */ > argc){ -usage: fprintf(stderr, - "Usage: %s [-egl] integer integer...\n", - argv[0] == NULL ? program_name : argv[0]); - return EX_USAGE; } + if(optind + 2 /* ref cmp */ > argc){ return usage(argv[0]); } + i = optind; - do{ r = c; + do{ + r = c; c = strtol(argv[i], &argv[i], 10); - if(*argv[i] != '\0' || errno != 0){ - fprintf(stderr, "%s: argument #%d: Invalid integer\n", - argv[0], (int)i); + + if (*argv[i] != '\0' || errno != 0) { + fprintf( + stderr, "%s: argument #%d: Invalid integer\n", argv[0], (int)i + ); return EX_USAGE; } - if(i == optind) - continue; + if (i == optind) { continue; } /* rule enforcement; if a mode isn't permitted and the numbers * correspond to it, return 1 */ - if( (!(mode & EQUAL) && r == c) - || (!(mode & GREATER) && r > c) - || (!(mode & LESS) && r < c)) - return 1; - }while(++i < argc); + if ( (!(mode & EQUAL) && r == c) + || (!(mode & GREATER) && r > c) + || (!(mode & LESSER) && r < c) + ) { return 1; } + } while(++i < argc); - return 0; + return EX_OK; } From 6e1e3db6c877592056810c22fc5e38d7b0228fc8 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 12 Jul 2024 15:55:36 -0600 Subject: [PATCH 192/343] npc(1): forgot to update copyright --- src/npc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/npc.c b/src/npc.c index d17f258..a6e3ce9 100644 --- a/src/npc.c +++ b/src/npc.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2023 DTB + * Copyright (c) 2024 Emma Tebibyte * SPDX-License-Identifier: AGPL-3.0-or-later * * This program is free software: you can redistribute it and/or modify it under From 5d2872d05046fca6d326c5ae3552dac208ee7787 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 12 Jul 2024 16:04:07 -0600 Subject: [PATCH 193/343] scrut(1): formatting, removes gotos --- src/scrut.c | 62 +++++++++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/src/scrut.c b/src/scrut.c index d85d243..f708eb5 100644 --- a/src/scrut.c +++ b/src/scrut.c @@ -20,9 +20,7 @@ #include /* fprintf(3), stderr, NULL */ #include /* EXIT_FAILURE, EXIT_SUCCESS */ #include /* memset(3), strchr(3) */ -#ifndef EX_USAGE -# include -#endif +#include #include /* access(3), getopt(3), F_OK, R_OK, W_OK, X_OK */ #include /* lstat(3), stat struct, S_ISBLK, S_ISCHR, S_ISDIR, * S_ISFIFO, S_ISGID, S_ISREG, S_ISLNK, S_ISSOCK, @@ -32,48 +30,56 @@ static char args[] = "bcdefghkprsuwxLS"; static char ops[(sizeof args) / (sizeof *args)]; static char *program_name = "scrut"; -int main(int argc, char *argv[]){ +int usage(char *s) { + fprintf( + stderr, + "Usage: %s [-%s] file...\n", + s == NULL ? program_name : s, args + ); + + return EX_USAGE; +} + +int main(int argc, char *argv[]) { struct stat buf; int c; size_t i; char *p; - if(argc < 2) - goto usage; + if (argc < 2) { return usage(argv[0]); } memset(ops, '\0', sizeof ops); - while((c = getopt(argc, argv, args)) != -1) - if((p = strchr(args, c)) == NULL) - goto usage; - else + while ((c = getopt(argc, argv, args)) != -1) { + if ((p = strchr(args, c)) == NULL) { + return usage(argv[0]); + } else { ops[p - args] = c; + } + } + /* straighten out ops */ - for(i = 0, p = ops; i < (sizeof ops) / (sizeof *ops); ++i) + for (i = 0, p = ops; i < (sizeof ops) / (sizeof *ops); ++i) { if(ops[i] != '\0'){ *p = ops[i]; if(&ops[i] != p++) ops[i] = '\0'; } + } - if(optind == argc) - goto usage; + if (optind == argc) { return usage(argv[0]); } argv += optind; - do{ if(access(*argv, F_OK) != 0 || lstat(*argv, &buf) == -1) + do { /* while(*++argv != NULL); */ + if(access(*argv, F_OK) != 0 || lstat(*argv, &buf) == -1) { return EXIT_FAILURE; /* doesn't exist or isn't stattable */ + } - for(i = 0; ops[i] != '\0'; ++i) - if(ops[i] == 'e') + for (i = 0; ops[i] != '\0'; ++i) + if (ops[i] == 'e') { continue; - else if(ops[i] == 'h'){ -usage: fprintf(stderr, "Usage: %s [-%s] file...\n", - argv[0] == NULL - ? program_name - : argv[0], - args); - - return EX_USAGE; - }else if( + } else if (ops[i] == 'h') { + return usage(argv[0]); + } else if ( (ops[i] == 'b' && !S_ISBLK(buf.st_mode)) || (ops[i] == 'c' @@ -99,9 +105,9 @@ usage: fprintf(stderr, "Usage: %s [-%s] file...\n", || (ops[i] == 'L' && !S_ISLNK(buf.st_mode)) || (ops[i] == 'S' - && !S_ISSOCK(buf.st_mode))) - return EXIT_FAILURE; - }while(*++argv != NULL); + && !S_ISSOCK(buf.st_mode)) + ) { return EXIT_FAILURE; } + } while(*++argv != NULL); return EXIT_SUCCESS; } From 59de0262bd5a543c19b494944ef3cfe658d8205d Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 12 Jul 2024 16:15:41 -0600 Subject: [PATCH 194/343] strcmp(1): adds copyright header, formatting, removes unused #include --- src/strcmp.c | 47 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/src/strcmp.c b/src/strcmp.c index 33b73c2..2872788 100644 --- a/src/strcmp.c +++ b/src/strcmp.c @@ -1,24 +1,49 @@ +/* + * Copyright (c) 2023 DTB + * Copyright (c) 2023–2024 Emma Tebibyte + * 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/. + */ + #include /* fprintf(3), stderr */ -#include /* EXIT_FAILURE */ #include static char *program_name = "strcmp"; -int main(int argc, char *argv[]){ +int main(int argc, char *argv[]) { int i; - if(argc < 3){ - fprintf(stderr, "Usage: %s string string...\n", - argv[0] == NULL ? program_name : argv[0]); + if (argc < 3) { + fprintf( + stderr, + "Usage: %s string string...\n", + argv[0] == NULL ? program_name : argv[0] + ); + return EX_USAGE; } - for(; *argv[1] != '\0'; ++argv[1]) - for(i = 2; i < argc; ++i) - if(*argv[i-1] > *argv[i]) + for (; *argv[1] != '\0'; ++argv[1]) { + for(i = 2; i < argc; ++i) { + if (*argv[i-1] > *argv[i]) { return 1; - else if(*argv[i-1] < *argv[i]++) - return -1; /* actually 255 */ + } else if (*argv[i-1] < *argv[i]++) { + return 255; + } + } + } - return 0; + return EX_OK; } From 958bfa52ed3fab3b251bb350f98b76fe7ddaa486 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 12 Jul 2024 16:18:48 -0600 Subject: [PATCH 195/343] scrut(1): more formatting --- src/scrut.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/scrut.c b/src/scrut.c index f708eb5..a0ee93d 100644 --- a/src/scrut.c +++ b/src/scrut.c @@ -59,10 +59,9 @@ int main(int argc, char *argv[]) { /* straighten out ops */ for (i = 0, p = ops; i < (sizeof ops) / (sizeof *ops); ++i) { - if(ops[i] != '\0'){ + if (ops[i] != '\0') { *p = ops[i]; - if(&ops[i] != p++) - ops[i] = '\0'; + if (&ops[i] != p++) { ops[i] = '\0'; } } } From 34cd715e37bb4999cd925a62a4b6764f30f0d81f Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 12 Jul 2024 16:22:56 -0600 Subject: [PATCH 196/343] mm(1): removes unnecessary macros --- src/mm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/mm.c b/src/mm.c index e905b35..231985d 100644 --- a/src/mm.c +++ b/src/mm.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2024 DTB + * Copyright (c) 2024 Emma Tebibyte * SPDX-License-Identifier: AGPL-3.0-or-later * * This program is free software: you can redistribute it and/or modify it under @@ -23,9 +24,7 @@ #include /* free(3), realloc(3) */ #include /* strcmp(3), strerror(3) */ #include /* getopt(3) */ -#if !defined EX_IOERR || !defined EX_OK || !defined EX_OSERR \ - || !defined EX_USAGE -# include +#include #endif extern int errno; From 666c621a02d1ec7ed935b5c3257478d2aadfb63f Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 12 Jul 2024 16:38:50 -0600 Subject: [PATCH 197/343] strcmp(1): more formatting --- src/strcmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strcmp.c b/src/strcmp.c index 2872788..b18f8c8 100644 --- a/src/strcmp.c +++ b/src/strcmp.c @@ -36,7 +36,7 @@ int main(int argc, char *argv[]) { } for (; *argv[1] != '\0'; ++argv[1]) { - for(i = 2; i < argc; ++i) { + for (i = 2; i < argc; ++i) { if (*argv[i-1] > *argv[i]) { return 1; } else if (*argv[i-1] < *argv[i]++) { From 99f2b2963a5f5d7288326edee6836cbb7f5d6ce1 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 12 Jul 2024 16:39:11 -0600 Subject: [PATCH 198/343] dj(1): more formatting --- src/dj.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dj.c b/src/dj.c index a36123e..7a2512e 100644 --- a/src/dj.c +++ b/src/dj.c @@ -96,8 +96,9 @@ static struct Io * Io_write(struct Io *io) { if ((t = write(io->fd, io->buf, io->bufuse)) < 0) { io->error = errno; t = 0; - } else if (t > 0) + } else if (t > 0) { memmove(io->buf, &(io->buf)[t], (io->bufuse -= t)); + } io->bytes += t; io->prec += (t > 0 && io->bufuse > 0); From 1dfad87e8742faae253951d5d43d635a1feb2f8a Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 13 Jul 2024 16:56:56 -0600 Subject: [PATCH 199/343] dj(1): lists sysexits imports, fixes negation --- src/dj.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dj.c b/src/dj.c index 7a2512e..b847b38 100644 --- a/src/dj.c +++ b/src/dj.c @@ -23,7 +23,7 @@ #include /* fprintf(3), stderr */ #include /* malloc(3), strtol(3), size_t */ #include /* memcpy(3), memmove(3), memset(3) */ -#include +#include /* EX_OK, EX_OSERR, EX_USAGE */ #include /* close(2), getopt(3), lseek(2), read(2), write(2), * optarg, optind, STDIN_FILENO, STDOUT_FILENO */ #include /* S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR */ @@ -176,7 +176,7 @@ int main(int argc, char *argv[]) { io[i].seek = 0; } - if (!argc < 0) { usage(program_name); } + if (!(argc < 0)) { usage(program_name); } int c; From d9dd4e60571292b32f7aa94b7bc6b0e01e6ed638 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 13 Jul 2024 16:57:52 -0600 Subject: [PATCH 200/343] intcmp(1): formatting, lists sysexits imports, allows no args --- src/intcmp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/intcmp.c b/src/intcmp.c index ce4a5e0..961b8a9 100644 --- a/src/intcmp.c +++ b/src/intcmp.c @@ -21,7 +21,7 @@ #include /* fprintf(3), stderr */ #include /* strtol(3), size_t, EXIT_FAILURE */ #include /* getopt(3), optind */ -#include +#include /* EX_OK, EX_USAGE */ /* 0b00? */ /* Equal | -e | 0b001 | 1 */ #define EQUAL 0x01 /* Greater | -g | 0b010 | 2 */ @@ -48,7 +48,7 @@ int main(int argc, char *argv[]) { mode = 0; - if(argc < 3) { return usage(argv[0]); } + if (argc == 0 | argc < 3) { return usage(argv[0]); } while ((c = getopt(argc, argv, "egl")) != -1) { switch(c){ From 0c530dffbfc60f65862c8c05222758b4f4149906 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 13 Jul 2024 17:01:53 -0600 Subject: [PATCH 201/343] intcmp(1): formatting, fixes argv[0] ternary and usage function --- src/intcmp.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/intcmp.c b/src/intcmp.c index 961b8a9..132c230 100644 --- a/src/intcmp.c +++ b/src/intcmp.c @@ -33,10 +33,8 @@ static char *program_name = "intcmp"; int usage(char *s) { - fprintf( - stderr, "Usage: %s [-egl] integer integer...\n", - s == NULL ? program_name : s - ); + fprintf(stderr, "Usage: %s [-egl] integer integer...\n", s); + return EX_USAGE; } @@ -45,25 +43,26 @@ int main(int argc, char *argv[]) { size_t i; unsigned char mode; int r; /* reference integer */ + char *s = (argv[0] == NULL ? program_name : argv[0]); mode = 0; - if (argc == 0 | argc < 3) { return usage(argv[0]); } + if (argc == 0 | argc < 3) { return usage(s); } while ((c = getopt(argc, argv, "egl")) != -1) { - switch(c){ + switch (c){ case 'e': mode |= EQUAL; break; case 'g': mode |= GREATER; break; case 'l': mode |= LESSER; break; - default: return usage(argv[0]); + default: return usage(s); } } - if(optind + 2 /* ref cmp */ > argc){ return usage(argv[0]); } + if (optind + 2 /* ref cmp */ > argc) { return usage(s); } i = optind; - do{ + do { r = c; c = strtol(argv[i], &argv[i], 10); @@ -82,7 +81,7 @@ int main(int argc, char *argv[]) { || (!(mode & GREATER) && r > c) || (!(mode & LESSER) && r < c) ) { return 1; } - } while(++i < argc); + } while (++i < argc); return EX_OK; } From 8421f8be8761b322c4eb6afbe1977c24a9172fd7 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 13 Jul 2024 17:02:23 -0600 Subject: [PATCH 202/343] mm(1): specifies sysexits imports --- src/mm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mm.c b/src/mm.c index 231985d..01fd400 100644 --- a/src/mm.c +++ b/src/mm.c @@ -24,8 +24,8 @@ #include /* free(3), realloc(3) */ #include /* strcmp(3), strerror(3) */ #include /* getopt(3) */ -#include -#endif +#include /* EX_IOERR, EX_OK, EX_OSERR, EX_USAGE */ + extern int errno; /* This structure is how open files are tracked. */ From 35a20dca7906eebc221af8672163130af2876aec Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 13 Jul 2024 17:03:41 -0600 Subject: [PATCH 203/343] npc(1): specifies sysexits imports, formatting --- src/npc.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/npc.c b/src/npc.c index a6e3ce9..0892a72 100644 --- a/src/npc.c +++ b/src/npc.c @@ -19,9 +19,9 @@ #include /* fprintf(3), fputs(3), getc(3), putc(3), stdin, stdout, * EOF */ -#include /* EXIT_FAILURE, EXIT_SUCCESS */ +#include /* EXIT_FAILURE */ #include /* getopt(3) */ -#include +#include /* EX_OK, EX_USAGE */ int usage(char *s) { fprintf(stderr, "Usage: %s [-et]\n", s); @@ -36,17 +36,17 @@ int main(int argc, char *argv[]) { showend = 0; showtab = 0; - if(!argc > 0) { usage(argv[0]); } - - while ((c = getopt(argc, argv, "et")) != -1) { - switch(c){ - case 'e': showend = 1; break; - case 't': showtab = 1; break; - default: return usage(argv[0]); + if (argc > 0) { + while ((c = getopt(argc, argv, "et")) != -1) { + switch (c){ + case 'e': showend = 1; break; + case 't': showtab = 1; break; + default: return usage(argv[0]); + } } } - if(argc > optind) { return usage(argv[0]); } + if (argc > optind) { return usage(argv[0]); } while ((c = getc(stdin)) != EOF) { if ((c & 0x80) != 0) { fputs("M-", stdout); } @@ -55,7 +55,7 @@ int main(int argc, char *argv[]) { case 0x7f: fputs("^?", stdout); break; case '\n': if (showend) { putc('$', stdout); } default: - if(c >= ' ' || c == '\n' || (!showtab && c == '\t')) { + if (c >= ' ' || c == '\n' || (!showtab && c == '\t')) { putc(c, stdout); } else { fprintf(stdout, "^%c", c + '@'); From 26b0c93f4d8be439bee4c5171b39a1897425e95e Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 13 Jul 2024 17:04:38 -0600 Subject: [PATCH 204/343] strcmp(1): returns -1, specifies sysexits imports --- src/strcmp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strcmp.c b/src/strcmp.c index b18f8c8..4b6bf3c 100644 --- a/src/strcmp.c +++ b/src/strcmp.c @@ -18,7 +18,7 @@ */ #include /* fprintf(3), stderr */ -#include +#include /* EX_OK, EX_USAGE */ static char *program_name = "strcmp"; @@ -40,7 +40,7 @@ int main(int argc, char *argv[]) { if (*argv[i-1] > *argv[i]) { return 1; } else if (*argv[i-1] < *argv[i]++) { - return 255; + return -1; /* actually 255 */ } } } From c7c6ca2c60d92e58fda3375c4a76ad0d051b2511 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 13 Jul 2024 17:23:31 -0600 Subject: [PATCH 205/343] mm(1): formatting --- src/mm.c | 187 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 110 insertions(+), 77 deletions(-) diff --git a/src/mm.c b/src/mm.c index 01fd400..0aced76 100644 --- a/src/mm.c +++ b/src/mm.c @@ -59,9 +59,9 @@ static char *wharsh = "wb"; * returning the FILE if successful and NULL if not, allocating more memory in * the files buffers as needed. */ static FILE * -Files_append(struct Files *files, FILE *file, char *name){ +Files_append(struct Files *files, FILE *file, char *name) { - if(file == NULL || (files->s == files->a + if (file == NULL || (files->s == files->a && ((files->files = realloc(files->files, (files->a += (files->a == 0) ? ALLOC_INITIAL @@ -83,7 +83,7 @@ Files_append(struct Files *files, FILE *file, char *name){ /* Prints a diagnostic message based on errno and returns an exit status * appropriate for an OS error. */ static int -oserr(char *s, char *r){ +oserr(char *s, char *r) { fprintf(stderr, "%s: %s: %s\n", s, r, strerror(errno)); @@ -94,12 +94,16 @@ oserr(char *s, char *r){ * closing its files and freeing its files and names arrays, returning retval * from main. */ #define terminate \ - for(i = 0; i < 2; ++i){ \ - for(j = 0; j < files[i].s; ++j) \ - if(files[i].files[j] != stdin \ - && files[i].files[j] != stdout \ - && files[i].files[j] != stderr) \ + for (i = 0; i < 2; ++i) { \ + for (j = 0; j < files[i].s; ++j) { \ + if ( \ + files[i].files[j] != stdin \ + && files[i].files[j] != stdout \ + && files[i].files[j] != stderr \ + ) { \ fclose(files[i].files[j]); \ + } \ + } \ free(files[i].files); \ free(files[i].names); \ } \ @@ -107,14 +111,14 @@ oserr(char *s, char *r){ /* Prints a usage text, in which s is the program being run (i.e. argv[0]), and * returns an exit status appropriate for a usage error. */ -int usage(char *s){ +int usage(char *s) { fprintf(stderr, "Usage: %s [-aenu] [-i input]... [-o output]...\n", s); return EX_USAGE; } -int main(int argc, char *argv[]){ +int main(int argc, char *argv[]) { int c; struct Files files[2]; /* {read, write} */ size_t i; @@ -127,70 +131,83 @@ int main(int argc, char *argv[]){ * these initial values will be overwritten, so to, say, use mm(1) * equivalently to tee(1p), -o - will need to be specified before * additional files to ensure standard output is still written. */ - for(i = 0; i < 2; ++i){ + for (i = 0; i < 2; ++i) { files[i].a = 0; files[i].s = 0; files[i].mode = fmode[i]; files[i].files = NULL; files[i].names = NULL; - Files_append(&files[i], i == 0 ? stdin : stdout, - i == 0 ? stdin_name : stdout_name); + + Files_append( + &files[i], + i == 0 ? stdin : stdout, + i == 0 ? stdin_name : stdout_name + ); + files[i].s = 0; } k = 0; - if(argc > 0) - program_name = argv[0]; + if (argc > 0) { program_name = argv[0]; } - if(argc > 1) - while((c = getopt(argc, argv, "aehi:no:u")) != -1) - switch(c){ - case 'a': /* "rb+" -> "ab" */ - files[1].mode[0] = 'a'; - files[1].mode[2] = '\0'; - break; - case 'e': - if(Files_append(&files[1], stderr, stderr_name) != NULL) + if (argc > 1) { + while ((c = getopt(argc, argv, "aehi:no:u")) != -1) { + switch (c){ + case 'a': /* "rb+" -> "ab" */ + files[1].mode[0] = 'a'; + files[1].mode[2] = '\0'; break; - retval = oserr(argv[0], "-e"); - terminate; - case 'i': - if((strcmp(optarg, "-") == 0 && Files_append(&files[0], - stdin, stdin_name) != NULL) - || Files_open(&files[0], optarg) != NULL) - break; - retval = oserr(argv[0], optarg); - terminate; - case 'o': - if((strcmp(optarg, "-") == 0 && Files_append(&files[1], - stdout, stdout_name) != NULL) - || Files_open(&files[1], optarg) != NULL) - break; - /* does not exist, so try to create it */ - if(errno == ENOENT){ - files[1].mode = wharsh; - if(Files_open(&files[1], optarg) != NULL){ - files[1].mode = fmode[1]; + case 'e': + if (Files_append(&files[1], stderr, stderr_name) != NULL) { break; } - } - retval = oserr(argv[0], optarg); - terminate; - case 'n': - if(signal(SIGINT, SIG_IGN) != SIG_ERR) - break; - retval = oserr(argv[0], "-n"); - terminate; - case 'u': - k = 1; - break; - default: - retval = usage(argv[0]); - terminate; - } - if(optind != argc){ + retval = oserr(argv[0], "-e"); + terminate; + case 'i': + if ( + (strcmp(optarg, "-") == 0 + && Files_append(&files[0], stdin, stdin_name) != NULL) + || Files_open(&files[0], optarg) != NULL + ) { break; } + + retval = oserr(argv[0], optarg); + terminate; + case 'o': + if ( + (strcmp(optarg, "-") == 0 + && Files_append(&files[1], stdout, stdout_name) != NULL) + || Files_open(&files[1], optarg) != NULL + ) { break; } + /* does not exist, so try to create it */ + if (errno == ENOENT) { + files[1].mode = wharsh; + + if (Files_open(&files[1], optarg) != NULL) { + files[1].mode = fmode[1]; + break; + } + } + + retval = oserr(argv[0], optarg); + terminate; + case 'n': + if (signal(SIGINT, SIG_IGN) != SIG_ERR) { break; } + + retval = oserr(argv[0], "-n"); + terminate; + case 'u': + k = 1; + break; + default: + retval = usage(argv[0]); + terminate; + } + } + } + + if (optind != argc) { retval = usage(argv[0]); terminate; } @@ -199,37 +216,53 @@ int main(int argc, char *argv[]){ files[1].s += files[1].s == 0; /* Unbuffer files. */ - if(k){ - for(i = 0; - i < files[0].s; - setvbuf(files[0].files[i++], NULL, _IONBF, 0)); - for(i = 0; - i < files[1].s; - setvbuf(files[1].files[i++], NULL, _IONBF, 0)); + if (k) { + for ( + i = 0; i < files[0].s; setvbuf(files[0].files[i++], NULL, _IONBF, 0) + ); + for ( + i = 0; i < files[1].s; setvbuf(files[1].files[i++], NULL, _IONBF, 0) + ); } retval = EX_OK; /* Actual program loop. */ - for(i = 0; i < files[0].s; ++i) /* iterate ins */ - while((c = getc(files[0].files[i])) != EOF) /* iterate chars */ - for(j = 0; j < files[1].s; ++j) /* iterate outs */ - if(putc(c, files[1].files[j]) == EOF){ + for (i = 0; i < files[0].s; ++i) { /* iterate ins */ + while ((c = getc(files[0].files[i])) != EOF) { /* iterate chars */ + for (j = 0; j < files[1].s; ++j) { /* iterate outs */ + if (putc(c, files[1].files[j]) == EOF) { /* notebook's full */ retval = EX_IOERR; - fprintf(stderr, "%s: %s: %s\n", - program_name, files[1].names[j], strerror(errno)); - if(fclose(files[1].files[j]) == EOF) - fprintf(stderr, "%s: %s: %s\n", - program_name, files[1].names[j], strerror(errno)); + fprintf( + stderr, + "%s: %s: %s\n", + program_name, + files[1].names[j], + strerror(errno) + ); + + if (fclose(files[1].files[j]) == EOF) { + fprintf( + stderr, + "%s: %s: %s\n", + program_name, + files[1].names[j], + strerror(errno) + ); + } + /* massage out the tense muscle */ for(k = j--; k < files[1].s - 1; ++k){ files[1].files[k] = files[1].files[k+1]; files[1].names[k] = files[1].names[k+1]; } - if(--files[1].s == 0) - terminate; + + if(--files[1].s == 0) { terminate; } } + } + } + } terminate; } From e4e823a3092822358de0fbafaefe49924391ed82 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 13 Jul 2024 18:03:49 -0600 Subject: [PATCH 206/343] fop(1): adds more comments --- src/fop.rs | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/src/fop.rs b/src/fop.rs index 91c8a72..061815e 100644 --- a/src/fop.rs +++ b/src/fop.rs @@ -32,8 +32,8 @@ use sysexits::{ EX_DATAERR, EX_IOERR, EX_UNAVAILABLE, EX_USAGE }; fn main() { let argv = args().collect::>(); - let mut d = '\u{1E}'.to_string(); - let mut index_arg = 0; + let mut d = '\u{1E}'.to_string(); /* ASCII record separator */ + let mut optind = 0; let usage = format!( "Usage: {} [-d delimiter] index command [args...]", @@ -43,10 +43,9 @@ fn main() { while let Some(opt) = argv.getopt("d:") { match opt.opt() { Ok(_) => { - /* unwrap because Err(OptError::MissingArg) will be returned if - * opt.arg() is None */ + /* delimiter */ d = opt.arg().unwrap(); - index_arg = opt.ind(); + optind = opt.ind(); }, Err(_) => { eprintln!("{}", usage); @@ -55,38 +54,46 @@ fn main() { }; } - let command_arg = index_arg as usize + 1; + /* index of the argv[0] for the operator command */ + let command_arg = optind as usize + 1; - argv.get(command_arg).unwrap_or_else(|| { + /* argv[0] of the operator command */ + let operator = argv.get(command_arg).unwrap_or_else(|| { eprintln!("{}", usage); exit(EX_USAGE); }); - let index = argv[index_arg].parse::().unwrap_or_else(|e| { + /* parse the specified index as a number we can use */ + let index = argv[optind].parse::().unwrap_or_else(|e| { eprintln!("{}: {}: {}", argv[0], argv[1], e); exit(EX_DATAERR); }); let mut buf = String::new(); let _ = stdin().read_to_string(&mut buf); + + /* split the buffer by the delimiter (by default, '\u{1E}') */ let mut fields = buf.split(&d).collect::>(); + /* collect arguments for the operator command */ let opts = argv .iter() .clone() - .skip(command_arg + 1) + .skip(command_arg + 1) /* skip the command name */ .collect::>(); - let mut spawned = Command::new(argv.get(command_arg).unwrap()) - .args(opts) + /* spawn the command to operate on the field */ + let mut spawned = Command::new(operator) + .args(opts) /* spawn with the specified arguments */ .stdin(Stdio::piped()) - .stdout(Stdio::piped()) + .stdout(Stdio::piped()) /* piped stdout to handle output ourselves */ .spawn() .unwrap_or_else( |e| { eprintln!("{}: {}: {}", argv[0], argv[command_arg], e.strerror()); exit(EX_UNAVAILABLE); }); + /* get field we want to pipe into spawned program */ let field = fields.get(index).unwrap_or_else(|| { eprintln!( "{}: {}: No such index in input", @@ -96,9 +103,10 @@ fn main() { exit(EX_DATAERR); }); + /* get the stdin of the newly spawned program and feed it the field val */ if let Some(mut child_stdin) = spawned.stdin.take() { let _ = child_stdin.write_all(field.as_bytes()); - drop(child_stdin); + drop(child_stdin); /* stay safe! drop your children! */ } let output = spawned.wait_with_output().unwrap_or_else(|e| { @@ -106,17 +114,22 @@ fn main() { exit(EX_IOERR); }); + /* get the output with which the original field will be replaced */ let mut replace = output.stdout.clone(); + /* as long as it’s not a newline, set the replacement to the output */ if replace.pop() != Some(b'\n') { replace = output.stdout; } + /* convert the output of the program to UTF-8 */ let new_field = String::from_utf8(replace).unwrap_or_else(|e| { eprintln!("{}: {}: {}", argv[0], argv[command_arg], e); exit(EX_IOERR); }); + /* store the new field in the old fields vector */ fields[index] = &new_field; + /* fop it */ stdout().write_all( fields.join(&d.to_string()).as_bytes() ).unwrap_or_else(|e| { From a9b388fe4b9101d8106064679cac6bfbe25a00c3 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 13 Jul 2024 18:18:32 -0600 Subject: [PATCH 207/343] hru(1): adds more descriptive comments --- src/hru.rs | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/hru.rs b/src/hru.rs index b7937f7..c02d4c1 100644 --- a/src/hru.rs +++ b/src/hru.rs @@ -29,40 +29,45 @@ extern crate sysexits; use strerror::StrError; use sysexits::{ EX_DATAERR, EX_IOERR, EX_SOFTWARE }; +/* list of SI prefixes */ 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") + (3, "k"), /* kilo */ + (6, "M"), /* mega */ + (9, "G"), /* giga */ + (12, "T"), /* tera */ + (15, "P"), /* peta */ + (18, "E"), /* exa */ + (21, "Z"), /* zetta */ + (24, "Y"), /* yotta */ + (27, "R"), /* ronna */ + (30, "Q"), /* quetta */ ]; fn convert(input: u128) -> Result<(f64, (u32, &'static str)), String> { + /* preserve decimal places in output by casting to a float */ + let mut out = (input as f64, (0_u32, "")); - let mut out = (input as f64, (0_u32, "")); - if input < 1000 { return Ok(out); } + if input < 1000 { return Ok(out); } /* too low to convert */ for (n, p) in LIST { let c = match 10_u128.checked_pow(n) { Some(c) => c, - None => { + None => { /* too big for the laws of computing :( */ return Err(format!("10^{}: Integer overflow", n.to_string())); }, }; match c.cmp(&input) { - Ordering::Less => { + Ordering::Less => { /* c < input */ + /* the program will keep assigning out every loop until either + * the list runs out of higher prefix bases or the input is + * greater than the prefix base */ out = (input as f64 / c as f64, (n, p)); }, - Ordering::Equal => { + Ordering::Equal => { /* c == input */ return Ok((input as f64 / c as f64, (n, p))); }, - Ordering::Greater => {}, + Ordering::Greater => {}, /* c > input */ }; } @@ -72,6 +77,7 @@ fn convert(input: u128) -> Result<(f64, (u32, &'static str)), String> { fn main() -> ExitCode { let argv = args().collect::>(); let mut buf = String::new(); + while let Ok(_) = stdin().read_line(&mut buf) { if buf.is_empty() { return ExitCode::SUCCESS; } @@ -96,6 +102,7 @@ fn main() -> ExitCode { let si_prefix = format!("{}B", prefix.1); + /* round output number to one decimal place */ let out = ((number * 10.0).round() / 10.0).to_string(); stdout().write_all(format!("{} {}\n", out, si_prefix).as_bytes()) From b0602388e7663b22e9472646366982984f723b7b Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 13 Jul 2024 18:29:27 -0600 Subject: [PATCH 208/343] rpn(1): better comments --- src/rpn.rs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/rpn.rs b/src/rpn.rs index 2bfbbf5..784e323 100644 --- a/src/rpn.rs +++ b/src/rpn.rs @@ -57,7 +57,7 @@ extern crate sysexits; use sysexits::EX_DATAERR; #[derive(Clone, PartialEq, PartialOrd, Debug)] -// enum CalcType is a type containing operations used in the calculator +/* enum CalcType is a type containing operations used in the calculator */ enum CalcType { Add, Subtract, @@ -117,8 +117,8 @@ struct EvaluationError { code: i32, } -// I’m no math nerd but I want the highest possible approximation of 0.9 -// repeating and it seems this can give it to me +/* I’m no math nerd but I want the highest possible approximation of 0.9 + * repeating and it seems this can give it to me */ const PRECISION_MOD: f64 = 0.9 + f64::EPSILON * 100.0; fn eval( @@ -133,7 +133,7 @@ fn eval( return Ok((stack, oper)); } - // Split the input into tokens. + /* Split the input into tokens. */ let mut toks: VecDeque = input .split_whitespace() .rev() @@ -183,7 +183,7 @@ fn eval( Ok((stack, oper)) } -// Round a float to the given precision level +/* Round a float to the given precision level */ fn round_precise(value: &f64, precision: usize) -> f64 { let multiplier = 10_f64.powi(precision as i32); (value * multiplier).round() / multiplier @@ -193,11 +193,11 @@ fn main() -> ExitCode { let argv = args().collect::>(); let mut stack = VecDeque::new(); let mut buf = String::new(); - // Set floating-point precision for correcting rounding errors based on - // machine epsilon + /* Set floating-point precision for correcting rounding errors based on + * machine epsilon */ let precision = (-f64::EPSILON.log10() * PRECISION_MOD).ceil() as usize; - if argv.get(1).is_none() { + if argv.get(1).is_none() { /* read from stdin */ while let Ok(_) = stdin().read_line(&mut buf) { match eval(&buf.trim(), stack) { Ok(s) => { @@ -219,12 +219,13 @@ fn main() -> ExitCode { }, }; } - } else { + } else { /* read from argv */ + /* join argv into an owned String joined by spaces minus argv[0] */ let input = argv .iter() .skip(1) .map(|x| x.to_owned()) - .collect::>() + .collect::>() .join(" "); match eval(&input, stack) { @@ -233,7 +234,7 @@ fn main() -> ExitCode { let val = match stack.iter().last() { Some(v) => v, - None => return ExitCode::from(0), + None => return ExitCode::SUCCESS, }; println!("{}", round_precise(val, precision).to_string()) @@ -244,5 +245,5 @@ fn main() -> ExitCode { }, }; } - ExitCode::from(0) + ExitCode::SUCCESS } From 579bf3b622b161f6d0fd2e232bacd7044a1e5d5a Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 13 Jul 2024 23:47:50 -0600 Subject: [PATCH 209/343] STYLE: initial commit --- STYLE | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 STYLE diff --git a/STYLE b/STYLE new file mode 100644 index 0000000..01940d9 --- /dev/null +++ b/STYLE @@ -0,0 +1,56 @@ +- Braces are mandatory for all control flow +- Indentation should be kept to a minimum +- Empty lines should be placed between different kinds of statements: + +int t; + +assert(io->bufuse > 0); +assert(io->bufuse <= io->bs); + +if ((t = write(io->fd, io->buf, io->bufuse)) < 0) { + io->error = errno; + t = 0; +} else if (t > 0) { + memmove(io->buf, &(io->buf)[t], (io->bufuse -= t)); +} + +io->bytes += t; +io->prec += (t > 0 && io->bufuse > 0); +io->rec += (t > 0 && io->bufuse == 0); + +return io; + +- Cases in switch statements and matches in match statements should be indented + one level +- In C, spaces should be placed in control flow statements after the keyword and + before the opening brace: + +for (i = 2; i < argc; ++i) { + +- If a function, a C control flow statement, or a Rust macro has arguments that + cause the statement to be broken into multiple lines, this should be done by + placing the arguments on a new line inside the parentheses: + +let usage = format!( + "Usage: {} [-d delimiter] index command [args...]", + argv[0], +); + +- If Rust function arguments or fields are on their own lines, they should + always have a trailing comma. + +- If text is on the same line as a brace, spaces should be placed after an + opening curly brace and before a closing one: + +use sysexits::{ EX_DATAERR, EX_IOERR, EX_UNAVAILABLE, EX_USAGE }; + +- If a control flow statement is short enough to be easily understood in a + glance, it may be placed on a single line: + +if (!argc < 0) { usage(program_name); }if (!(argc < 0)) { usage(program_name); } + +-- +Copyright © 2024 Emma Tebibyte + +This work is licensed under CC BY-SA 4.0. To view a copy of this license, visit +. From b22ded9e98a68e56dae6efb878f2ad685bd95af2 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 14 Jul 2024 02:15:07 -0600 Subject: [PATCH 210/343] STYLE: adds do while rule --- STYLE | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/STYLE b/STYLE index 01940d9..5560aa3 100644 --- a/STYLE +++ b/STYLE @@ -47,7 +47,12 @@ use sysexits::{ EX_DATAERR, EX_IOERR, EX_UNAVAILABLE, EX_USAGE }; - If a control flow statement is short enough to be easily understood in a glance, it may be placed on a single line: -if (!argc < 0) { usage(program_name); }if (!(argc < 0)) { usage(program_name); } +if (!argc < 0) { usage(program_name); } + +- If a do while loop in C is longer than ~25 lines, place the while statement + in a comment after the opening brace: + +do { /* while(count == 0 || --count > 0); */ -- Copyright © 2024 Emma Tebibyte From aa074ad9b6d2feb74ad7e8baab76d24ca3f4a08f Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 14 Jul 2024 02:37:37 -0600 Subject: [PATCH 211/343] dj.1: fixes ambiguity in block size options --- docs/dj.1 | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index d358e3f..1440ff4 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH DJ 1 2024-07-03 "Harakit X.X.X" +.TH DJ 1 2024-07-14 "Harakit X.X.X" .SH NAME dj \(en disk jockey .\" @@ -56,9 +56,9 @@ bytes read to this point are discarded. .IP \fB-o\fP Takes a file path as an argument and opens it for use as an output. .IP \fB-B\fP\ \fIblock_size\fP -Does the same as -.B -b -but for the output buffer. +Takes a numeric argument as the size in bytes of the output buffer, the default +being 1024. Note that this option only affects the size of output writes and not +the amount of output data itself. See the CAVEATS section. .IP \fB-S\fP Takes a numeric argument as the index of the byte at which writing will commence; \(lqseeks\(rq that number of bytes. If the standard output is used, @@ -68,8 +68,8 @@ Accepts a single literal byte with which the input buffer is padded in the event of an incomplete read from the input file. If the option argument is empty, the null byte is used. .IP \fB-c\fP -Specifies a number of reads to make. The default is 0, in which case the -input is read until a partial or empty read is made. +Specifies a number of blocks to read. The default is 0, in which case the input +is read until a partial or empty read is made. .IP \fB-H\fP Prints diagnostic messages in a human-readable manner as described in the DIAGNOSTICS section. @@ -181,15 +181,22 @@ option is specified, this could make written data nonsensical. Existing files are not truncated on ouput and are instead overwritten. -The options -.B -b -and +Option variants that have uppercase and lowercase forms could be confused for +each other. The former affects input and the latter affects output. + +The .B -B -could be confused for each other, and so could -.B -s +option could be mistaken for write size, meaning the count in bytes of data +placed in the output. This conception is intuitive but incorrect; the amount of +data read and output is controlled by the +.B -c and -.BR -S . -The lowercase option affects input and the capitalized option affects output. +.B -b +options. The latter sets the size of blocks to be read and the former sets the +number of blocks to be read. The +.B -B +option is similar to the latter but sets the size of blocks to be written, +regardless of the amount of data that will actually be written. The skipped or sought bytes while processing irregular files, such as streams, are reported in the diagnostic output, because they were actually read or From fe0c631d42aed6f8eb97351f0efcb24b4aa8678b Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 14 Jul 2024 02:41:59 -0600 Subject: [PATCH 212/343] dj.1: reverts change to hex literals --- src/dj.c | 2 +- src/npc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dj.c b/src/dj.c index b847b38..53adb61 100644 --- a/src/dj.c +++ b/src/dj.c @@ -219,7 +219,7 @@ int main(int argc, char *argv[]) { if (c == 'c' && (count = parse(optarg)) >= 0) { break; } i = (c >= 'A' && c <= 'Z'); - c |= 0b00100000; /* (ASCII) make lowercase */ + c |= 0x20 /* ASCII make lowercase 0b 0010 0000 */ if ( (c == 'b' && (io[i].bs = parse(optarg)) > 0) diff --git a/src/npc.c b/src/npc.c index 0892a72..d160523 100644 --- a/src/npc.c +++ b/src/npc.c @@ -51,7 +51,7 @@ int main(int argc, char *argv[]) { while ((c = getc(stdin)) != EOF) { if ((c & 0x80) != 0) { fputs("M-", stdout); } - switch (c ^ 0b10000000) { + switch (c ^ 0x80) { /* 0b 1000 0000 */ case 0x7f: fputs("^?", stdout); break; case '\n': if (showend) { putc('$', stdout); } default: From fd1ed79329c25563bc128de278d2e43c7979b929 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 14 Jul 2024 02:43:01 -0600 Subject: [PATCH 213/343] dj(1): return top-of-scope variable --- src/dj.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dj.c b/src/dj.c index 53adb61..1dead90 100644 --- a/src/dj.c +++ b/src/dj.c @@ -282,13 +282,14 @@ int main(int argc, char *argv[]) { { /* read */ long skipping; + size_t t; /* hack to intentionally get a partial read from Io_read */ if ((skipping = MIN(io[0].seek, io[0].bs)) > 0) { io[0].bufuse = io[0].bs - (size_t)skipping; } - size_t t = io[0].bufuse; + t = io[0].bufuse; if (Io_read(&io[0])->bufuse == t && !noerror && io[0].error == 0) { Io_read(&io[0]); /* second chance */ } From 49031102f2b3cb36dc338487c039062ce84b5dd8 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 14 Jul 2024 03:17:21 -0600 Subject: [PATCH 214/343] npc(1): commenting --- src/npc.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/npc.c b/src/npc.c index d160523..34fb9ce 100644 --- a/src/npc.c +++ b/src/npc.c @@ -30,11 +30,8 @@ int usage(char *s) { int main(int argc, char *argv[]) { int c; - char showend; - char showtab; - - showend = 0; - showtab = 0; + char showend = 0; /* print a dollar sign before each newline */ + char showtab = 0; /* prints tab characters in caret notation */ if (argc > 0) { while ((c = getopt(argc, argv, "et")) != -1) { @@ -52,7 +49,7 @@ int main(int argc, char *argv[]) { if ((c & 0x80) != 0) { fputs("M-", stdout); } switch (c ^ 0x80) { /* 0b 1000 0000 */ - case 0x7f: fputs("^?", stdout); break; + case 0x7f: fputs("^?", stdout); break; /* delete character */ case '\n': if (showend) { putc('$', stdout); } default: if (c >= ' ' || c == '\n' || (!showtab && c == '\t')) { From 3c243e4a09a55e7659f703b13a1c50f9ce82d5d9 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 14 Jul 2024 03:20:15 -0600 Subject: [PATCH 215/343] str(1): formatting --- src/str.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/str.c b/src/str.c index b4725eb..73bb911 100644 --- a/src/str.c +++ b/src/str.c @@ -29,7 +29,7 @@ static char *program_name = "str"; static struct { char *name; int (*f)(int); -}ctypes[] = { +} ctypes[] = { { "isalnum", isalnum }, { "isalpha", isalpha }, { "isblank", isblank }, @@ -49,27 +49,33 @@ int main(int argc, char *argv[]){ int i; int r; - if(argc >= 3){ - for(ctype = 0; ctype < (sizeof ctypes) / (sizeof *ctypes); - ++ctype) - if(strcmp(argv[1], ctypes[ctype].name) == 0) + if (argc >= 3) { + for (ctype = 0; ctype < (sizeof ctypes) / (sizeof *ctypes); ++ctype) { + if(strcmp(argv[1], ctypes[ctype].name) == 0) { goto pass; + } + } } - fprintf(stderr, "Usage: %s type string...\n", - argv[0] == NULL ? program_name : argv[0]); + fprintf( + stderr, + "Usage: %s type string...\n", + argv[0] == NULL ? program_name : argv[0] + ); return EX_USAGE; -pass: for(argv += 2, r = 1; *argv != NULL; ++argv) - for(i = 0; argv[0][i] != '\0'; ++i) +pass: for (argv += 2, r = 1; *argv != NULL; ++argv) { + for (i = 0; argv[0][i] != '\0'; ++i) { /* First checks if argv[0][i] is valid ASCII; ctypes(3) * don't handle non-ASCII. * This is bad. */ - if((unsigned char)argv[0][i] < 0x80 && !ctypes[ctype].f(argv[0][i])) - return 1; - else - r = 0; + if( + (unsigned char)argv[0][i] < 0x80 && !ctypes[ctype].f(argv[0][i]) + ) { return 1; } + else { r = 0; } + } + } return r; } From ab003f7d4aff847bdf3f836331c58ecb663a859f Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 14 Jul 2024 03:25:52 -0600 Subject: [PATCH 216/343] strcmp(1): commenting --- src/strcmp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/strcmp.c b/src/strcmp.c index 4b6bf3c..c9d56b0 100644 --- a/src/strcmp.c +++ b/src/strcmp.c @@ -37,8 +37,10 @@ int main(int argc, char *argv[]) { for (; *argv[1] != '\0'; ++argv[1]) { for (i = 2; i < argc; ++i) { - if (*argv[i-1] > *argv[i]) { + /* a former string has a greater byte value */ + if (*argv[i-1] > *argv[i]) { return 1; + /* a latter string has a greater byte value */ } else if (*argv[i-1] < *argv[i]++) { return -1; /* actually 255 */ } From 699893af892788d10f8c4664ae6b08a3f7d4017d Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 15 Jul 2024 03:09:00 -0600 Subject: [PATCH 217/343] intcmp(1): initial rust impl --- src/intcmp.rs | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 src/intcmp.rs diff --git a/src/intcmp.rs b/src/intcmp.rs new file mode 100644 index 0000000..470e751 --- /dev/null +++ b/src/intcmp.rs @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2023–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/. + */ + +// /* 0b00? */ /* Equal | -e | 0b001 | 1 */ +// #define EQUAL 0x01 /* Greater | -g | 0b010 | 2 */ +// /* 0b0?0 */ /* Greater or Equal | -ge | 0b011 | 3 */ +// #define GREATER 0x02 /* Less | -l | 0b100 | 4 */ +// /* 0b?00 */ /* Less or Equal | -le | 0b101 | 5 */ +// #define LESS 0x04 /* Inequal (Greater or Less) | -gl | 0b110 | 6 */ + +use std::{ + env::args, + process::ExitCode +}; + +fn usage(s: &str) -> ExitCode { + eprintln!("Usage: {} [-egl] integer integer...", s); + ExitCode::from(EX_USAGE as u8) +} + +fn main() -> ExitCode { + let argv = args().collect::>(); + let mut can_eq = false; + let mut can_gt = false; + let mut can_lt = false; + let mut optind = 0; + + if argv.len() < 3 { return usage(&argv[0]); } + + while let Some(opt) = argv.getopt("egl") { + match opt.opt() { + Ok("e") => can_eq = true, + Ok("g") => can_gt = true, + Ok("l") => can_lt = true, + _ => { return usage(&argv[0]); }, + } + optind = opt.ind(); + } + + if argv.len() - optind < 2 /* ref cmp */ { return usage(&argv[0]); } + + let mut reference = None; + let mut cmpn: usize; + + for arg in argv.iter().skip(optind) { + match arg.parse::() { + Ok(n) => cmpn = n, + _ => { + eprintln!("{}: {}: Invalid integer", &argv[0], arg); + return ExitCode::from(EX_USAGE as u8); + } + } + + if let Some(refn) = reference { + if (!can_eq && refn == cmpn) + || (!can_gt && refn > cmpn) + || (!can_lt && refn < cmpn) + { return ExitCode::FAILURE; } + } + } + + ExitCode::SUCCESS +} From 2f2270322adb2839c4a18298090624a4db12f36b Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 15 Jul 2024 03:14:57 -0600 Subject: [PATCH 218/343] intcmp(1): rewrite in rust --- Makefile | 4 +-- src/intcmp.c | 82 --------------------------------------------------- src/intcmp.rs | 17 ++++++----- 3 files changed, 11 insertions(+), 92 deletions(-) delete mode 100644 src/intcmp.c diff --git a/Makefile b/Makefile index 5e2c70d..8f1f6d9 100644 --- a/Makefile +++ b/Makefile @@ -109,8 +109,8 @@ build/bin/hru: src/hru.rs build rustlibs .PHONY: intcmp intcmp: build/bin/intcmp -build/bin/intcmp: src/intcmp.c build - $(CC) $(CFLAGS) -o $@ src/intcmp.c +build/bin/intcmp: src/intcmp.rs build rustlibs + $(RUSTC) $(RUSTFLAGS) $(RUSTLIBS) -o $@ src/intcmp.rs .PHONY: mm mm: build/bin/mm diff --git a/src/intcmp.c b/src/intcmp.c deleted file mode 100644 index d6dff0d..0000000 --- a/src/intcmp.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2023 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/. - */ - -#include /* errno */ -#include /* fprintf(3), stderr */ -#include /* strtol(3), size_t, EXIT_FAILURE */ -#include /* getopt(3), optind */ -#include - -/* 0b00? */ /* Equal | -e | 0b001 | 1 */ -#define EQUAL 0x01 /* Greater | -g | 0b010 | 2 */ -/* 0b0?0 */ /* Greater or Equal | -ge | 0b011 | 3 */ -#define GREATER 0x02 /* Less | -l | 0b100 | 4 */ -/* 0b?00 */ /* Less or Equal | -le | 0b101 | 5 */ -#define LESS 0x04 /* Inequal (Greater or Less) | -gl | 0b110 | 6 */ - -static char *program_name = "intcmp"; - -int main(int argc, char *argv[]){ - int c; - size_t i; - unsigned char mode; - int r; /* reference integer */ - - mode = 0; - - if(argc < 3) - goto usage; - - while((c = getopt(argc, argv, "egl")) != -1) - switch(c){ - case 'e': mode |= EQUAL; break; - case 'g': mode |= GREATER; break; - case 'l': mode |= LESS; break; - default: goto usage; - } - - if(optind + 2 /* ref cmp */ > argc){ -usage: fprintf(stderr, - "Usage: %s [-egl] integer integer...\n", - argv[0] == NULL ? program_name : argv[0]); - return EX_USAGE; - } - - i = optind; - - do{ r = c; - c = strtol(argv[i], &argv[i], 10); - if(*argv[i] != '\0' || errno != 0){ - fprintf(stderr, "%s: argument #%d: Invalid integer\n", - argv[0], (int)i); - return EX_USAGE; - } - - if(i == optind) - continue; - - /* rule enforcement; if a mode isn't permitted and the numbers - * correspond to it, return 1 */ - if( (!(mode & EQUAL) && r == c) - || (!(mode & GREATER) && r > c) - || (!(mode & LESS) && r < c)) - return 1; - }while(++i < argc); - - return 0; -} diff --git a/src/intcmp.rs b/src/intcmp.rs index 470e751..88be72c 100644 --- a/src/intcmp.rs +++ b/src/intcmp.rs @@ -16,18 +16,17 @@ * along with this program. If not, see https://www.gnu.org/licenses/. */ -// /* 0b00? */ /* Equal | -e | 0b001 | 1 */ -// #define EQUAL 0x01 /* Greater | -g | 0b010 | 2 */ -// /* 0b0?0 */ /* Greater or Equal | -ge | 0b011 | 3 */ -// #define GREATER 0x02 /* Less | -l | 0b100 | 4 */ -// /* 0b?00 */ /* Less or Equal | -le | 0b101 | 5 */ -// #define LESS 0x04 /* Inequal (Greater or Less) | -gl | 0b110 | 6 */ - use std::{ env::args, process::ExitCode }; +extern crate getopt; +use getopt::GetOpt; + +extern crate sysexits; +use sysexits::EX_USAGE; + fn usage(s: &str) -> ExitCode { eprintln!("Usage: {} [-egl] integer integer...", s); ExitCode::from(EX_USAGE as u8) @@ -54,7 +53,7 @@ fn main() -> ExitCode { if argv.len() - optind < 2 /* ref cmp */ { return usage(&argv[0]); } - let mut reference = None; + let mut reference: Option = None; let mut cmpn: usize; for arg in argv.iter().skip(optind) { @@ -72,6 +71,8 @@ fn main() -> ExitCode { || (!can_lt && refn < cmpn) { return ExitCode::FAILURE; } } + + reference = Some(cmpn); } ExitCode::SUCCESS From 8d743dab7a2dc32f47c50e7a64e3b93a47730001 Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 15 Jul 2024 03:43:25 -0600 Subject: [PATCH 219/343] strcmp(1): add copyright header I could trace strcmp(1) as far back as in my repo. --- src/strcmp.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/strcmp.c b/src/strcmp.c index 33b73c2..bd42054 100644 --- a/src/strcmp.c +++ b/src/strcmp.c @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2022–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/. + */ + #include /* fprintf(3), stderr */ #include /* EXIT_FAILURE */ #include From 5caefbb465eccdf1062fb6f01cbeecaf31d86d5d Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 15 Jul 2024 03:45:36 -0600 Subject: [PATCH 220/343] strcmp(1): note used sysexit --- src/strcmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strcmp.c b/src/strcmp.c index bd42054..f2b86bb 100644 --- a/src/strcmp.c +++ b/src/strcmp.c @@ -18,7 +18,7 @@ #include /* fprintf(3), stderr */ #include /* EXIT_FAILURE */ -#include +#include /* EX_USAGE */ static char *program_name = "strcmp"; From d87c278be5f071f01c3611411c665b92d35ad914 Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 15 Jul 2024 04:21:50 -0600 Subject: [PATCH 221/343] strcmp(1): re-style, tweak exits --- src/strcmp.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/strcmp.c b/src/strcmp.c index f2b86bb..7de36a5 100644 --- a/src/strcmp.c +++ b/src/strcmp.c @@ -17,26 +17,26 @@ */ #include /* fprintf(3), stderr */ -#include /* EXIT_FAILURE */ +#include /* size_t */ #include /* EX_USAGE */ -static char *program_name = "strcmp"; +static *program_name = "strcmp"; int main(int argc, char *argv[]){ - int i; - - if(argc < 3){ + if (argc < 3) { fprintf(stderr, "Usage: %s string string...\n", - argv[0] == NULL ? program_name : argv[0]); + argv[0] == NULL ? program_name : argv[0] + ); return EX_USAGE; } - for(; *argv[1] != '\0'; ++argv[1]) - for(i = 2; i < argc; ++i) - if(*argv[i-1] > *argv[i]) - return 1; - else if(*argv[i-1] < *argv[i]++) - return -1; /* actually 255 */ + for (; *argv[1] != '\0'; ++argv[1]) { /* iterate chars in ref */ + /* iterate argc */ + for (size_t i = 2 /* ref cmp */; i < argc; ++argv[i], ++i) { + /* this doesn't overrun because of nul termination */ + if (*argv[i-1] != *argv[i]) { return *argv[i-1] - *argv[i]; } + } + } return 0; } From 16f23e11c0dde95690ed1a2ec969170073493f24 Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 15 Jul 2024 04:26:57 -0600 Subject: [PATCH 222/343] strcmp.1: update docs to match utility --- docs/strcmp.1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/strcmp.1 b/docs/strcmp.1 index c99c8c8..db6d3e8 100644 --- a/docs/strcmp.1 +++ b/docs/strcmp.1 @@ -4,7 +4,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH STRCMP 1 2024-06-17 "Harakit X.X.X" +.TH STRCMP 1 2024-07-15 "Harakit X.X.X" .SH NAME strcmp \(en compare strings .\" @@ -20,15 +20,15 @@ Check whether string arguments are the same. .SH DIAGNOSTICS The program will exit successfully if the strings are identical. Otherwise, it -will exit with an error code of 1 if a string passed has a lesser byte value -than one of the prior strings: +will exit with an error code less than 128 if a string passed has a lesser byte +value than one of the prior strings: .RS strcmp b a .RE -or with an error code of 255 if it has a greater byte value than one of the -prior strings: +or with an error code greater than 128 if it has a greater byte value than one +of the prior strings: .RS strcmp a b From efb3ce626d28f3ae8dea04f22cf54adc713f03a7 Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 15 Jul 2024 04:29:43 -0600 Subject: [PATCH 223/343] strcmp(1): fix program_name type --- src/strcmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strcmp.c b/src/strcmp.c index 7de36a5..784029c 100644 --- a/src/strcmp.c +++ b/src/strcmp.c @@ -20,7 +20,7 @@ #include /* size_t */ #include /* EX_USAGE */ -static *program_name = "strcmp"; +char *program_name = "strcmp"; int main(int argc, char *argv[]){ if (argc < 3) { From 1b3b03cae093e6e343fb5bf021dd2c303375a3cd Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 13 Jul 2024 23:49:27 -0600 Subject: [PATCH 224/343] mm(1): rewritten in Rust --- Makefile | 4 +- src/mm.c | 236 ------------------------------------------------------ src/mm.rs | 137 +++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 238 deletions(-) delete mode 100644 src/mm.c create mode 100644 src/mm.rs diff --git a/Makefile b/Makefile index 5e2c70d..a523591 100644 --- a/Makefile +++ b/Makefile @@ -114,8 +114,8 @@ build/bin/intcmp: src/intcmp.c build .PHONY: mm mm: build/bin/mm -build/bin/mm: src/mm.c build - $(CC) $(CFLAGS) -o $@ src/mm.c +build/bin/mm: src/mm.rs build rustlibs + $(RUSTC) $(RUSTFLAGS) $(RUSTLIBS) -o $@ src/mm.rs .PHONY: npc npc: build/bin/npc diff --git a/src/mm.c b/src/mm.c deleted file mode 100644 index e905b35..0000000 --- a/src/mm.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * 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/. - */ - -#include /* errno */ -#include /* signal(2), SIG_ERR, SIG_IGN, SIGINT */ -#include /* fclose(3), fopen(3), fprintf(3), getc(3), putc(3), - * setvbuf(3), size_t, _IONBF, NULL */ -#include /* free(3), realloc(3) */ -#include /* strcmp(3), strerror(3) */ -#include /* getopt(3) */ -#if !defined EX_IOERR || !defined EX_OK || !defined EX_OSERR \ - || !defined EX_USAGE -# include -#endif -extern int errno; - -/* This structure is how open files are tracked. */ -struct Files{ - size_t a; /* allocation */ - size_t s; /* used size */ - char *mode; /* file opening mode */ - char **names; /* file names */ - FILE **files; /* file pointers */ -}; - -/* How much to grow the allocation when it's saturated. */ -#ifndef ALLOC_INCREMENT -# define ALLOC_INCREMENT 1 -#endif - -/* How much to grow the allocation at program start. */ -#ifndef ALLOC_INITIAL -# define ALLOC_INITIAL 10 -#endif - -/* pre-allocated strings */ -static char *program_name = ""; -static char *stdin_name = ""; -static char *stdout_name = ""; -static char *stderr_name = ""; -static char *(fmode[]) = { (char []){"rb"}, (char []){"rb+"} }; -static char *wharsh = "wb"; - -/* Adds the open FILE pointer for the file at the path s to the files struct, - * returning the FILE if successful and NULL if not, allocating more memory in - * the files buffers as needed. */ -static FILE * -Files_append(struct Files *files, FILE *file, char *name){ - - if(file == NULL || (files->s == files->a - && ((files->files = realloc(files->files, - (files->a += (files->a == 0) - ? ALLOC_INITIAL - : ALLOC_INCREMENT) - * sizeof *(files->files))) == NULL - || (files->names = realloc(files->names, - files->a * sizeof *(files->names))) == NULL))) - return NULL; - - files->names[files->s] = name; - return files->files[files->s++] = file; -} - -/* Opens the file at the path p and puts it in the files struct, returning NULL - * if either the opening or the placement of the open FILE pointer fail. */ -#define Files_open(files, p) \ - Files_append((files), fopen((p), (files)->mode), (p)) - -/* Prints a diagnostic message based on errno and returns an exit status - * appropriate for an OS error. */ -static int -oserr(char *s, char *r){ - - fprintf(stderr, "%s: %s: %s\n", s, r, strerror(errno)); - - return EX_OSERR; -} - -/* Hijacks i and j from main and destructs the files[2] struct used by main by - * closing its files and freeing its files and names arrays, returning retval - * from main. */ -#define terminate \ - for(i = 0; i < 2; ++i){ \ - for(j = 0; j < files[i].s; ++j) \ - if(files[i].files[j] != stdin \ - && files[i].files[j] != stdout \ - && files[i].files[j] != stderr) \ - fclose(files[i].files[j]); \ - free(files[i].files); \ - free(files[i].names); \ - } \ - return retval - -/* Prints a usage text, in which s is the program being run (i.e. argv[0]), and - * returns an exit status appropriate for a usage error. */ -int usage(char *s){ - - fprintf(stderr, "Usage: %s [-aenu] [-i input]... [-o output]...\n", s); - - return EX_USAGE; -} - -int main(int argc, char *argv[]){ - int c; - struct Files files[2]; /* {read, write} */ - size_t i; - size_t j; - size_t k; /* loop index but also unbuffer status */ - int retval; - - /* Initializes the files structs with their default values, standard - * input and standard output. If an input or an output is specified - * these initial values will be overwritten, so to, say, use mm(1) - * equivalently to tee(1p), -o - will need to be specified before - * additional files to ensure standard output is still written. */ - for(i = 0; i < 2; ++i){ - files[i].a = 0; - files[i].s = 0; - files[i].mode = fmode[i]; - files[i].files = NULL; - files[i].names = NULL; - Files_append(&files[i], i == 0 ? stdin : stdout, - i == 0 ? stdin_name : stdout_name); - files[i].s = 0; - } - - k = 0; - - if(argc > 0) - program_name = argv[0]; - - if(argc > 1) - while((c = getopt(argc, argv, "aehi:no:u")) != -1) - switch(c){ - case 'a': /* "rb+" -> "ab" */ - files[1].mode[0] = 'a'; - files[1].mode[2] = '\0'; - break; - case 'e': - if(Files_append(&files[1], stderr, stderr_name) != NULL) - break; - retval = oserr(argv[0], "-e"); - terminate; - case 'i': - if((strcmp(optarg, "-") == 0 && Files_append(&files[0], - stdin, stdin_name) != NULL) - || Files_open(&files[0], optarg) != NULL) - break; - retval = oserr(argv[0], optarg); - terminate; - case 'o': - if((strcmp(optarg, "-") == 0 && Files_append(&files[1], - stdout, stdout_name) != NULL) - || Files_open(&files[1], optarg) != NULL) - break; - /* does not exist, so try to create it */ - if(errno == ENOENT){ - files[1].mode = wharsh; - if(Files_open(&files[1], optarg) != NULL){ - files[1].mode = fmode[1]; - break; - } - } - retval = oserr(argv[0], optarg); - terminate; - case 'n': - if(signal(SIGINT, SIG_IGN) != SIG_ERR) - break; - retval = oserr(argv[0], "-n"); - terminate; - case 'u': - k = 1; - break; - default: - retval = usage(argv[0]); - terminate; - } - - if(optind != argc){ - retval = usage(argv[0]); - terminate; - } - - files[0].s += files[0].s == 0; - files[1].s += files[1].s == 0; - - /* Unbuffer files. */ - if(k){ - for(i = 0; - i < files[0].s; - setvbuf(files[0].files[i++], NULL, _IONBF, 0)); - for(i = 0; - i < files[1].s; - setvbuf(files[1].files[i++], NULL, _IONBF, 0)); - } - - retval = EX_OK; - - /* Actual program loop. */ - for(i = 0; i < files[0].s; ++i) /* iterate ins */ - while((c = getc(files[0].files[i])) != EOF) /* iterate chars */ - for(j = 0; j < files[1].s; ++j) /* iterate outs */ - if(putc(c, files[1].files[j]) == EOF){ - /* notebook's full */ - retval = EX_IOERR; - fprintf(stderr, "%s: %s: %s\n", - program_name, files[1].names[j], strerror(errno)); - if(fclose(files[1].files[j]) == EOF) - fprintf(stderr, "%s: %s: %s\n", - program_name, files[1].names[j], strerror(errno)); - /* massage out the tense muscle */ - for(k = j--; k < files[1].s - 1; ++k){ - files[1].files[k] = files[1].files[k+1]; - files[1].names[k] = files[1].names[k+1]; - } - if(--files[1].s == 0) - terminate; - } - - terminate; -} diff --git a/src/mm.rs b/src/mm.rs new file mode 100644 index 0000000..aa7ce19 --- /dev/null +++ b/src/mm.rs @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2024 Emma Tebibyte + * 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, + fs::File, + io::{ stdin, stdout, stderr, BufWriter, Read, Write }, + os::fd::{ AsRawFd, FromRawFd }, + process::{ exit, ExitCode }, +}; + +extern crate getopt; +extern crate strerror; +extern crate sysexits; + +use getopt::GetOpt; +use strerror::StrError; +use sysexits::{ EX_IOERR, EX_USAGE }; + +fn main() -> ExitCode { + let argv = args().collect::>(); + let usage = format!("Usage: {} [-aeu] [-i input] [-o output]", argv[0]); + + let mut a = false; /* append rather than update */ + let mut e = false; /* use stderr as an output */ + let mut u = false; /* unbuffer i/o */ + let mut ins = Vec::new(); /* initial inputs vector */ + let mut outs = Vec::new(); /* initial outputs vector */ + + while let Some(opt) = argv.getopt("aei:o:u") { + match opt.opt() { + Ok("a") => a = true, + Ok("e") => e = true, + Ok("u") => u = true, + Ok("i") => { /* add input */ + let input = opt.arg().unwrap(); + ins.push(input); + }, + Ok("o") => { /* add output */ + let output = opt.arg().unwrap(); + outs.push(output); + }, + Err(_) | Ok(_) => { + eprintln!("{}", usage); + return ExitCode::from(EX_USAGE as u8); + }, + }; + } + + /* use stdin if no inputs are specified */ + if ins.is_empty() { ins.push("-".to_string()); } + + /* use stdout if no outputs are specified */ + if outs.is_empty() { outs.push("-".to_string()); } + + /* map all path strings to files */ + let inputs = ins.iter().map(|file| { + /* if a file is “-”, it is stdin */ + if *file == "-" { + return unsafe { File::from_raw_fd(stdin().as_raw_fd()) }; /* fd0 = stdin */ + } + + match File::options().append(a).open(file) { + Ok(f) => f, + Err(e) => { + eprintln!("{}: {}", argv[0], e.strerror()); + exit(EX_IOERR); + }, + } + }).collect::>(); + + /* map all path strings to files */ + let mut outputs = outs.iter().map(|file| { + /* of a file is “-”, it is stdout */ + if *file == "-" { + return unsafe { File::from_raw_fd(stdout().as_raw_fd()) }; /* fd1 = stdout */ + } + + match File::options().append(a).open(file) { + Ok(f) => return f, + Err(e) => { + eprintln!("{}: {}", argv[0], e.strerror()); + exit(EX_IOERR); + }, + }; + }).collect::>(); + + /* if -e is specified, use stderr */ + if e { + outputs.push(unsafe { File::from_raw_fd(stderr().as_raw_fd()) }); /* fd2 = stderr */ + } + + let mut outputs = outputs.iter().map(|o| { + if u { + BufWriter::with_capacity(0, o) + } else { + BufWriter::new(o) + } + }).collect::>(); + + for file in inputs { + for byte in file.bytes().map(|b| { + b.unwrap_or_else(|e| { + eprintln!("{}: {}", argv[0], e.strerror()); + exit(EX_IOERR); + }) + }) { + for out in &mut outputs { + if let Err(e) = out.write(&[byte]) { + eprintln!("{}: {}", argv[0], e.strerror()); + return ExitCode::from(EX_IOERR as u8); + } + if let Err(e) = out.flush() { + eprintln!("{}: {}", argv[0], e.strerror()); + return ExitCode::from(EX_IOERR as u8); + } + } + } + } + + ExitCode::SUCCESS +} From e972ff468aeee799090477fb9a270ec3f0d7f475 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 13 Jul 2024 23:56:30 -0600 Subject: [PATCH 225/343] mm(1): added -t for disabling truncation; mm.1: updated docs --- docs/mm.1 | 16 ++++++---------- src/mm.rs | 14 ++++++++------ 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/docs/mm.1 b/docs/mm.1 index 2916aa7..d4659d2 100644 --- a/docs/mm.1 +++ b/docs/mm.1 @@ -10,7 +10,7 @@ mm \(en middleman .SH SYNOPSIS mm -.RB [ -aenu ] +.RB [ -aetu ] .RB [ -i\ input ] .RB [ -o\ output ] .\" @@ -21,19 +21,19 @@ Catenate input files and write them to the start of each output file or stream. .SH OPTIONS .IP \fB-a\fP -Opens subsequent outputs for appending rather than updating. +Opens outputs for appending rather than updating. .IP \fB-e\fP Use the standard error as an output. +.IP \fB-t\fP +Causes outputs to be overwritten instead of being truncated. +.IP \fB-u\fP +Ensures neither input or output will be buffered. .IP \fB-i\fP\ \fIinput\fP Opens a path as an input. If one or more of the input files is \(lq-\(rq or if no inputs are specified, the standard input shall be used. .IP \fB-o\fP\ \fIoutput\fP Opens a path as an output. If one or more of the output files is \(lq-\(rq or if no outputs are specified, the standard output shall be used. -.IP \fB-u\fP -Ensures neither input or output will be buffered. -.IP \fB-n\fP -Causes SIGINT signals to be ignored. .\" .SH DIAGNOSTICS @@ -45,10 +45,6 @@ exits with the appropriate .BR sysexits.h (3) status. .\" -.SH CAVEATS - -Existing files are not truncated on ouput and are instead overwritten. -.\" .SH RATIONALE The diff --git a/src/mm.rs b/src/mm.rs index aa7ce19..e991b5a 100644 --- a/src/mm.rs +++ b/src/mm.rs @@ -34,19 +34,21 @@ use sysexits::{ EX_IOERR, EX_USAGE }; fn main() -> ExitCode { let argv = args().collect::>(); - let usage = format!("Usage: {} [-aeu] [-i input] [-o output]", argv[0]); + let usage = format!("Usage: {} [-aetu] [-i input] [-o output]", argv[0]); let mut a = false; /* append rather than update */ let mut e = false; /* use stderr as an output */ + let mut t = true; let mut u = false; /* unbuffer i/o */ let mut ins = Vec::new(); /* initial inputs vector */ let mut outs = Vec::new(); /* initial outputs vector */ - while let Some(opt) = argv.getopt("aei:o:u") { + while let Some(opt) = argv.getopt("aei:o:tu") { match opt.opt() { Ok("a") => a = true, - Ok("e") => e = true, - Ok("u") => u = true, + Ok("e") => e = true, + Ok("u") => u = true, + Ok("t") => t = false, Ok("i") => { /* add input */ let input = opt.arg().unwrap(); ins.push(input); @@ -75,7 +77,7 @@ fn main() -> ExitCode { return unsafe { File::from_raw_fd(stdin().as_raw_fd()) }; /* fd0 = stdin */ } - match File::options().append(a).open(file) { + match File::options().open(file) { Ok(f) => f, Err(e) => { eprintln!("{}: {}", argv[0], e.strerror()); @@ -91,7 +93,7 @@ fn main() -> ExitCode { return unsafe { File::from_raw_fd(stdout().as_raw_fd()) }; /* fd1 = stdout */ } - match File::options().append(a).open(file) { + match File::options().truncate(t).append(a).open(file) { Ok(f) => return f, Err(e) => { eprintln!("{}: {}", argv[0], e.strerror()); From 3b7625459921aebd9b7c37b411fa523fe0bce1b2 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 14 Jul 2024 00:31:23 -0600 Subject: [PATCH 226/343] mm(1): fixes creating files --- src/mm.rs | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/src/mm.rs b/src/mm.rs index e991b5a..9c1151c 100644 --- a/src/mm.rs +++ b/src/mm.rs @@ -36,12 +36,12 @@ fn main() -> ExitCode { let argv = args().collect::>(); let usage = format!("Usage: {} [-aetu] [-i input] [-o output]", argv[0]); - let mut a = false; /* append rather than update */ + let mut a = false; /* append to the file */ let mut e = false; /* use stderr as an output */ - let mut t = true; + let mut t = true; /* do not truncate the file before writing */ let mut u = false; /* unbuffer i/o */ - let mut ins = Vec::new(); /* initial inputs vector */ - let mut outs = Vec::new(); /* initial outputs vector */ + let mut ins = Vec::new(); /* initial input file path vector */ + let mut outs = Vec::new(); /* initial output file path vector */ while let Some(opt) = argv.getopt("aei:o:tu") { match opt.opt() { @@ -74,29 +74,43 @@ fn main() -> ExitCode { let inputs = ins.iter().map(|file| { /* if a file is “-”, it is stdin */ if *file == "-" { - return unsafe { File::from_raw_fd(stdin().as_raw_fd()) }; /* fd0 = stdin */ + /* portable way to access stdin as a file */ + return unsafe { File::from_raw_fd(stdin().as_raw_fd()) }; } - match File::options().open(file) { + match File::open(file) { Ok(f) => f, Err(e) => { - eprintln!("{}: {}", argv[0], e.strerror()); + eprintln!("{}: {}: {}", argv[0], file, e.strerror()); exit(EX_IOERR); }, } }).collect::>(); + println!("{:?}", outs); + /* map all path strings to files */ let mut outputs = outs.iter().map(|file| { /* of a file is “-”, it is stdout */ if *file == "-" { - return unsafe { File::from_raw_fd(stdout().as_raw_fd()) }; /* fd1 = stdout */ + /* portable way to access stdout as a file */ + return unsafe { File::from_raw_fd(stdout().as_raw_fd()) }; } - match File::options().truncate(t).append(a).open(file) { + let options = File::options() + /* truncate if -t is specified and append if -a is specified */ + .truncate(t) + .append(a) + /* enable the ability to create and write to files */ + .create(true) + .write(true) + /* finally, open the file! */ + .open(file); + + match options { Ok(f) => return f, Err(e) => { - eprintln!("{}: {}", argv[0], e.strerror()); + eprintln!("{}: {}: {}", argv[0], file, e.strerror()); exit(EX_IOERR); }, }; @@ -104,13 +118,16 @@ fn main() -> ExitCode { /* if -e is specified, use stderr */ if e { - outputs.push(unsafe { File::from_raw_fd(stderr().as_raw_fd()) }); /* fd2 = stderr */ + /* portable way to access stderr as a file */ + outputs.push(unsafe { File::from_raw_fd(stderr().as_raw_fd()) }); } let mut outputs = outputs.iter().map(|o| { if u { + /* unbuffered writing through a buffer of capacity 0 */ BufWriter::with_capacity(0, o) } else { + /* theoretically buffered writing */ BufWriter::new(o) } }).collect::>(); @@ -127,7 +144,8 @@ fn main() -> ExitCode { eprintln!("{}: {}", argv[0], e.strerror()); return ExitCode::from(EX_IOERR as u8); } - if let Err(e) = out.flush() { + /* immediately flush the output for -u */ + if let Err(e) = out.flush() { eprintln!("{}: {}", argv[0], e.strerror()); return ExitCode::from(EX_IOERR as u8); } From 37804aab6b799db8b60ba4e9f0853cdc7b18f9a6 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 14 Jul 2024 00:33:37 -0600 Subject: [PATCH 227/343] mm(1): fixes comment about flags -a & -t --- src/mm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mm.rs b/src/mm.rs index 9c1151c..9a1590f 100644 --- a/src/mm.rs +++ b/src/mm.rs @@ -98,7 +98,7 @@ fn main() -> ExitCode { } let options = File::options() - /* truncate if -t is specified and append if -a is specified */ + /* don’t truncate if -t is specified, append if -a is specified */ .truncate(t) .append(a) /* enable the ability to create and write to files */ From 8d693b66649cd91cf532ec8ad4bd17dcd2e20d33 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 14 Jul 2024 01:25:25 -0600 Subject: [PATCH 228/343] mm(1): removes debug print --- src/mm.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mm.rs b/src/mm.rs index 9a1590f..d00dfc2 100644 --- a/src/mm.rs +++ b/src/mm.rs @@ -87,8 +87,6 @@ fn main() -> ExitCode { } }).collect::>(); - println!("{:?}", outs); - /* map all path strings to files */ let mut outputs = outs.iter().map(|file| { /* of a file is “-”, it is stdout */ From 20692d581a9cd7574e1e3c78e0d9d63f4ec3678a Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 14 Jul 2024 14:15:55 -0600 Subject: [PATCH 229/343] mm(1): makes -e block inferring stdout as an output, mm.1: reflects changes to -e --- docs/mm.1 | 4 +++- src/mm.rs | 13 ++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/mm.1 b/docs/mm.1 index d4659d2..9e26420 100644 --- a/docs/mm.1 +++ b/docs/mm.1 @@ -33,7 +33,9 @@ Opens a path as an input. If one or more of the input files is \(lq-\(rq or if no inputs are specified, the standard input shall be used. .IP \fB-o\fP\ \fIoutput\fP Opens a path as an output. If one or more of the output files is \(lq-\(rq or if -no outputs are specified, the standard output shall be used. +no outputs are specified and the +.B -e +option is not specified, the standard output shall be used. .\" .SH DIAGNOSTICS diff --git a/src/mm.rs b/src/mm.rs index d00dfc2..df431db 100644 --- a/src/mm.rs +++ b/src/mm.rs @@ -68,7 +68,7 @@ fn main() -> ExitCode { if ins.is_empty() { ins.push("-".to_string()); } /* use stdout if no outputs are specified */ - if outs.is_empty() { outs.push("-".to_string()); } + if outs.is_empty() && !e { outs.push("-".to_string()); } /* map all path strings to files */ let inputs = ins.iter().map(|file| { @@ -142,10 +142,13 @@ fn main() -> ExitCode { eprintln!("{}: {}", argv[0], e.strerror()); return ExitCode::from(EX_IOERR as u8); } - /* immediately flush the output for -u */ - if let Err(e) = out.flush() { - eprintln!("{}: {}", argv[0], e.strerror()); - return ExitCode::from(EX_IOERR as u8); + + if u { + /* immediately flush the output for -u */ + if let Err(e) = out.flush() { + eprintln!("{}: {}", argv[0], e.strerror()); + return ExitCode::from(EX_IOERR as u8); + } } } } From 8dc763f05ebe58487c5569545342cc5a8ee19945 Mon Sep 17 00:00:00 2001 From: DTB Date: Sun, 14 Jul 2024 18:34:08 -0600 Subject: [PATCH 230/343] mm(1): treats trailing arguments as optargs for the last opt --- src/mm.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/mm.rs b/src/mm.rs index df431db..f39b3b2 100644 --- a/src/mm.rs +++ b/src/mm.rs @@ -1,5 +1,6 @@ /* * Copyright (c) 2024 Emma Tebibyte + * 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 @@ -32,6 +33,8 @@ use getopt::GetOpt; use strerror::StrError; use sysexits::{ EX_IOERR, EX_USAGE }; +enum ArgMode{ In, Out } + fn main() -> ExitCode { let argv = args().collect::>(); let usage = format!("Usage: {} [-aetu] [-i input] [-o output]", argv[0]); @@ -42,6 +45,8 @@ fn main() -> ExitCode { let mut u = false; /* unbuffer i/o */ let mut ins = Vec::new(); /* initial input file path vector */ let mut outs = Vec::new(); /* initial output file path vector */ + let mut mode: Option = None; /* mode for positional arguments */ + let mut optind = 0; while let Some(opt) = argv.getopt("aei:o:tu") { match opt.opt() { @@ -49,19 +54,33 @@ fn main() -> ExitCode { Ok("e") => e = true, Ok("u") => u = true, Ok("t") => t = false, - Ok("i") => { /* add input */ + Ok("i") => { /* add inputs */ let input = opt.arg().unwrap(); ins.push(input); + mode = Some(ArgMode::In); }, Ok("o") => { /* add output */ let output = opt.arg().unwrap(); outs.push(output); + mode = Some(ArgMode::Out); }, Err(_) | Ok(_) => { eprintln!("{}", usage); return ExitCode::from(EX_USAGE as u8); }, }; + optind = opt.ind(); + } + + let remaining = argv.iter().skip(optind); + + if let Some(m) = mode { + for arg in remaining { + match m { + ArgMode::In => ins.push(arg.to_string()), + ArgMode::Out => outs.push(arg.to_string()), + }; + } } /* use stdin if no inputs are specified */ From 7a0ad7800091afce5cf8d84bb44ab7a0abad5d4c Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 14 Jul 2024 18:38:02 -0600 Subject: [PATCH 231/343] mm.1: reflects new changes --- docs/mm.1 | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/mm.1 b/docs/mm.1 index 9e26420..5a90aa1 100644 --- a/docs/mm.1 +++ b/docs/mm.1 @@ -3,7 +3,7 @@ .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" visit . .\" -.TH MM 1 2024-06-17 "Harakit X.X.X" +.TH MM 1 2024-07-14 "Harakit X.X.X" .SH NAME mm \(en middleman .\" @@ -30,12 +30,16 @@ Causes outputs to be overwritten instead of being truncated. Ensures neither input or output will be buffered. .IP \fB-i\fP\ \fIinput\fP Opens a path as an input. If one or more of the input files is \(lq-\(rq or if -no inputs are specified, the standard input shall be used. +no inputs are specified, the standard input shall be used. If specified as the +last option and if there are trailing arguments to the program, they shall be +appended to the list of files to use as inputs. .IP \fB-o\fP\ \fIoutput\fP Opens a path as an output. If one or more of the output files is \(lq-\(rq or if no outputs are specified and the .B -e -option is not specified, the standard output shall be used. +option is not specified, the standard output shall be used. If specified as the +last option and if there are trailing arguments to the program, they shall be +appended to the list of files to use as inputs. .\" .SH DIAGNOSTICS From eda5385058280f84daa450ddd0a48f64fef52434 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 14 Jul 2024 18:38:53 -0600 Subject: [PATCH 232/343] mm.1: small correction --- docs/mm.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/mm.1 b/docs/mm.1 index 5a90aa1..f641156 100644 --- a/docs/mm.1 +++ b/docs/mm.1 @@ -39,7 +39,7 @@ no outputs are specified and the .B -e option is not specified, the standard output shall be used. If specified as the last option and if there are trailing arguments to the program, they shall be -appended to the list of files to use as inputs. +appended to the list of files to use as outputs. .\" .SH DIAGNOSTICS From 64f3f73d96814cb708bcf69743254a317803f16b Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 14 Jul 2024 18:39:55 -0600 Subject: [PATCH 233/343] mm(1): formatting --- src/mm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mm.rs b/src/mm.rs index f39b3b2..bb7b3d0 100644 --- a/src/mm.rs +++ b/src/mm.rs @@ -33,7 +33,7 @@ use getopt::GetOpt; use strerror::StrError; use sysexits::{ EX_IOERR, EX_USAGE }; -enum ArgMode{ In, Out } +enum ArgMode { In, Out } fn main() -> ExitCode { let argv = args().collect::>(); From 48dbea0228f19b5442fd3cea92918f20d4c14ff4 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 14 Jul 2024 18:41:18 -0600 Subject: [PATCH 234/343] mm(1): imports full enum --- src/mm.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/mm.rs b/src/mm.rs index bb7b3d0..301ed55 100644 --- a/src/mm.rs +++ b/src/mm.rs @@ -33,6 +33,8 @@ use getopt::GetOpt; use strerror::StrError; use sysexits::{ EX_IOERR, EX_USAGE }; +use ArgMode::*; + enum ArgMode { In, Out } fn main() -> ExitCode { @@ -57,12 +59,12 @@ fn main() -> ExitCode { Ok("i") => { /* add inputs */ let input = opt.arg().unwrap(); ins.push(input); - mode = Some(ArgMode::In); + mode = Some(In); }, Ok("o") => { /* add output */ let output = opt.arg().unwrap(); outs.push(output); - mode = Some(ArgMode::Out); + mode = Some(Out); }, Err(_) | Ok(_) => { eprintln!("{}", usage); @@ -77,8 +79,8 @@ fn main() -> ExitCode { if let Some(m) = mode { for arg in remaining { match m { - ArgMode::In => ins.push(arg.to_string()), - ArgMode::Out => outs.push(arg.to_string()), + In => ins.push(arg.to_string()), + Out => outs.push(arg.to_string()), }; } } From e7a6632b41d93d361750fd6242d7b0826068cfc4 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 14 Jul 2024 18:56:23 -0600 Subject: [PATCH 235/343] mm(1): improves comments --- src/mm.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/mm.rs b/src/mm.rs index 301ed55..41b7857 100644 --- a/src/mm.rs +++ b/src/mm.rs @@ -47,7 +47,7 @@ fn main() -> ExitCode { let mut u = false; /* unbuffer i/o */ let mut ins = Vec::new(); /* initial input file path vector */ let mut outs = Vec::new(); /* initial output file path vector */ - let mut mode: Option = None; /* mode for positional arguments */ + let mut mode: Option = None; /* mode set by last-used option */ let mut optind = 0; while let Some(opt) = argv.getopt("aei:o:tu") { @@ -59,30 +59,36 @@ fn main() -> ExitCode { Ok("i") => { /* add inputs */ let input = opt.arg().unwrap(); ins.push(input); - mode = Some(In); + mode = Some(In); /* latest argument == -i */ }, Ok("o") => { /* add output */ let output = opt.arg().unwrap(); outs.push(output); - mode = Some(Out); + mode = Some(Out); /* latest argument == -o */ }, Err(_) | Ok(_) => { eprintln!("{}", usage); return ExitCode::from(EX_USAGE as u8); }, }; + optind = opt.ind(); } let remaining = argv.iter().skip(optind); + /* check the last flag specified */ if let Some(m) = mode { for arg in remaining { + /* move the subsequent arguments to the list of inputs or outputs */ match m { In => ins.push(arg.to_string()), Out => outs.push(arg.to_string()), }; } + } else { + eprintln!("{}", usage); + return ExitCode::from(EX_USAGE as u8); } /* use stdin if no inputs are specified */ From 789046f69457fb58560f4dbdca32ca5733b30fb1 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 15 Jul 2024 13:03:30 -0600 Subject: [PATCH 236/343] STYLE: removes do while constraint & reword indentation rule --- STYLE | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/STYLE b/STYLE index 5560aa3..5a236a0 100644 --- a/STYLE +++ b/STYLE @@ -1,5 +1,5 @@ - Braces are mandatory for all control flow -- Indentation should be kept to a minimum +- Nested indentation should be kept to a minimum - Empty lines should be placed between different kinds of statements: int t; @@ -49,11 +49,6 @@ use sysexits::{ EX_DATAERR, EX_IOERR, EX_UNAVAILABLE, EX_USAGE }; if (!argc < 0) { usage(program_name); } -- If a do while loop in C is longer than ~25 lines, place the while statement - in a comment after the opening brace: - -do { /* while(count == 0 || --count > 0); */ - -- Copyright © 2024 Emma Tebibyte From e9496cb4a5ff144566e1023af1baa25fb30cc13b Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 15 Jul 2024 13:04:23 -0600 Subject: [PATCH 237/343] dj.1: fixes ambiguity and false information --- docs/dj.1 | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index 1440ff4..a110166 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -181,22 +181,22 @@ option is specified, this could make written data nonsensical. Existing files are not truncated on ouput and are instead overwritten. -Option variants that have uppercase and lowercase forms could be confused for +Option variants that have lowercase and uppercase forms could be confused for each other. The former affects input and the latter affects output. The .B -B option could be mistaken for write size, meaning the count in bytes of data -placed in the output. This conception is intuitive but incorrect; the amount of -data read and output is controlled by the +placed in the output. This conception is intuitive but incorrect, as the .B -c -and +option controls the number of blocks to read and the .B -b -options. The latter sets the size of blocks to be read and the former sets the -number of blocks to be read. The +option sets the size of the blocks. The .B -B option is similar to the latter but sets the size of blocks to be written, -regardless of the amount of data that will actually be written. +regardless of the amount of data that will actually be written. In practice, +this means the input buffer should be very large to make use of modern hardware +input and output speeds. The skipped or sought bytes while processing irregular files, such as streams, are reported in the diagnostic output, because they were actually read or @@ -223,3 +223,4 @@ Copyright \(co 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later .SH SEE ALSO .BR dd (1p) .BR lseek (3p) +.BR mm (1) From 71e98dbde72346f8bdbbbf62a01943bceb82a23c Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 15 Jul 2024 13:06:34 -0600 Subject: [PATCH 238/343] dj.1: fixes more ambiguity --- docs/dj.1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/dj.1 b/docs/dj.1 index a110166..79096d5 100644 --- a/docs/dj.1 +++ b/docs/dj.1 @@ -186,8 +186,8 @@ each other. The former affects input and the latter affects output. The .B -B -option could be mistaken for write size, meaning the count in bytes of data -placed in the output. This conception is intuitive but incorrect, as the +option could be mistaken for the count in bytes of data written to the output. +This conception is intuitive but incorrect, as the .B -c option controls the number of blocks to read and the .B -b From c2e6744e2b242239150a43698735ce9798ffb158 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 15 Jul 2024 13:09:09 -0600 Subject: [PATCH 239/343] dj(1): revert changes to function return type formatting --- src/dj.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/dj.c b/src/dj.c index 1dead90..d1fae4c 100644 --- a/src/dj.c +++ b/src/dj.c @@ -66,7 +66,8 @@ static int write_flags = O_WRONLY | O_CREAT; /* Macro to check if fd is stdin or stdout */ #define fdisstd(fd) ((fd) == STDIN_FILENO || (fd) == STDOUT_FILENO) -static struct Io * Io_read(struct Io *io) { +static struct Io * +Io_read(struct Io *io) { int t; assert(io->bs > 0); @@ -87,7 +88,8 @@ static struct Io * Io_read(struct Io *io) { return io; } -static struct Io * Io_write(struct Io *io) { +static struct Io * +Io_write(struct Io *io) { int t; assert(io->bufuse > 0); @@ -107,14 +109,16 @@ static struct Io * Io_write(struct Io *io) { return io; } -static int oserr(char *e, int n) { +static int +oserr(char *e, int n) { fprintf(stderr, "%s: %s: %s\n", program_name, e, strerror(n)); return EX_OSERR; } /* Prints statistics regarding the use of dj, particularly partially and * completely read and written records. */ -static void fprintio(FILE *stream, char *fmt, struct Io io[2]) { +static void +fprintio(FILE *stream, char *fmt, struct Io io[2]) { fprintf( stream, fmt, @@ -132,7 +136,8 @@ static void fprintio(FILE *stream, char *fmt, struct Io io[2]) { /* Parses the string s to an integer, returning either the integer or in the * case of an error a negative integer. This is used for argument parsing * (e.g. -B [int]) in dj and no negative integer would be valid anyway. */ -static long parse(char *s){ +static long +parse(char *s) { long r; errno = 0; @@ -140,7 +145,8 @@ static long parse(char *s){ return (*s == '\0' && errno == 0) ? r : -1; /* no chars left unparsed */ } -static int usage(char *s){ +static int +usage(char *s) { fprintf( stderr, "Usage: %s [-Hn] [-a byte] [-c count]\n" "\t[-i file] [-b block_size] [-s offset]\n" From a3ceb845e370ba4471616735d50693cc153762f8 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 15 Jul 2024 13:16:05 -0600 Subject: [PATCH 240/343] dj(1): revert some formatting changes --- src/dj.c | 94 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 48 insertions(+), 46 deletions(-) diff --git a/src/dj.c b/src/dj.c index d1fae4c..7a05e3e 100644 --- a/src/dj.c +++ b/src/dj.c @@ -142,7 +142,7 @@ parse(char *s) { errno = 0; r = strtol(s, &s, 0); - return (*s == '\0' && errno == 0) ? r : -1; /* no chars left unparsed */ + return (*s == '\0' /* no chars left unparsed */ && errno == 0) ? r : -1; } static int @@ -182,59 +182,59 @@ int main(int argc, char *argv[]) { io[i].seek = 0; } - if (!(argc < 0)) { usage(program_name); } + if (argc > 0) { + int c; - int c; + program_name = argv[0]; + while ((c = getopt(argc, argv, "a:b:B:c:i:hHns:S:o:")) != -1) { + switch (c) { + case 'i': case 'o': /* input, output */ + i = (c == 'o'); - program_name = argv[0]; - while ((c = getopt(argc, argv, "a:b:B:c:i:hHns:S:o:")) != -1) { - switch (c) { - case 'i': case 'o': /* input, output */ - i = (c == 'o'); + /* optarg == "-" (stdin/stdout) */ + if (optarg[0] == '-' && optarg[1] == '\0') { + io[i].fd = i == 0 ? STDIN_FILENO : STDOUT_FILENO; + io[i].fn = i == 0 ? stdin_name : stdout_name; + break; + } else { + int fd; - /* optarg == "-" (stdin/stdout) */ - if (optarg[0] == '-' && optarg[1] == '\0') { - io[i].fd = i == 0 ? STDIN_FILENO : STDOUT_FILENO; - io[i].fn = i == 0 ? stdin_name : stdout_name; - break; - } else { - int fd; + if ( + (fd = open(optarg, io[i].fl, creat_mode)) != -1 + && (fdisstd(io[i].fd) || close(io[i].fd) == 0) + ) { + io[i].fd = fd; + io[i].fn = optarg; + break; + } + } - if ( - (fd = open(optarg, io[i].fl, creat_mode)) != -1 - && (fdisstd(io[i].fd) || close(io[i].fd) == 0) - ) { - io[i].fd = fd; - io[i].fn = optarg; + return oserr(optarg, errno); /* break; */ + case 'n': noerror = 1; break; /* retry failed reads once */ + case 'H': fmt = fmt_human; break; /* human-readable output */ + case 'a': /* input buffer padding */ + if (optarg[0] == '\0' || optarg[1] == '\0') { + align = optarg[0]; break; } - } + /* FALLTHROUGH */ + case 'c': /* number of reads */ + case 'b': case 'B': /* input/output block size */ + case 's': case 'S': /* (s)kip/(S)eek in input/output */ + if (c == 'c' && (count = parse(optarg)) >= 0) { break; } - return oserr(optarg, errno); /* break; */ - case 'n': noerror = 1; break; /* retry failed reads once */ - case 'H': fmt = fmt_human; break; /* human-readable output */ - case 'a': /* input buffer padding */ - if (optarg[0] == '\0' || optarg[1] == '\0') { - align = optarg[0]; - break; - } - /* FALLTHROUGH */ - case 'c': /* number of reads */ - case 'b': case 'B': /* input/output block size */ - case 's': case 'S': /* (s)kip/(S)eek in input/output */ - if (c == 'c' && (count = parse(optarg)) >= 0) { break; } + i = (c >= 'A' && c <= 'Z'); + c |= 0x20; /* 0b 0010 0000 (ASCII make lowercase) */ - i = (c >= 'A' && c <= 'Z'); - c |= 0x20 /* ASCII make lowercase 0b 0010 0000 */ + if ( + (c == 'b' && (io[i].bs = parse(optarg)) > 0) + || (c == 's' && (io[i].seek = parse(optarg)) >= 0) + ) { break; } - if ( - (c == 'b' && (io[i].bs = parse(optarg)) > 0) - || (c == 's' && (io[i].seek = parse(optarg)) >= 0) - ) { break; } - - /* FALLTHROUGH */ - default: - return usage(program_name); + /* FALLTHROUGH */ + default: + return usage(program_name); + } } } @@ -272,7 +272,9 @@ int main(int argc, char *argv[]) { if (Io_write(&io[1])->bufuse == t && !noerror && io[1].error == 0) { Io_write(&io[1]); /* second chance */ } - if (io[1].error != 0) { return oserr(io[1].fn, io[1].error); } + if (io[1].error != 0) { + return oserr(io[1].fn, io[1].error); + } } while ((io[1].seek -= (t - io[1].bufuse)) > 0 && io[1].bufuse != t); io[1].bufuse = 0; From 7ff14214c3c983d815e7a4537fdc47bfa1ec58cd Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 15 Jul 2024 13:16:41 -0600 Subject: [PATCH 241/343] npc(1): move bit comment to be next to hex --- src/npc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/npc.c b/src/npc.c index 34fb9ce..5e00351 100644 --- a/src/npc.c +++ b/src/npc.c @@ -48,7 +48,7 @@ int main(int argc, char *argv[]) { while ((c = getc(stdin)) != EOF) { if ((c & 0x80) != 0) { fputs("M-", stdout); } - switch (c ^ 0x80) { /* 0b 1000 0000 */ + switch (c ^ 0x80 /* 0b 1000 0000 */) { case 0x7f: fputs("^?", stdout); break; /* delete character */ case '\n': if (showend) { putc('$', stdout); } default: From dc2a4a39bad2e4ec9553cecf0ddbc5c62f85339d Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 15 Jul 2024 13:17:00 -0600 Subject: [PATCH 242/343] swab(1): note what sysexits are being used --- src/scrut.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scrut.c b/src/scrut.c index a0ee93d..74a96dc 100644 --- a/src/scrut.c +++ b/src/scrut.c @@ -20,7 +20,7 @@ #include /* fprintf(3), stderr, NULL */ #include /* EXIT_FAILURE, EXIT_SUCCESS */ #include /* memset(3), strchr(3) */ -#include +#include /* EX_USAGE */ #include /* access(3), getopt(3), F_OK, R_OK, W_OK, X_OK */ #include /* lstat(3), stat struct, S_ISBLK, S_ISCHR, S_ISDIR, * S_ISFIFO, S_ISGID, S_ISREG, S_ISLNK, S_ISSOCK, From a0ed14a089b6cb02dee790cca9e8357bdd4fa9e9 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 15 Jul 2024 13:29:12 -0600 Subject: [PATCH 243/343] STYLE: example for trailing comma & add includes guideline --- STYLE | 84 ++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 48 insertions(+), 36 deletions(-) diff --git a/STYLE b/STYLE index 5a236a0..4344991 100644 --- a/STYLE +++ b/STYLE @@ -1,53 +1,65 @@ -- Braces are mandatory for all control flow -- Nested indentation should be kept to a minimum -- Empty lines should be placed between different kinds of statements: +0. Braces are mandatory for all control flow, as it improves the visibility of + scope. +1. Nested indentation should be kept to a minimum. +2. Empty lines should be placed between different kinds of statements: -int t; + int t; -assert(io->bufuse > 0); -assert(io->bufuse <= io->bs); + assert(io->bufuse > 0); + assert(io->bufuse <= io->bs); -if ((t = write(io->fd, io->buf, io->bufuse)) < 0) { - io->error = errno; - t = 0; -} else if (t > 0) { - memmove(io->buf, &(io->buf)[t], (io->bufuse -= t)); -} + if ((t = write(io->fd, io->buf, io->bufuse)) < 0) { + io->error = errno; + t = 0; + } else if (t > 0) { + memmove(io->buf, &(io->buf)[t], (io->bufuse -= t)); + } -io->bytes += t; -io->prec += (t > 0 && io->bufuse > 0); -io->rec += (t > 0 && io->bufuse == 0); + io->bytes += t; + io->prec += (t > 0 && io->bufuse > 0); + io->rec += (t > 0 && io->bufuse == 0); -return io; + return io; -- Cases in switch statements and matches in match statements should be indented - one level -- In C, spaces should be placed in control flow statements after the keyword and - before the opening brace: +3. Cases in switch statements and matches in match statements should be indented + one level +4. In C, spaces should be placed in control flow statements after the keyword + and before the opening brace: -for (i = 2; i < argc; ++i) { + for (i = 2; i < argc; ++i) { -- If a function, a C control flow statement, or a Rust macro has arguments that - cause the statement to be broken into multiple lines, this should be done by - placing the arguments on a new line inside the parentheses: +5. If a function, a C control flow statement, or a Rust macro has arguments that + cause the statement to be broken into multiple lines, this should be done by + placing the arguments on a new line inside the parentheses: -let usage = format!( - "Usage: {} [-d delimiter] index command [args...]", - argv[0], -); + let usage = format!( + "Usage: {} [-d delimiter] index command [args...]", + argv[0], + ); -- If Rust function arguments or fields are on their own lines, they should - always have a trailing comma. +6. If Rust function arguments or fields are on their own lines, they should + always have a trailing comma: -- If text is on the same line as a brace, spaces should be placed after an - opening curly brace and before a closing one: + return Err(EvaluationError { + message: format!("{}: Invalid token", i), + code: EX_DATAERR, + }) -use sysexits::{ EX_DATAERR, EX_IOERR, EX_UNAVAILABLE, EX_USAGE }; +7. If text is on the same line as a brace, spaces should be placed after an + opening curly brace and before a closing one: -- If a control flow statement is short enough to be easily understood in a - glance, it may be placed on a single line: + use sysexits::{ EX_DATAERR, EX_IOERR, EX_UNAVAILABLE, EX_USAGE }; -if (!argc < 0) { usage(program_name); } +8. If a control flow statement is short enough to be easily understood in a + glance, it may be placed on a single line: + + if (!argc < 0) { usage(program_name); } + +9. In C, note everything you use from a library in a comment subsequent to its + #include statement: + + #include /* close(2), getopt(3), lseek(2), read(2), write(2), + * optarg, optind, STDIN_FILENO, STDOUT_FILENO */ -- Copyright © 2024 Emma Tebibyte From 806ddac8da2079924987e2f579d54d3e656296bd Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 15 Jul 2024 13:31:38 -0600 Subject: [PATCH 244/343] dj(1): whitespace formatting --- src/dj.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dj.c b/src/dj.c index 7a05e3e..22772cb 100644 --- a/src/dj.c +++ b/src/dj.c @@ -36,8 +36,8 @@ char *program_name = "dj"; * writing ends of its jockeyed "pipe". User-configurable members are noted * with their relevant options. */ struct Io { - char *buf; /* buffer */ - char *fn; /* file name (-io) */ + char *buf; /* buffer */ + char *fn; /* file name (-io) */ size_t bs; /* buffer size (-bB) */ size_t bufuse; /* buffer usage */ size_t bytes; /* bytes processed */ @@ -45,8 +45,8 @@ struct Io { size_t rec; /* records processed */ long seek; /* remaining bytes to seek/skip (-sS) */ int error; /* errno */ - int fd; /* file descriptor */ - int fl; /* file opening flags */ + int fd; /* file descriptor */ + int fl; /* file opening flags */ }; /* To be assigned to main:fmt and used with printio(). */ From fbdf4f9c45afb3dd6064d97105ebf3fa4afb6181 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 15 Jul 2024 13:38:08 -0600 Subject: [PATCH 245/343] intcmp(1): switch formatting --- src/intcmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intcmp.c b/src/intcmp.c index 132c230..41a1592 100644 --- a/src/intcmp.c +++ b/src/intcmp.c @@ -50,7 +50,7 @@ int main(int argc, char *argv[]) { if (argc == 0 | argc < 3) { return usage(s); } while ((c = getopt(argc, argv, "egl")) != -1) { - switch (c){ + switch (c) { case 'e': mode |= EQUAL; break; case 'g': mode |= GREATER; break; case 'l': mode |= LESSER; break; From 9f2447ce94550fae406d5755464526f6e5f4de37 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 15 Jul 2024 13:38:26 -0600 Subject: [PATCH 246/343] STYLE: code block indentation edits and example --- STYLE | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/STYLE b/STYLE index 4344991..23cd0c5 100644 --- a/STYLE +++ b/STYLE @@ -21,8 +21,16 @@ return io; -3. Cases in switch statements and matches in match statements should be indented - one level +3. Each block of code should be indented once more than the keyword which + initiated the block: + + switch (c) { + case 'e': mode |= EQUAL; break; + case 'g': mode |= GREATER; break; + case 'l': mode |= LESS; break; + default: return usage(s); + } + 4. In C, spaces should be placed in control flow statements after the keyword and before the opening brace: From becb3bac4eb308584ab13f558fe17e692cc8f8bb Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 15 Jul 2024 14:40:26 -0600 Subject: [PATCH 247/343] strcmp(1): code clarification --- src/strcmp.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/strcmp.c b/src/strcmp.c index 784029c..33eab10 100644 --- a/src/strcmp.c +++ b/src/strcmp.c @@ -30,10 +30,11 @@ int main(int argc, char *argv[]){ return EX_USAGE; } - for (; *argv[1] != '\0'; ++argv[1]) { /* iterate chars in ref */ - /* iterate argc */ - for (size_t i = 2 /* ref cmp */; i < argc; ++argv[i], ++i) { - /* this doesn't overrun because of nul termination */ + /* This compares the Nth character of arg[2] onward with argv[1]'s Nth + * character, rather than comparing each arg with argv[1] sequentially. */ + for (; *argv[1] != '\0'; ++argv[1]) { /* iterate chars in argv[1] */ + for (size_t i = 2; i < argc; ++argv[i], ++i) { /* iterate &argv[2] */ + /* this never overruns because of nul termination */ if (*argv[i-1] != *argv[i]) { return *argv[i-1] - *argv[i]; } } } From 27ff64dffabd38555524fdd5b2838af7ec7cc5a4 Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 15 Jul 2024 14:51:54 -0600 Subject: [PATCH 248/343] intcmp(1): add comments --- src/intcmp.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/intcmp.rs b/src/intcmp.rs index 88be72c..f504b50 100644 --- a/src/intcmp.rs +++ b/src/intcmp.rs @@ -34,45 +34,45 @@ fn usage(s: &str) -> ExitCode { fn main() -> ExitCode { let argv = args().collect::>(); - let mut can_eq = false; - let mut can_gt = false; - let mut can_lt = false; + let mut e = false; /* args can be == */ + let mut g = false; /* args can be > */ + let mut l = false; /* args can be < */ let mut optind = 0; if argv.len() < 3 { return usage(&argv[0]); } while let Some(opt) = argv.getopt("egl") { match opt.opt() { - Ok("e") => can_eq = true, - Ok("g") => can_gt = true, - Ok("l") => can_lt = true, + Ok("e") => e = true, + Ok("g") => g = true, + Ok("l") => l = true, _ => { return usage(&argv[0]); }, } optind = opt.ind(); } - if argv.len() - optind < 2 /* ref cmp */ { return usage(&argv[0]); } + if argv.len() - optind < 2 /* see usage */ { return usage(&argv[0]); } - let mut reference: Option = None; - let mut cmpn: usize; + let mut prev: Option = None; /* no previous operand */ + let mut currn: usize; - for arg in argv.iter().skip(optind) { - match arg.parse::() { - Ok(n) => cmpn = n, + for arg in argv.iter().skip(optind) { /* iterate operands */ + match arg.parse::() { /* parse current operand */ + Ok(n) => currn = n, _ => { eprintln!("{}: {}: Invalid integer", &argv[0], arg); return ExitCode::from(EX_USAGE as u8); } } - if let Some(refn) = reference { - if (!can_eq && refn == cmpn) - || (!can_gt && refn > cmpn) - || (!can_lt && refn < cmpn) + if let Some(prevn) = prev { /* if there was a previous opr., test */ + if (!e && prevn == currn) + || (!g && prevn > currn) + || (!l && prevn < currn) { return ExitCode::FAILURE; } } - reference = Some(cmpn); + prev = Some(currn); /* there is a previous operand */ } ExitCode::SUCCESS From 3ba6682ab3af10cf2c1e00a7e4f766f24abe4db7 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 19 Jul 2024 16:41:02 -0600 Subject: [PATCH 249/343] STYLE: extern and use statements rules --- STYLE | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/STYLE b/STYLE index 23cd0c5..4c03953 100644 --- a/STYLE +++ b/STYLE @@ -1,6 +1,8 @@ 0. Braces are mandatory for all control flow, as it improves the visibility of - scope. +scope. + 1. Nested indentation should be kept to a minimum. + 2. Empty lines should be placed between different kinds of statements: int t; @@ -22,7 +24,7 @@ return io; 3. Each block of code should be indented once more than the keyword which - initiated the block: +initiated the block: switch (c) { case 'e': mode |= EQUAL; break; @@ -32,13 +34,13 @@ } 4. In C, spaces should be placed in control flow statements after the keyword - and before the opening brace: +and before the opening brace: for (i = 2; i < argc; ++i) { 5. If a function, a C control flow statement, or a Rust macro has arguments that - cause the statement to be broken into multiple lines, this should be done by - placing the arguments on a new line inside the parentheses: +cause the statement to be broken into multiple lines, this should be done by +placing the arguments on a new line inside the parentheses: let usage = format!( "Usage: {} [-d delimiter] index command [args...]", @@ -46,7 +48,7 @@ ); 6. If Rust function arguments or fields are on their own lines, they should - always have a trailing comma: +always have a trailing comma: return Err(EvaluationError { message: format!("{}: Invalid token", i), @@ -54,21 +56,32 @@ }) 7. If text is on the same line as a brace, spaces should be placed after an - opening curly brace and before a closing one: +opening curly brace and before a closing one: use sysexits::{ EX_DATAERR, EX_IOERR, EX_UNAVAILABLE, EX_USAGE }; 8. If a control flow statement is short enough to be easily understood in a - glance, it may be placed on a single line: +glance, it may be placed on a single line: if (!argc < 0) { usage(program_name); } 9. In C, note everything you use from a library in a comment subsequent to its - #include statement: +#include statement: #include /* close(2), getopt(3), lseek(2), read(2), write(2), * optarg, optind, STDIN_FILENO, STDOUT_FILENO */ +10. In Rust, place extern statements after use statements that include standard +library crates. Group alike statements: + + use std::fs::Path; + + extern crate strerror; + extern crate sysexits; + + use strerror::StrError; + use sysexits::{ EX_OSERR, EX_USAGE }; + -- Copyright © 2024 Emma Tebibyte From 22bb26b9cbc74b699399e1b5ed27474060add5e1 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 19 Jul 2024 17:04:49 -0600 Subject: [PATCH 250/343] STYLE: added introduction statement --- STYLE | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/STYLE b/STYLE index 4c03953..e59b6fd 100644 --- a/STYLE +++ b/STYLE @@ -1,5 +1,7 @@ -0. Braces are mandatory for all control flow, as it improves the visibility of -scope. +The following guidelines are conducive to clear and readable code that is +consistent with the style of the rest of the Bonsai Computer System. + +0. Braces are mandatory for all control flow. 1. Nested indentation should be kept to a minimum. From f7ebe7cf573aaedf813fb2f7aa50f8ccd3c64c0d Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 19 Jul 2024 17:31:51 -0600 Subject: [PATCH 251/343] STYLE: added 10 rules reference --- STYLE | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/STYLE b/STYLE index e59b6fd..4e35af6 100644 --- a/STYLE +++ b/STYLE @@ -84,8 +84,33 @@ library crates. Group alike statements: use strerror::StrError; use sysexits::{ EX_OSERR, EX_USAGE }; +11. Do not use do while loops in C. + +12. Follow the rules from the paper The Power of 10: Rules for Developing +Safety-Critical Code [0]: + 1. Avoid complex flow constructs, such as goto and recursion. + 2. All loops must have fixed bounds. This prevents runaway code. + 3. Avoid heap memory allocation. + 4. Restrict functions to a single printed page. + 5. Use a minimum of two runtime assertions per function. + 6. Restrict the scope of data to the smallest possible. + 7. Check the return value of all non-void functions, or cast to void to + indicate the return value is useless. + 8. Use the preprocessor sparingly. + 9. Limit pointer use to a single dereference, and do not use function + pointers. + 10. Compile with all possible warnings active; all warnings should then be + addressed before release of the software. + + +References +========== + +[0] + -- Copyright © 2024 Emma Tebibyte +Copyright © Wikipedia contributors This work is licensed under CC BY-SA 4.0. To view a copy of this license, visit . From a01cea572daf71b08624824941b561723967bf80 Mon Sep 17 00:00:00 2001 From: DTB Date: Fri, 19 Jul 2024 18:26:59 -0600 Subject: [PATCH 252/343] dj(1): replace do/while on hard seeking --- src/dj.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/dj.c b/src/dj.c index 22772cb..4af59ff 100644 --- a/src/dj.c +++ b/src/dj.c @@ -259,28 +259,27 @@ int main(int argc, char *argv[]) { } } - /* hard seeking */ - if (io[1].seek > 0) { - size_t t; + assert(io[1].bufuse == 0); /* requirement for hard seeking */ - do { - memset( - io[1].buf, '\0', - (t = io[1].bufuse = MIN(io[1].bs, io[1].seek)) - ); + /* hard seeking; t is io[1].bufuse, before Io_write subtracts from it */ + for(size_t t; io[1].seek > 0; io[1].seek -= (t - io[1].bufuse)) { + memset( + io[1].buf, '\0', /* set buf to all nulls */ + (t = io[1].bufuse = MIN(io[1].bs, io[1].seek)) /* saturate block */ + ); - if (Io_write(&io[1])->bufuse == t && !noerror && io[1].error == 0) { - Io_write(&io[1]); /* second chance */ - } - if (io[1].error != 0) { - return oserr(io[1].fn, io[1].error); - } - } while ((io[1].seek -= (t - io[1].bufuse)) > 0 && io[1].bufuse != t); + if (Io_write(&io[1])->bufuse == t && !noerror && io[1].error == 0) { + Io_write(&io[1]); /* second chance */ + } - io[1].bufuse = 0; + if (io[1].error != 0) { return oserr(io[1].fn, io[1].error); } + + if (io[1].bufuse == t) { break; } /* all writes failed! */ } - if (io[1].seek > 0) { + io[1].bufuse = 0; + + if (io[1].seek > 0) { /* hard seeking failed */ fprintio(stderr, fmt, io); return oserr(io[1].fn, errno); } From 71f4a411b69356772ee90466586670f4c194b6c7 Mon Sep 17 00:00:00 2001 From: DTB Date: Fri, 19 Jul 2024 18:40:24 -0600 Subject: [PATCH 253/343] dj(1): replace do/while in write loop --- src/dj.c | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/src/dj.c b/src/dj.c index 4af59ff..593ae31 100644 --- a/src/dj.c +++ b/src/dj.c @@ -157,7 +157,7 @@ usage(char *s) { } int main(int argc, char *argv[]) { - int align; /* low 8b used, negative if no alignment is being done */ + int align; /* low 8b used, negative if no alignment is being done */ int count; /* 0 if dj(1) runs until no more reads are possible */ char *fmt; /* == fmt_asv (default) or fmt_human (-H) */ size_t i; /* side of io being modified */ @@ -331,21 +331,20 @@ int main(int argc, char *argv[]) { } } - /* write */ - do { /* while(io[0].bufuse > 0); */ - int t; + assert(io[0].bufuse > 0); + while (io[0].bufuse > 0) { /* write */ if (io[0].bs <= io[1].bs) { int n; - /* saturate obuf */ - memcpy( + memcpy( /* saturate obuf */ io[1].buf, io[0].buf, (io[1].bufuse = (n = MIN(io[0].bufuse, io[1].bs))) ); + /* permute the copied units out of ibuf */ memmove(io[0].buf, &(io[0].buf)[n], (io[0].bufuse -= n)); - } else /* if(io[0].bs < io[1].bs) */ { + } else /* if(io[0].bs > io[1].bs) */ { int n; /* drain what we can from ibuf */ @@ -353,12 +352,10 @@ int main(int argc, char *argv[]) { &(io[1].buf)[io[1].bufuse], io[0].buf, (n = MIN(io[0].bufuse, io[1].bs - io[1].bufuse)) ); - io[1].bufuse += n; /* permute out the copied units */ memmove(io[0].buf, &(io[0].buf)[n], io[0].bs - n); - io[0].bufuse -= n; if(io[0].bs + io[1].bufuse <= io[1].bs && count != 1) { @@ -366,16 +363,27 @@ int main(int argc, char *argv[]) { } } - t = io[1].bufuse; - if (Io_write(&io[1])->bufuse == t && !noerror && io[1].error == 0) { - Io_write(&io[1]); /* second chance */ - } + { /* writes actually happen, or die */ + size_t t; - assert(io[1].bufuse <= t); + t = io[1].bufuse; + if (Io_write(&io[1])->bufuse == t + && !noerror + && io[1].error == 0) { + Io_write(&io[1]); /* second chance */ + } - if (io[1].bufuse == t) { /* no more love */ - count = 1; - break; + assert(io[1].error == 0 || io[1].bufuse == t); + /* if the Io_writes errored, bufuse wouldn't have changed, and + * the error will be reported at the end of the read/write + * loop */ + + assert(io[1].bufuse <= t); + + if (io[1].bufuse == t) { /* no more love */ + count = 1; + break; + } } if (0 < io[1].bufuse /* && io[1].bufuse < t */) { @@ -384,7 +392,7 @@ int main(int argc, char *argv[]) { if(!noerror) { count = 1; } } - } while(io[0].bufuse > 0); + } } while(count == 0 || --count > 0); fprintio(stderr, fmt, io); From c8b4f7a8b3bf4e39b1ce3e45302ab1f6994d29a2 Mon Sep 17 00:00:00 2001 From: DTB Date: Fri, 19 Jul 2024 19:03:23 -0600 Subject: [PATCH 254/343] str(1): edit out goto --- src/str.c | 54 +++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/str.c b/src/str.c index 73bb911..d6a89c3 100644 --- a/src/str.c +++ b/src/str.c @@ -20,11 +20,11 @@ #include #include /* NULL */ #include /* fprintf(3) */ -#include /* EXIT_FAILURE */ +#include /* size_t, EXIT_FAILURE */ #include /* strcmp(3) */ -#include +#include /* EX_USAGE */ -static char *program_name = "str"; +char *program_name = "str"; static struct { char *name; @@ -41,41 +41,41 @@ static struct { { "isprint", isprint }, { "ispunct", ispunct }, { "isspace", isspace }, - { "isupper", isupper } + { "isupper", isupper }, + { NULL, NULL } /* marks end */ }; +int usage(char *s){ + fprintf(stderr, "Usage: %s type string...\n", s); + return EX_USAGE; +} + int main(int argc, char *argv[]){ - int ctype; - int i; - int r; + size_t ctype; /* selected from ctypes.h; index of ctype */ + int retval; - if (argc >= 3) { - for (ctype = 0; ctype < (sizeof ctypes) / (sizeof *ctypes); ++ctype) { - if(strcmp(argv[1], ctypes[ctype].name) == 0) { - goto pass; - } - } - } + if (argc < 3) { return usage(argv[0] == NULL ? program_name : argv[0]); } - fprintf( - stderr, - "Usage: %s type string...\n", - argv[0] == NULL ? program_name : argv[0] + for ( /* iterate ctypes */ + ctype = 0; + ctypes[ctype].f != NULL /* break at the end of ctypes */ + && strcmp(argv[1], ctypes[ctype].name) != 0; /* break at match */ + ++ctype ); - return EX_USAGE; + if (ctypes[ctype].f == NULL) { return usage(argv[0]); } -pass: for (argv += 2, r = 1; *argv != NULL; ++argv) { - for (i = 0; argv[0][i] != '\0'; ++i) { - /* First checks if argv[0][i] is valid ASCII; ctypes(3) - * don't handle non-ASCII. - * This is bad. */ + /* iterate args */ + for (argv += 2, retval = EXIT_FAILURE; *argv != NULL; ++argv) { + for (size_t i = 0; argv[0][i] != '\0'; ++i) { /* iterate arg bytes */ + /* First checks if argv[0][i] is valid ASCII; ctypes(3) don't + * handle non-ASCII. This is bad. */ if( (unsigned char)argv[0][i] < 0x80 && !ctypes[ctype].f(argv[0][i]) - ) { return 1; } - else { r = 0; } + ) { return EXIT_FAILURE; } + else { retval = EXIT_SUCCESS; } } } - return r; + return retval; } From 9086bf0d08ddc582273a516510ff7cf962a8d867 Mon Sep 17 00:00:00 2001 From: DTB Date: Fri, 19 Jul 2024 19:18:04 -0600 Subject: [PATCH 255/343] dj(1): remove do/while statement in read loop --- src/dj.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/dj.c b/src/dj.c index 593ae31..2301eb4 100644 --- a/src/dj.c +++ b/src/dj.c @@ -158,7 +158,7 @@ usage(char *s) { int main(int argc, char *argv[]) { int align; /* low 8b used, negative if no alignment is being done */ - int count; /* 0 if dj(1) runs until no more reads are possible */ + int count; /* -1 if dj(1) runs until no more reads are possible */ char *fmt; /* == fmt_asv (default) or fmt_human (-H) */ size_t i; /* side of io being modified */ char noerror; /* 0=exits (default) 1=retries on partial reads or writes */ @@ -166,7 +166,7 @@ int main(int argc, char *argv[]) { /* Set defaults. */ align = -1; - count = 0; + count = -1; fmt = fmt_asv; noerror = 0; for (i = 0; i < (sizeof io) / (sizeof *io); ++i) { @@ -284,7 +284,10 @@ int main(int argc, char *argv[]) { return oserr(io[1].fn, errno); } - do { /* while(count == 0 || --count > 0); */ + for ( ; + count == -1 || count > 0; + count -= (count != -1) /* decrement if counting */ + ) { assert(io[0].bufuse == 0); { /* read */ @@ -303,7 +306,7 @@ int main(int argc, char *argv[]) { assert(io[0].bufuse >= t); - if (io[0].bufuse == t) /* that's all she wrote */ { break; } + if (io[0].bufuse == t) { break; } /* that's all she wrote */ if (/* t < io[0].bufuse && */ io[0].bufuse < io[0].bs) { fprintf(stderr, "%s: Partial read:\n\t", program_name); @@ -326,7 +329,7 @@ int main(int argc, char *argv[]) { if (skipping > 0) { io[0].seek -= skipping; io[0].bufuse = 0; - count += (count != 0); + count += (count != -1); /* increment if counting */ continue; } } @@ -393,7 +396,7 @@ int main(int argc, char *argv[]) { if(!noerror) { count = 1; } } } - } while(count == 0 || --count > 0); + } fprintio(stderr, fmt, io); From 19eee6b4e569d8fd81617fc02012e739e5d45e0b Mon Sep 17 00:00:00 2001 From: DTB Date: Fri, 19 Jul 2024 19:31:34 -0600 Subject: [PATCH 256/343] scrut(1): replace do/while loop --- src/scrut.c | 100 ++++++++++++++++++++-------------------------------- 1 file changed, 39 insertions(+), 61 deletions(-) diff --git a/src/scrut.c b/src/scrut.c index 74a96dc..cb84f33 100644 --- a/src/scrut.c +++ b/src/scrut.c @@ -26,87 +26,65 @@ * S_ISFIFO, S_ISGID, S_ISREG, S_ISLNK, S_ISSOCK, * S_ISUID, S_ISVTX */ -static char args[] = "bcdefghkprsuwxLS"; -static char ops[(sizeof args) / (sizeof *args)]; -static char *program_name = "scrut"; +char *program_name = "scrut"; +static char args[] = "bcdefgkprsuwxLS"; int usage(char *s) { - fprintf( - stderr, - "Usage: %s [-%s] file...\n", - s == NULL ? program_name : s, args - ); - + fprintf(stderr, "Usage: %s [-%s] file...\n", s, args); return EX_USAGE; } int main(int argc, char *argv[]) { - struct stat buf; - int c; - size_t i; - char *p; + char sel[(sizeof args) / (sizeof *args)]; - if (argc < 2) { return usage(argv[0]); } + if (argc < 2) { return usage(argv[0] == NULL ? program_name : argv[0]); } - memset(ops, '\0', sizeof ops); - while ((c = getopt(argc, argv, args)) != -1) { - if ((p = strchr(args, c)) == NULL) { - return usage(argv[0]); - } else { - ops[p - args] = c; + { /* option parsing */ + char *p; + + memset(sel, '\0', sizeof sel); + for (int c; (c = getopt(argc, argv, args)) != -1;) { + if ((p = strchr(args, c)) == NULL) { return usage(argv[0]); } + else { sel[p - args] = c; } } - } - /* straighten out ops */ - for (i = 0, p = ops; i < (sizeof ops) / (sizeof *ops); ++i) { - if (ops[i] != '\0') { - *p = ops[i]; - if (&ops[i] != p++) { ops[i] = '\0'; } + /* straighten out selections */ + for (size_t i = 0, p = sel; i < (sizeof sel) / (sizeof *sel); ++i) { + if (sel[i] != '\0') { + *p = sel[i]; + if (&sel[i] != p++) { sel[i] = '\0'; } + } } } if (optind == argc) { return usage(argv[0]); } - argv += optind; - do { /* while(*++argv != NULL); */ + for (argv += optind ; *argv != NULL; ++argv) { + struct stat buf; + if(access(*argv, F_OK) != 0 || lstat(*argv, &buf) == -1) { return EXIT_FAILURE; /* doesn't exist or isn't stattable */ } - for (i = 0; ops[i] != '\0'; ++i) - if (ops[i] == 'e') { - continue; - } else if (ops[i] == 'h') { - return usage(argv[0]); - } else if ( - (ops[i] == 'b' - && !S_ISBLK(buf.st_mode)) - || (ops[i] == 'c' - && !S_ISCHR(buf.st_mode)) - || (ops[i] == 'd' - && !S_ISDIR(buf.st_mode)) - || (ops[i] == 'f' - && !S_ISREG(buf.st_mode)) - || (ops[i] == 'g' - && !(buf.st_mode & S_ISGID)) - || (ops[i] == 'k' - && !(buf.st_mode & S_ISVTX)) - || (ops[i] == 'p' - && !S_ISFIFO(buf.st_mode)) - || (ops[i] == 'r' - && access(*argv, R_OK) != 0) - || (ops[i] == 'u' - && !(buf.st_mode & S_ISUID)) - || (ops[i] == 'w' - && access(*argv, W_OK) != 0) - || (ops[i] == 'x' - && access(*argv, X_OK) != 0) - || (ops[i] == 'L' - && !S_ISLNK(buf.st_mode)) - || (ops[i] == 'S' - && !S_ISSOCK(buf.st_mode)) + for (size_t i = 0; sel[i] != '\0'; ++i) { + if ( + (sel[i] == 'b' && !S_ISBLK(buf.st_mode)) + || (sel[i] == 'c' && !S_ISCHR(buf.st_mode)) + || (sel[i] == 'd' && !S_ISDIR(buf.st_mode)) + || (sel[i] == 'e' && 0) + || (sel[i] == 'f' && !S_ISREG(buf.st_mode)) + || (sel[i] == 'g' && !(buf.st_mode & S_ISGID)) + || (sel[i] == 'k' && !(buf.st_mode & S_ISVTX)) + || (sel[i] == 'p' && !S_ISFIFO(buf.st_mode)) + || (sel[i] == 'r' && access(*argv, R_OK) != 0) + || (sel[i] == 'u' && !(buf.st_mode & S_ISUID)) + || (sel[i] == 'w' && access(*argv, W_OK) != 0) + || (sel[i] == 'x' && access(*argv, X_OK) != 0) + || (sel[i] == 'L' && !S_ISLNK(buf.st_mode)) + || (sel[i] == 'S' && !S_ISSOCK(buf.st_mode)) ) { return EXIT_FAILURE; } - } while(*++argv != NULL); + } + } return EXIT_SUCCESS; } From f96ed9c1f3f0d80d6277bdf6d9c143704fd0fe39 Mon Sep 17 00:00:00 2001 From: DTB Date: Fri, 19 Jul 2024 19:34:37 -0600 Subject: [PATCH 257/343] scrut(1): fix syntax error --- src/scrut.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/scrut.c b/src/scrut.c index cb84f33..5e41def 100644 --- a/src/scrut.c +++ b/src/scrut.c @@ -48,8 +48,9 @@ int main(int argc, char *argv[]) { else { sel[p - args] = c; } } - /* straighten out selections */ - for (size_t i = 0, p = sel; i < (sizeof sel) / (sizeof *sel); ++i) { + /* straighten out selections; permute out nulls */ + p = sel; + for (size_t i = 0; i < (sizeof sel) / (sizeof *sel); ++i) { if (sel[i] != '\0') { *p = sel[i]; if (&sel[i] != p++) { sel[i] = '\0'; } From 0282b60e650305182ab13448e58284da5067fb6c Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 20 Jul 2024 07:18:59 -0600 Subject: [PATCH 258/343] dj(1), mm(1), npc(1), scrut(1), str(1): consistent argv[0] handling --- src/dj.c | 9 +++++---- src/mm.c | 17 +++++++++-------- src/npc.c | 7 +++++-- src/scrut.c | 7 ++++--- src/str.c | 11 ++++++----- 5 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/dj.c b/src/dj.c index 2301eb4..894feba 100644 --- a/src/dj.c +++ b/src/dj.c @@ -30,7 +30,7 @@ extern int errno; -char *program_name = "dj"; +static char *program_name = "dj"; /* dj uses two structures that respectively correspond to the reading and * writing ends of its jockeyed "pipe". User-configurable members are noted @@ -150,7 +150,7 @@ usage(char *s) { fprintf( stderr, "Usage: %s [-Hn] [-a byte] [-c count]\n" "\t[-i file] [-b block_size] [-s offset]\n" - "\t[-o file] [-B block_size] [-S offset]\n", program_name + "\t[-o file] [-B block_size] [-S offset]\n", s ); return EX_USAGE; @@ -163,6 +163,7 @@ int main(int argc, char *argv[]) { size_t i; /* side of io being modified */ char noerror; /* 0=exits (default) 1=retries on partial reads or writes */ struct Io io[2 /* { in, out } */]; + char *s = (argv[0] == NULL ? program_name : argv[0]); /* Set defaults. */ align = -1; @@ -233,7 +234,7 @@ int main(int argc, char *argv[]) { /* FALLTHROUGH */ default: - return usage(program_name); + return usage(s); } } } @@ -241,7 +242,7 @@ int main(int argc, char *argv[]) { assert(io->fd != STDIN_FILENO || io->fl == read_flags); assert(io->fd != STDOUT_FILENO || io->fl == write_flags); - if (argc > optind) { return usage(program_name); } + if (argc > optind) { return usage(s); } for (i = 0; i < (sizeof io) / (sizeof *io); ++i) { /* buffer allocation */ diff --git a/src/mm.c b/src/mm.c index 0aced76..459d3b3 100644 --- a/src/mm.c +++ b/src/mm.c @@ -48,7 +48,7 @@ struct Files{ #endif /* pre-allocated strings */ -static char *program_name = ""; +static char *program_name = "mm"; static char *stdin_name = ""; static char *stdout_name = ""; static char *stderr_name = ""; @@ -125,6 +125,7 @@ int main(int argc, char *argv[]) { size_t j; size_t k; /* loop index but also unbuffer status */ int retval; + char *s = argv[0] == NULL ? program_name : argv[0]; /* Initializes the files structs with their default values, standard * input and standard output. If an input or an output is specified @@ -149,7 +150,7 @@ int main(int argc, char *argv[]) { k = 0; - if (argc > 0) { program_name = argv[0]; } + if (argc > 0) { program_name = s; } if (argc > 1) { while ((c = getopt(argc, argv, "aehi:no:u")) != -1) { @@ -163,7 +164,7 @@ int main(int argc, char *argv[]) { break; } - retval = oserr(argv[0], "-e"); + retval = oserr(s, "-e"); terminate; case 'i': if ( @@ -172,7 +173,7 @@ int main(int argc, char *argv[]) { || Files_open(&files[0], optarg) != NULL ) { break; } - retval = oserr(argv[0], optarg); + retval = oserr(s, optarg); terminate; case 'o': if ( @@ -190,25 +191,25 @@ int main(int argc, char *argv[]) { } } - retval = oserr(argv[0], optarg); + retval = oserr(s, optarg); terminate; case 'n': if (signal(SIGINT, SIG_IGN) != SIG_ERR) { break; } - retval = oserr(argv[0], "-n"); + retval = oserr(s, "-n"); terminate; case 'u': k = 1; break; default: - retval = usage(argv[0]); + retval = usage(s); terminate; } } } if (optind != argc) { - retval = usage(argv[0]); + retval = usage(s); terminate; } diff --git a/src/npc.c b/src/npc.c index 5e00351..0767163 100644 --- a/src/npc.c +++ b/src/npc.c @@ -23,6 +23,8 @@ #include /* getopt(3) */ #include /* EX_OK, EX_USAGE */ +static char *program_name = "dj"; + int usage(char *s) { fprintf(stderr, "Usage: %s [-et]\n", s); return EX_USAGE; @@ -32,18 +34,19 @@ int main(int argc, char *argv[]) { int c; char showend = 0; /* print a dollar sign before each newline */ char showtab = 0; /* prints tab characters in caret notation */ + char *s = (argv[0] == NULL ? program_name : argv[0]); if (argc > 0) { while ((c = getopt(argc, argv, "et")) != -1) { switch (c){ case 'e': showend = 1; break; case 't': showtab = 1; break; - default: return usage(argv[0]); + default: return usage(s); } } } - if (argc > optind) { return usage(argv[0]); } + if (argc > optind) { return usage(s); } while ((c = getc(stdin)) != EOF) { if ((c & 0x80) != 0) { fputs("M-", stdout); } diff --git a/src/scrut.c b/src/scrut.c index 5e41def..ad2ed92 100644 --- a/src/scrut.c +++ b/src/scrut.c @@ -26,7 +26,7 @@ * S_ISFIFO, S_ISGID, S_ISREG, S_ISLNK, S_ISSOCK, * S_ISUID, S_ISVTX */ -char *program_name = "scrut"; +static char *program_name = "scrut"; static char args[] = "bcdefgkprsuwxLS"; int usage(char *s) { @@ -36,15 +36,16 @@ int usage(char *s) { int main(int argc, char *argv[]) { char sel[(sizeof args) / (sizeof *args)]; + char *s = (argv[0] == NULL ? program_name : argv[0]); - if (argc < 2) { return usage(argv[0] == NULL ? program_name : argv[0]); } + if (argc < 2) { return usage(s); } { /* option parsing */ char *p; memset(sel, '\0', sizeof sel); for (int c; (c = getopt(argc, argv, args)) != -1;) { - if ((p = strchr(args, c)) == NULL) { return usage(argv[0]); } + if ((p = strchr(args, c)) == NULL) { return usage(s); } else { sel[p - args] = c; } } diff --git a/src/str.c b/src/str.c index d6a89c3..646e4c7 100644 --- a/src/str.c +++ b/src/str.c @@ -53,8 +53,9 @@ int usage(char *s){ int main(int argc, char *argv[]){ size_t ctype; /* selected from ctypes.h; index of ctype */ int retval; + char *s = (argv[0] == NULL ? program_name : argv[0]); - if (argc < 3) { return usage(argv[0] == NULL ? program_name : argv[0]); } + if (argc < 3) { return usage(s); } for ( /* iterate ctypes */ ctype = 0; @@ -63,15 +64,15 @@ int main(int argc, char *argv[]){ ++ctype ); - if (ctypes[ctype].f == NULL) { return usage(argv[0]); } + if (ctypes[ctype].f == NULL) { return usage(s); } /* iterate args */ for (argv += 2, retval = EXIT_FAILURE; *argv != NULL; ++argv) { - for (size_t i = 0; argv[0][i] != '\0'; ++i) { /* iterate arg bytes */ - /* First checks if argv[0][i] is valid ASCII; ctypes(3) don't + for (size_t i = 0; s[i] != '\0'; ++i) { /* iterate arg bytes */ + /* First checks if s[i] is valid ASCII; ctypes(3) don't * handle non-ASCII. This is bad. */ if( - (unsigned char)argv[0][i] < 0x80 && !ctypes[ctype].f(argv[0][i]) + (unsigned char)s[i] < 0x80 && !ctypes[ctype].f(s[i]) ) { return EXIT_FAILURE; } else { retval = EXIT_SUCCESS; } } From 2fe3aa894c02b8cba4b9dd40a263c52bb94b45b4 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 24 Jul 2024 19:37:07 -0600 Subject: [PATCH 259/343] dj(1), intcmp(1), mm(1), npc(1), scrut(1), strcmp(1): changes to use and modify program_name --- src/dj.c | 8 ++++---- src/intcmp.c | 12 ++++++------ src/mm.c | 18 ++++++++---------- src/npc.c | 8 ++++---- src/scrut.c | 10 +++++----- src/strcmp.c | 2 +- 6 files changed, 28 insertions(+), 30 deletions(-) diff --git a/src/dj.c b/src/dj.c index 894feba..1913dd9 100644 --- a/src/dj.c +++ b/src/dj.c @@ -30,7 +30,7 @@ extern int errno; -static char *program_name = "dj"; +char *program_name = "dj"; /* dj uses two structures that respectively correspond to the reading and * writing ends of its jockeyed "pipe". User-configurable members are noted @@ -163,7 +163,7 @@ int main(int argc, char *argv[]) { size_t i; /* side of io being modified */ char noerror; /* 0=exits (default) 1=retries on partial reads or writes */ struct Io io[2 /* { in, out } */]; - char *s = (argv[0] == NULL ? program_name : argv[0]); + program_name = (argv[0] == NULL ? program_name : argv[0]); /* Set defaults. */ align = -1; @@ -234,7 +234,7 @@ int main(int argc, char *argv[]) { /* FALLTHROUGH */ default: - return usage(s); + return usage(program_name); } } } @@ -242,7 +242,7 @@ int main(int argc, char *argv[]) { assert(io->fd != STDIN_FILENO || io->fl == read_flags); assert(io->fd != STDOUT_FILENO || io->fl == write_flags); - if (argc > optind) { return usage(s); } + if (argc > optind) { return usage(program_name); } for (i = 0; i < (sizeof io) / (sizeof *io); ++i) { /* buffer allocation */ diff --git a/src/intcmp.c b/src/intcmp.c index 41a1592..7673944 100644 --- a/src/intcmp.c +++ b/src/intcmp.c @@ -30,7 +30,7 @@ /* 0b?00 */ /* Lesser or Equal | -le | 0b101 | 5 */ #define LESSER 0x04 /* Inequal (Greater or Lesser) | -gl | 0b110 | 6 */ -static char *program_name = "intcmp"; +char *program_name = "intcmp"; int usage(char *s) { fprintf(stderr, "Usage: %s [-egl] integer integer...\n", s); @@ -43,22 +43,22 @@ int main(int argc, char *argv[]) { size_t i; unsigned char mode; int r; /* reference integer */ - char *s = (argv[0] == NULL ? program_name : argv[0]); + program_name = (argv[0] == NULL ? program_name : argv[0]); mode = 0; - if (argc == 0 | argc < 3) { return usage(s); } + if (argc == 0 | argc < 3) { return usage(program_name); } while ((c = getopt(argc, argv, "egl")) != -1) { switch (c) { case 'e': mode |= EQUAL; break; case 'g': mode |= GREATER; break; case 'l': mode |= LESSER; break; - default: return usage(s); + default: return usage(program_name); } } - if (optind + 2 /* ref cmp */ > argc) { return usage(s); } + if (optind + 2 /* ref cmp */ > argc) { return usage(program_name); } i = optind; @@ -68,7 +68,7 @@ int main(int argc, char *argv[]) { if (*argv[i] != '\0' || errno != 0) { fprintf( - stderr, "%s: argument #%d: Invalid integer\n", argv[0], (int)i + stderr, "%s: argument #%d: Invalid integer\n", program_name, (int)i ); return EX_USAGE; } diff --git a/src/mm.c b/src/mm.c index 459d3b3..63cc3ff 100644 --- a/src/mm.c +++ b/src/mm.c @@ -48,7 +48,7 @@ struct Files{ #endif /* pre-allocated strings */ -static char *program_name = "mm"; +char *program_name = "mm"; static char *stdin_name = ""; static char *stdout_name = ""; static char *stderr_name = ""; @@ -125,7 +125,7 @@ int main(int argc, char *argv[]) { size_t j; size_t k; /* loop index but also unbuffer status */ int retval; - char *s = argv[0] == NULL ? program_name : argv[0]; + program_name = (argv[0] == NULL ? program_name : argv[0]); /* Initializes the files structs with their default values, standard * input and standard output. If an input or an output is specified @@ -150,8 +150,6 @@ int main(int argc, char *argv[]) { k = 0; - if (argc > 0) { program_name = s; } - if (argc > 1) { while ((c = getopt(argc, argv, "aehi:no:u")) != -1) { switch (c){ @@ -164,7 +162,7 @@ int main(int argc, char *argv[]) { break; } - retval = oserr(s, "-e"); + retval = oserr(program_name, "-e"); terminate; case 'i': if ( @@ -173,7 +171,7 @@ int main(int argc, char *argv[]) { || Files_open(&files[0], optarg) != NULL ) { break; } - retval = oserr(s, optarg); + retval = oserr(program_name, optarg); terminate; case 'o': if ( @@ -191,25 +189,25 @@ int main(int argc, char *argv[]) { } } - retval = oserr(s, optarg); + retval = oserr(program_name, optarg); terminate; case 'n': if (signal(SIGINT, SIG_IGN) != SIG_ERR) { break; } - retval = oserr(s, "-n"); + retval = oserr(program_name, "-n"); terminate; case 'u': k = 1; break; default: - retval = usage(s); + retval = usage(program_name); terminate; } } } if (optind != argc) { - retval = usage(s); + retval = usage(program_name); terminate; } diff --git a/src/npc.c b/src/npc.c index 0767163..4f74c6f 100644 --- a/src/npc.c +++ b/src/npc.c @@ -23,7 +23,7 @@ #include /* getopt(3) */ #include /* EX_OK, EX_USAGE */ -static char *program_name = "dj"; +char *program_name = "npc"; int usage(char *s) { fprintf(stderr, "Usage: %s [-et]\n", s); @@ -34,19 +34,19 @@ int main(int argc, char *argv[]) { int c; char showend = 0; /* print a dollar sign before each newline */ char showtab = 0; /* prints tab characters in caret notation */ - char *s = (argv[0] == NULL ? program_name : argv[0]); + program_name = (argv[0] == NULL ? program_name : argv[0]); if (argc > 0) { while ((c = getopt(argc, argv, "et")) != -1) { switch (c){ case 'e': showend = 1; break; case 't': showtab = 1; break; - default: return usage(s); + default: return usage(program_name); } } } - if (argc > optind) { return usage(s); } + if (argc > optind) { return usage(program_name); } while ((c = getc(stdin)) != EOF) { if ((c & 0x80) != 0) { fputs("M-", stdout); } diff --git a/src/scrut.c b/src/scrut.c index ad2ed92..7320c8f 100644 --- a/src/scrut.c +++ b/src/scrut.c @@ -26,7 +26,7 @@ * S_ISFIFO, S_ISGID, S_ISREG, S_ISLNK, S_ISSOCK, * S_ISUID, S_ISVTX */ -static char *program_name = "scrut"; +char *program_name = "scrut"; static char args[] = "bcdefgkprsuwxLS"; int usage(char *s) { @@ -36,16 +36,16 @@ int usage(char *s) { int main(int argc, char *argv[]) { char sel[(sizeof args) / (sizeof *args)]; - char *s = (argv[0] == NULL ? program_name : argv[0]); + program_name = (argv[0] == NULL ? program_name : argv[0]); - if (argc < 2) { return usage(s); } + if (argc < 2) { return usage(program_name); } { /* option parsing */ char *p; memset(sel, '\0', sizeof sel); for (int c; (c = getopt(argc, argv, args)) != -1;) { - if ((p = strchr(args, c)) == NULL) { return usage(s); } + if ((p = strchr(args, c)) == NULL) { return usage(program_name); } else { sel[p - args] = c; } } @@ -59,7 +59,7 @@ int main(int argc, char *argv[]) { } } - if (optind == argc) { return usage(argv[0]); } + if (optind == argc) { return usage(program_name); } for (argv += optind ; *argv != NULL; ++argv) { struct stat buf; diff --git a/src/strcmp.c b/src/strcmp.c index c9d56b0..16ec3ca 100644 --- a/src/strcmp.c +++ b/src/strcmp.c @@ -20,7 +20,7 @@ #include /* fprintf(3), stderr */ #include /* EX_OK, EX_USAGE */ -static char *program_name = "strcmp"; +char *program_name = "strcmp"; int main(int argc, char *argv[]) { int i; From 0641a487d711fcf11adba9e5b81da9f2407614e2 Mon Sep 17 00:00:00 2001 From: emma Date: Thu, 25 Jul 2024 21:17:30 -0600 Subject: [PATCH 260/343] intcmp(1): fixes pointless condition; formatting --- src/intcmp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/intcmp.c b/src/intcmp.c index 7673944..f990a10 100644 --- a/src/intcmp.c +++ b/src/intcmp.c @@ -47,7 +47,7 @@ int main(int argc, char *argv[]) { mode = 0; - if (argc == 0 | argc < 3) { return usage(program_name); } + if (argc == 0) { return usage(program_name); } while ((c = getopt(argc, argv, "egl")) != -1) { switch (c) { @@ -68,7 +68,10 @@ int main(int argc, char *argv[]) { if (*argv[i] != '\0' || errno != 0) { fprintf( - stderr, "%s: argument #%d: Invalid integer\n", program_name, (int)i + stderr, + "%s: argument #%d: Invalid integer\n", + program_name, + (int)i ); return EX_USAGE; } From c0a5e11eef53f166ba638ac561a4205905c9922b Mon Sep 17 00:00:00 2001 From: emma Date: Thu, 25 Jul 2024 21:28:42 -0600 Subject: [PATCH 261/343] mm(1): revert changes to program_name --- src/mm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mm.c b/src/mm.c index 63cc3ff..8779e8e 100644 --- a/src/mm.c +++ b/src/mm.c @@ -125,7 +125,6 @@ int main(int argc, char *argv[]) { size_t j; size_t k; /* loop index but also unbuffer status */ int retval; - program_name = (argv[0] == NULL ? program_name : argv[0]); /* Initializes the files structs with their default values, standard * input and standard output. If an input or an output is specified @@ -150,6 +149,8 @@ int main(int argc, char *argv[]) { k = 0; + if (argc > 0) { program_name = argv[0]; } + if (argc > 1) { while ((c = getopt(argc, argv, "aehi:no:u")) != -1) { switch (c){ From 199d48d85b29689d37d4bb4f78bc7e8fb83a83e9 Mon Sep 17 00:00:00 2001 From: DTB Date: Sat, 27 Jul 2024 17:59:47 -0600 Subject: [PATCH 262/343] swab(1): comment code --- src/swab.rs | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/swab.rs b/src/swab.rs index 5942c38..771d352 100644 --- a/src/swab.rs +++ b/src/swab.rs @@ -27,15 +27,12 @@ extern crate getopt; use getopt::GetOpt; extern crate sysexits; -use sysexits::{ EX_OK, EX_OSERR, EX_USAGE }; +use sysexits::{ EX_IOERR, EX_OK, EX_USAGE }; extern crate strerror; use strerror::StrError; -fn oserr(s: &str, e: Error) -> ExitCode { - eprintln!("{}: {}", s, e.strerror()); - ExitCode::from(EX_OSERR as u8) -} +fn err(s: &str, e: Error) { eprintln!("{}: {}", s, e.strerror()); } fn usage(s: &str) -> ExitCode { eprintln!("Usage: {} [-f] [-w word_size]", s); @@ -44,19 +41,20 @@ fn usage(s: &str) -> ExitCode { fn main() -> ExitCode { let argv = args().collect::>(); - let mut buf: Vec = Vec::new(); + let mut buf: Vec = Vec::new(); // holds the sequence getting swabbed let mut input = stdin(); let mut output = stdout().lock(); let mut force = false; - let mut wordsize: usize = 2; + let mut wordsize: usize = 2; // default; mimics dd(1p) conv=swab while let Some(opt) = argv.getopt("fw:") { match opt.opt() { Ok("f") => force = true, - Ok("w") => { + Ok("w") => { // sets new sequence length if let Some(arg) = opt.arg() { match arg.parse::() { + // an odd sequence length is nonsensical Ok(w) if w % 2 == 0 => { wordsize = w; () }, _ => { return usage(&argv[0]); }, } @@ -70,21 +68,28 @@ fn main() -> ExitCode { loop { match input.read(&mut buf) { - Ok(0) => break ExitCode::from(EX_OK as u8), - Ok(v) if v == wordsize => { + Ok(0) => break ExitCode::from(EX_OK as u8), // read nothing; bye + Ok(v) if v == wordsize => { // read full block; swab 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) + err(&argv[0], e); + break EX_IOERR // write error } + }, - Ok(v) => { + Ok(v) => { // partial read; partially write if let Err(e) = output.write(&buf[..v]) { - break oserr(&argv[0], e) + err(&argv[0], e); + break EX_IOERR // write error } }, Err(e) if e.kind() == ErrorKind::Interrupted && force => continue, - Err(e) => break oserr(&argv[0], e) + Err(e) => { + err(&argv[0], e); + break EX_IOERR // read error (or signal) + } } } } From cba8394d95a76c75801681b929640788ee9f90b3 Mon Sep 17 00:00:00 2001 From: DTB Date: Sat, 27 Jul 2024 18:18:29 -0600 Subject: [PATCH 263/343] str(1): fix argv parsing and add comments --- src/str.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/str.c b/src/str.c index 646e4c7..e503470 100644 --- a/src/str.c +++ b/src/str.c @@ -51,11 +51,10 @@ int usage(char *s){ } int main(int argc, char *argv[]){ - size_t ctype; /* selected from ctypes.h; index of ctype */ - int retval; - char *s = (argv[0] == NULL ? program_name : argv[0]); + size_t ctype; // selected from ctypes.h; index of ctype + int retval; // initially fail but becomes success on the first valid char - if (argc < 3) { return usage(s); } + if (argc < 3) { return usage(argv[0] == NULL ? program_name : argv[0]); } for ( /* iterate ctypes */ ctype = 0; @@ -64,15 +63,16 @@ int main(int argc, char *argv[]){ ++ctype ); - if (ctypes[ctype].f == NULL) { return usage(s); } + if (ctypes[ctype].f == NULL) { return usage(argv[0]); } /* iterate args */ for (argv += 2, retval = EXIT_FAILURE; *argv != NULL; ++argv) { - for (size_t i = 0; s[i] != '\0'; ++i) { /* iterate arg bytes */ - /* First checks if s[i] is valid ASCII; ctypes(3) don't + for (size_t i = 0; argv[0][i] != '\0'; ++i) { /* iterate arg bytes */ + /* First checks if argv[0][i] is valid ASCII; ctypes(3) don't * handle non-ASCII. This is bad. */ if( - (unsigned char)s[i] < 0x80 && !ctypes[ctype].f(s[i]) + (unsigned char)argv[0][i] < 0x80 // argv[0][i] is ASCII, + && !ctypes[ctype].f(argv[0][i]) // so use ctypes(3) ) { return EXIT_FAILURE; } else { retval = EXIT_SUCCESS; } } From c5c0e543e487dcf416ce44e9094606e417ac0650 Mon Sep 17 00:00:00 2001 From: DTB Date: Sat, 27 Jul 2024 18:21:17 -0600 Subject: [PATCH 264/343] mm(1): remove useless extern errno --- src/mm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mm.c b/src/mm.c index 8779e8e..e57e3b3 100644 --- a/src/mm.c +++ b/src/mm.c @@ -26,8 +26,6 @@ #include /* getopt(3) */ #include /* EX_IOERR, EX_OK, EX_OSERR, EX_USAGE */ -extern int errno; - /* This structure is how open files are tracked. */ struct Files{ size_t a; /* allocation */ From 429d0642090e91bc35dfcf7f5e04082d6bb9d250 Mon Sep 17 00:00:00 2001 From: DTB Date: Sat, 27 Jul 2024 18:22:43 -0600 Subject: [PATCH 265/343] mm(1): fix argv use --- src/mm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mm.c b/src/mm.c index e57e3b3..1d97ab5 100644 --- a/src/mm.c +++ b/src/mm.c @@ -147,9 +147,9 @@ int main(int argc, char *argv[]) { k = 0; - if (argc > 0) { program_name = argv[0]; } + if (argc > 0) { + program_name = argv[0]; - if (argc > 1) { while ((c = getopt(argc, argv, "aehi:no:u")) != -1) { switch (c){ case 'a': /* "rb+" -> "ab" */ From 5d481140835ed94e263d3921c9418b4a43059d12 Mon Sep 17 00:00:00 2001 From: DTB Date: Sat, 27 Jul 2024 18:32:04 -0600 Subject: [PATCH 266/343] dj(1), intcmp(1), mm(1), npc(1), scrut(1), str(1): make usage function consistent --- src/dj.c | 10 ++++++---- src/intcmp.c | 5 +++-- src/mm.c | 12 +++++++----- src/npc.c | 6 ++++-- src/scrut.c | 17 ++++++++++------- src/str.c | 6 ++++-- 6 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/dj.c b/src/dj.c index 1913dd9..c4ebf38 100644 --- a/src/dj.c +++ b/src/dj.c @@ -146,11 +146,13 @@ parse(char *s) { } static int -usage(char *s) { - fprintf( - stderr, "Usage: %s [-Hn] [-a byte] [-c count]\n" +usage(char *argv0) { + (void)fprintf( + stderr, + "Usage: %s [-Hn] [-a byte] [-c count]\n" "\t[-i file] [-b block_size] [-s offset]\n" - "\t[-o file] [-B block_size] [-S offset]\n", s + "\t[-o file] [-B block_size] [-S offset]\n", + argv0 ); return EX_USAGE; diff --git a/src/intcmp.c b/src/intcmp.c index f990a10..35fecf3 100644 --- a/src/intcmp.c +++ b/src/intcmp.c @@ -32,8 +32,9 @@ char *program_name = "intcmp"; -int usage(char *s) { - fprintf(stderr, "Usage: %s [-egl] integer integer...\n", s); +static int +usage(char *argv0) { + (void)fprintf(stderr, "Usage: %s [-egl] integer integer...\n", argv0); return EX_USAGE; } diff --git a/src/mm.c b/src/mm.c index 1d97ab5..d148446 100644 --- a/src/mm.c +++ b/src/mm.c @@ -107,11 +107,13 @@ oserr(char *s, char *r) { } \ return retval -/* Prints a usage text, in which s is the program being run (i.e. argv[0]), and - * returns an exit status appropriate for a usage error. */ -int usage(char *s) { - - fprintf(stderr, "Usage: %s [-aenu] [-i input]... [-o output]...\n", s); +static int +usage(char *argv0) { + (void)fprintf( + stderr, + "Usage: %s [-aenu] [-i input]... [-o output]...\n", + argv0 + ); return EX_USAGE; } diff --git a/src/npc.c b/src/npc.c index 4f74c6f..4cc4160 100644 --- a/src/npc.c +++ b/src/npc.c @@ -25,8 +25,10 @@ char *program_name = "npc"; -int usage(char *s) { - fprintf(stderr, "Usage: %s [-et]\n", s); +static int +usage(char *argv0) { + fprintf(stderr, "Usage: %s [-et]\n", argv0); + return EX_USAGE; } diff --git a/src/scrut.c b/src/scrut.c index 7320c8f..4d5a932 100644 --- a/src/scrut.c +++ b/src/scrut.c @@ -27,15 +27,18 @@ * S_ISUID, S_ISVTX */ char *program_name = "scrut"; -static char args[] = "bcdefgkprsuwxLS"; +#define OPTS "bcdefgkprsuwxLS" +static char *opts = OPTS; + +static int +usage(char *argv0) { + (void)fprintf(stderr, "Usage: %s [-" OPTS "] file...\n", argv0); -int usage(char *s) { - fprintf(stderr, "Usage: %s [-%s] file...\n", s, args); return EX_USAGE; } int main(int argc, char *argv[]) { - char sel[(sizeof args) / (sizeof *args)]; + char sel[(sizeof opts) / (sizeof *opts)]; program_name = (argv[0] == NULL ? program_name : argv[0]); if (argc < 2) { return usage(program_name); } @@ -44,9 +47,9 @@ int main(int argc, char *argv[]) { char *p; memset(sel, '\0', sizeof sel); - for (int c; (c = getopt(argc, argv, args)) != -1;) { - if ((p = strchr(args, c)) == NULL) { return usage(program_name); } - else { sel[p - args] = c; } + for (int c; (c = getopt(argc, argv, opts)) != -1;) { + if ((p = strchr(opts, c)) == NULL) { return usage(program_name); } + else { sel[p - opts] = c; } } /* straighten out selections; permute out nulls */ diff --git a/src/str.c b/src/str.c index e503470..a41e4a1 100644 --- a/src/str.c +++ b/src/str.c @@ -45,8 +45,10 @@ static struct { { NULL, NULL } /* marks end */ }; -int usage(char *s){ - fprintf(stderr, "Usage: %s type string...\n", s); +static int +usage(char *argv0){ + (void)fprintf(stderr, "Usage: %s type string...\n", argv0); + return EX_USAGE; } From 970b25dee29cc48e705f62ae49f37d698ca03f1d Mon Sep 17 00:00:00 2001 From: DTB Date: Sat, 27 Jul 2024 18:35:02 -0600 Subject: [PATCH 267/343] str(1): fix brackets --- src/str.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/str.c b/src/str.c index a41e4a1..9f7b351 100644 --- a/src/str.c +++ b/src/str.c @@ -46,13 +46,13 @@ static struct { }; static int -usage(char *argv0){ +usage(char *argv0) { (void)fprintf(stderr, "Usage: %s type string...\n", argv0); return EX_USAGE; } -int main(int argc, char *argv[]){ +int main(int argc, char *argv[]) { size_t ctype; // selected from ctypes.h; index of ctype int retval; // initially fail but becomes success on the first valid char From d45fa19d5cc4375b9706cf7b6ea55ba791a1ba8b Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 27 Jul 2024 23:59:32 -0600 Subject: [PATCH 268/343] dj(1): fixes extraneous ternary for program_name --- src/dj.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dj.c b/src/dj.c index c4ebf38..8dc066a 100644 --- a/src/dj.c +++ b/src/dj.c @@ -165,7 +165,6 @@ int main(int argc, char *argv[]) { size_t i; /* side of io being modified */ char noerror; /* 0=exits (default) 1=retries on partial reads or writes */ struct Io io[2 /* { in, out } */]; - program_name = (argv[0] == NULL ? program_name : argv[0]); /* Set defaults. */ align = -1; From aed64840ea9adcf332ba482cc0fb53f27cc9a5cd Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 28 Jul 2024 00:12:34 -0600 Subject: [PATCH 269/343] STYLE: fixes some concerns --- STYLE | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/STYLE b/STYLE index 4e35af6..76ecc99 100644 --- a/STYLE +++ b/STYLE @@ -65,7 +65,7 @@ opening curly brace and before a closing one: 8. If a control flow statement is short enough to be easily understood in a glance, it may be placed on a single line: - if (!argc < 0) { usage(program_name); } + if !(argc < 0) { usage(program_name); } 9. In C, note everything you use from a library in a comment subsequent to its #include statement: @@ -86,13 +86,13 @@ library crates. Group alike statements: 11. Do not use do while loops in C. -12. Follow the rules from the paper The Power of 10: Rules for Developing -Safety-Critical Code [0]: +12. Follow the following rules from the paper The Power of 10: Rules for +Developing Safety-Critical Code [0]: 1. Avoid complex flow constructs, such as goto and recursion. 2. All loops must have fixed bounds. This prevents runaway code. 3. Avoid heap memory allocation. - 4. Restrict functions to a single printed page. - 5. Use a minimum of two runtime assertions per function. + 4. Restrict functions to the length of a single printed page. + 6. Restrict the scope of data to the smallest possible. 7. Check the return value of all non-void functions, or cast to void to indicate the return value is useless. @@ -100,7 +100,8 @@ Safety-Critical Code [0]: 9. Limit pointer use to a single dereference, and do not use function pointers. 10. Compile with all possible warnings active; all warnings should then be - addressed before release of the software. + addressed before release of the software (for C compilers, compile with + -Wpedantic). References From d5d13b84a76a07182814bf87be92d05b9fe45cc1 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 28 Jul 2024 00:34:42 -0600 Subject: [PATCH 270/343] STYLE: repition & Kernighan quote --- STYLE | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/STYLE b/STYLE index 76ecc99..5322661 100644 --- a/STYLE +++ b/STYLE @@ -86,7 +86,7 @@ library crates. Group alike statements: 11. Do not use do while loops in C. -12. Follow the following rules from the paper The Power of 10: Rules for +12. Adhere to the following rules from the paper The Power of 10: Rules for Developing Safety-Critical Code [0]: 1. Avoid complex flow constructs, such as goto and recursion. 2. All loops must have fixed bounds. This prevents runaway code. @@ -95,7 +95,8 @@ Developing Safety-Critical Code [0]: 6. Restrict the scope of data to the smallest possible. 7. Check the return value of all non-void functions, or cast to void to - indicate the return value is useless. + indicate the return value is useless (such as in the case of using + fprintf(3p) to print to the standard error). 8. Use the preprocessor sparingly. 9. Limit pointer use to a single dereference, and do not use function pointers. @@ -103,6 +104,12 @@ Developing Safety-Critical Code [0]: addressed before release of the software (for C compilers, compile with -Wpedantic). +13. Remember this quote from The Elements of Programming Style by Brian +Kernighan: + Everyone knows that debugging is twice as hard as writing a program in the + first place. So if you're as clever as you can be when you write it, how + will you ever debug it? + References ========== From 09193a14d5dcdc324387081667c02aa4854bee0b Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 28 Jul 2024 00:35:55 -0600 Subject: [PATCH 271/343] fop(1): fixes unhandled i/o error --- src/fop.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/fop.rs b/src/fop.rs index 061815e..0faa827 100644 --- a/src/fop.rs +++ b/src/fop.rs @@ -70,7 +70,10 @@ fn main() { }); let mut buf = String::new(); - let _ = stdin().read_to_string(&mut buf); + if let Err(e) = stdin().read_to_string(&mut buf) { + eprintln!("{}: {}", argv[0], e.strerror); + exit(EX_IOERR); + }; /* split the buffer by the delimiter (by default, '\u{1E}') */ let mut fields = buf.split(&d).collect::>(); From 0f121cbac735fb5a43c8106a42f4b38e30fcb269 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 28 Jul 2024 00:40:16 -0600 Subject: [PATCH 272/343] fop(1): more descriptive command arguments variable name --- src/fop.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fop.rs b/src/fop.rs index 0faa827..fc45248 100644 --- a/src/fop.rs +++ b/src/fop.rs @@ -79,7 +79,7 @@ fn main() { let mut fields = buf.split(&d).collect::>(); /* collect arguments for the operator command */ - let opts = argv + let command_args = argv .iter() .clone() .skip(command_arg + 1) /* skip the command name */ @@ -87,7 +87,7 @@ fn main() { /* spawn the command to operate on the field */ let mut spawned = Command::new(operator) - .args(opts) /* spawn with the specified arguments */ + .args(command_args) /* spawn with the specified arguments */ .stdin(Stdio::piped()) .stdout(Stdio::piped()) /* piped stdout to handle output ourselves */ .spawn() From d2ae35eac9eca030d9b96252706da8494b7f5b18 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 28 Jul 2024 01:15:08 -0600 Subject: [PATCH 273/343] fop(1): fixes glaring issue with newline handling --- src/fop.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/fop.rs b/src/fop.rs index fc45248..06024d5 100644 --- a/src/fop.rs +++ b/src/fop.rs @@ -71,7 +71,7 @@ fn main() { let mut buf = String::new(); if let Err(e) = stdin().read_to_string(&mut buf) { - eprintln!("{}: {}", argv[0], e.strerror); + eprintln!("{}: {}", argv[0], e.strerror()); exit(EX_IOERR); }; @@ -120,8 +120,13 @@ fn main() { /* get the output with which the original field will be replaced */ let mut replace = output.stdout.clone(); - /* as long as it’s not a newline, set the replacement to the output */ - if replace.pop() != Some(b'\n') { replace = output.stdout; } + /* pop trailing newline out if the input did not contain it */ + if fields[index].chars().last() != Some('\n') /* no newline */ + && replace.pop() != Some(b'\n') { /* pop last char of replacement */ + /* restore replacement to original command output if popped char was not + * a newline */ + replace = output.stdout; + } /* convert the output of the program to UTF-8 */ let new_field = String::from_utf8(replace).unwrap_or_else(|e| { From 68e31058a864052d03605b859fa96459167824b8 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 28 Jul 2024 17:49:39 -0600 Subject: [PATCH 274/343] intcmp(1): move program_name ternary --- src/intcmp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/intcmp.c b/src/intcmp.c index 35fecf3..88356b4 100644 --- a/src/intcmp.c +++ b/src/intcmp.c @@ -44,10 +44,10 @@ int main(int argc, char *argv[]) { size_t i; unsigned char mode; int r; /* reference integer */ - program_name = (argv[0] == NULL ? program_name : argv[0]); - mode = 0; + program_name = (argv[0] == NULL ? program_name : argv[0]); + if (argc == 0) { return usage(program_name); } while ((c = getopt(argc, argv, "egl")) != -1) { From 6b9d13b8a0dc6a8a072148954e0e222a085c57d8 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 28 Jul 2024 18:27:22 -0600 Subject: [PATCH 275/343] fop(1): better opt matching --- src/fop.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fop.rs b/src/fop.rs index 06024d5..bbca85e 100644 --- a/src/fop.rs +++ b/src/fop.rs @@ -42,12 +42,12 @@ fn main() { while let Some(opt) = argv.getopt("d:") { match opt.opt() { - Ok(_) => { + Ok("d") => { /* delimiter */ d = opt.arg().unwrap(); optind = opt.ind(); }, - Err(_) => { + _ => { eprintln!("{}", usage); exit(EX_USAGE); } From 338a3e715550c84d4049fb802bf000e1bf26a9ad Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 28 Jul 2024 18:31:01 -0600 Subject: [PATCH 276/343] intcmp(1): move program_name ternary --- src/intcmp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/intcmp.c b/src/intcmp.c index 88356b4..3e329b9 100644 --- a/src/intcmp.c +++ b/src/intcmp.c @@ -46,20 +46,20 @@ int main(int argc, char *argv[]) { int r; /* reference integer */ mode = 0; - program_name = (argv[0] == NULL ? program_name : argv[0]); - - if (argc == 0) { return usage(program_name); } + if (argc < 3) { + return usage(argv[0] == NULL ? program_name : argv[0]); + } while ((c = getopt(argc, argv, "egl")) != -1) { switch (c) { case 'e': mode |= EQUAL; break; case 'g': mode |= GREATER; break; case 'l': mode |= LESSER; break; - default: return usage(program_name); + default: return usage(argv[0]); } } - if (optind + 2 /* ref cmp */ > argc) { return usage(program_name); } + if (optind + 2 /* ref cmp */ > argc) { return usage(argv[0]); } i = optind; @@ -71,7 +71,7 @@ int main(int argc, char *argv[]) { fprintf( stderr, "%s: argument #%d: Invalid integer\n", - program_name, + argv[0], (int)i ); return EX_USAGE; From 44d461fb16ddc9bfb91565ad7417fe7e9f912548 Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 28 Jul 2024 18:33:49 -0600 Subject: [PATCH 277/343] scrut(1): return program_name ternary to former position --- src/scrut.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/scrut.c b/src/scrut.c index 4d5a932..39fa698 100644 --- a/src/scrut.c +++ b/src/scrut.c @@ -39,16 +39,15 @@ usage(char *argv0) { int main(int argc, char *argv[]) { char sel[(sizeof opts) / (sizeof *opts)]; - program_name = (argv[0] == NULL ? program_name : argv[0]); - if (argc < 2) { return usage(program_name); } + if (argc < 2) { return usage(argv[0] == NULL ? program_name : argv[0]); } { /* option parsing */ char *p; memset(sel, '\0', sizeof sel); for (int c; (c = getopt(argc, argv, opts)) != -1;) { - if ((p = strchr(opts, c)) == NULL) { return usage(program_name); } + if ((p = strchr(opts, c)) == NULL) { return usage(argv[0]); } else { sel[p - opts] = c; } } @@ -62,7 +61,7 @@ int main(int argc, char *argv[]) { } } - if (optind == argc) { return usage(program_name); } + if (optind == argc) { return usage(argv[0]); } for (argv += optind ; *argv != NULL; ++argv) { struct stat buf; From ca6148e11f188f415677bec659e5150d1aeed14a Mon Sep 17 00:00:00 2001 From: DTB Date: Sun, 28 Jul 2024 21:06:53 -0600 Subject: [PATCH 278/343] intcmp(1): tweak comment --- src/intcmp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/intcmp.c b/src/intcmp.c index 35fecf3..36cc579 100644 --- a/src/intcmp.c +++ b/src/intcmp.c @@ -23,12 +23,12 @@ #include /* getopt(3), optind */ #include /* EX_OK, EX_USAGE */ -/* 0b00? */ /* Equal | -e | 0b001 | 1 */ -#define EQUAL 0x01 /* Greater | -g | 0b010 | 2 */ -/* 0b0?0 */ /* Greater or Equal | -ge | 0b011 | 3 */ -#define GREATER 0x02 /* Lesser | -l | 0b100 | 4 */ -/* 0b?00 */ /* Lesser or Equal | -le | 0b101 | 5 */ -#define LESSER 0x04 /* Inequal (Greater or Lesser) | -gl | 0b110 | 6 */ +#define /* 0b00? */ EQUAL 0x01 /* | -e | 0b001 | 1 */ +#define /* 0b0?0 */ GREATER 0x02 /* | -g | 0b010 | 2 */ +/* Equal | Greater 0x03 | -ge | 0b011 | 3 */ +#define /* 0b?00 */ LESSER 0x04 /* | -l | 0b100 | 4 */ +/* Equal | Lesser 0x05 | -le | 0b101 | 5 */ +/* (Inequal) Greater | Lesser 0x06 | -gl | 0b110 | 6 */ char *program_name = "intcmp"; From 361b34c50f13e32d6c2c67263253d791f665687b Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 29 Jul 2024 02:35:01 -0600 Subject: [PATCH 279/343] npc(1): improves program_name resolution --- src/npc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/npc.c b/src/npc.c index 4cc4160..2e256b0 100644 --- a/src/npc.c +++ b/src/npc.c @@ -36,9 +36,10 @@ int main(int argc, char *argv[]) { int c; char showend = 0; /* print a dollar sign before each newline */ char showtab = 0; /* prints tab characters in caret notation */ - program_name = (argv[0] == NULL ? program_name : argv[0]); if (argc > 0) { + program_name = argv[0]; + while ((c = getopt(argc, argv, "et")) != -1) { switch (c){ case 'e': showend = 1; break; From 549fa98bdb771079219df2af0ce56bb8f379f992 Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 29 Jul 2024 10:53:58 -0600 Subject: [PATCH 280/343] npc(1): interpret all retvals --- src/npc.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/npc.c b/src/npc.c index 2e256b0..b35aba4 100644 --- a/src/npc.c +++ b/src/npc.c @@ -17,17 +17,23 @@ * along with this program. If not, see https://www.gnu.org/licenses/. */ -#include /* fprintf(3), fputs(3), getc(3), putc(3), stdin, stdout, - * EOF */ -#include /* EXIT_FAILURE */ +#include /* fprintf(3), fputs(3), getc(3), perror(3), putc(3), stdin, + * stdout, EOF */ +#include /* EX_IOERR, EX_OK, EX_USAGE */ #include /* getopt(3) */ -#include /* EX_OK, EX_USAGE */ char *program_name = "npc"; +static int +ioerr(char *argv0, int err) { + perror(argv0); + + return EX_IOERR; +} + static int usage(char *argv0) { - fprintf(stderr, "Usage: %s [-et]\n", argv0); + (void)fprintf(stderr, "Usage: %s [-et]\n", argv0); return EX_USAGE; } @@ -52,16 +58,23 @@ int main(int argc, char *argv[]) { if (argc > optind) { return usage(program_name); } while ((c = getc(stdin)) != EOF) { - if ((c & 0x80) != 0) { fputs("M-", stdout); } + if ((c & 0x80) != 0 && fputs("M-", stdout) == EOF) { + return ioerr(argv[0]); + } switch (c ^ 0x80 /* 0b 1000 0000 */) { - case 0x7f: fputs("^?", stdout); break; /* delete character */ - case '\n': if (showend) { putc('$', stdout); } + case 0x7f: /* ASCII DEL (127d) */ + if(fputs("^?", stdout) == EOF) { return ioerr(argv[0]); } + break; + case '\n': + if (showend && fputc('$', stdout) == EOF) { + return ioerr(argv[0]); } + } default: if (c >= ' ' || c == '\n' || (!showtab && c == '\t')) { - putc(c, stdout); - } else { - fprintf(stdout, "^%c", c + '@'); + if (fputc(c, stdout) == EOF) { return ioerr(argv[0]); } + } else if (fprintf(stdout, "^%c", c + '@') < 0) { + return ioerr(argv[0]); } } } From 2e172d93e8735c6e35040d324dd2e898c7a13840 Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 29 Jul 2024 11:04:00 -0600 Subject: [PATCH 281/343] dj(1): interpret all retvals --- src/dj.c | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/dj.c b/src/dj.c index 8dc066a..1d12844 100644 --- a/src/dj.c +++ b/src/dj.c @@ -99,7 +99,7 @@ Io_write(struct Io *io) { io->error = errno; t = 0; } else if (t > 0) { - memmove(io->buf, &(io->buf)[t], (io->bufuse -= t)); + (void)memmove(io->buf, &(io->buf)[t], (io->bufuse -= t)); } io->bytes += t; @@ -111,7 +111,8 @@ Io_write(struct Io *io) { static int oserr(char *e, int n) { - fprintf(stderr, "%s: %s: %s\n", program_name, e, strerror(n)); + (void)fprintf(stderr, "%s: %s: %s\n", program_name, e, strerror(n)); + return EX_OSERR; } @@ -119,7 +120,7 @@ oserr(char *e, int n) { * completely read and written records. */ static void fprintio(FILE *stream, char *fmt, struct Io io[2]) { - fprintf( + return fprintf( stream, fmt, io[0].rec, @@ -129,8 +130,6 @@ fprintio(FILE *stream, char *fmt, struct Io io[2]) { io[0].bytes, io[1].bytes ); - - return; } /* Parses the string s to an integer, returning either the integer or in the @@ -248,7 +247,7 @@ int main(int argc, char *argv[]) { for (i = 0; i < (sizeof io) / (sizeof *io); ++i) { /* buffer allocation */ if ((io[i].buf = malloc(io[i].bs * (sizeof *(io[i].buf)))) == NULL) { - fprintf( + (void)fprintf( stderr, "%s: Failed to allocate %zd bytes\n", program_name, io[i].bs ); @@ -265,13 +264,13 @@ int main(int argc, char *argv[]) { /* hard seeking; t is io[1].bufuse, before Io_write subtracts from it */ for(size_t t; io[1].seek > 0; io[1].seek -= (t - io[1].bufuse)) { - memset( + (void)memset( io[1].buf, '\0', /* set buf to all nulls */ (t = io[1].bufuse = MIN(io[1].bs, io[1].seek)) /* saturate block */ ); if (Io_write(&io[1])->bufuse == t && !noerror && io[1].error == 0) { - Io_write(&io[1]); /* second chance */ + (void)Io_write(&io[1]); /* second chance */ } if (io[1].error != 0) { return oserr(io[1].fn, io[1].error); } @@ -282,7 +281,7 @@ int main(int argc, char *argv[]) { io[1].bufuse = 0; if (io[1].seek > 0) { /* hard seeking failed */ - fprintio(stderr, fmt, io); + (void)fprintio(stderr, fmt, io); return oserr(io[1].fn, errno); } @@ -303,7 +302,7 @@ int main(int argc, char *argv[]) { t = io[0].bufuse; if (Io_read(&io[0])->bufuse == t && !noerror && io[0].error == 0) { - Io_read(&io[0]); /* second chance */ + (void)Io_read(&io[0]); /* second chance */ } assert(io[0].bufuse >= t); @@ -311,14 +310,14 @@ int main(int argc, char *argv[]) { if (io[0].bufuse == t) { break; } /* that's all she wrote */ if (/* t < io[0].bufuse && */ io[0].bufuse < io[0].bs) { - fprintf(stderr, "%s: Partial read:\n\t", program_name); - fprintio(stderr, fmt, io); + (void)fprintf(stderr, "%s: Partial read:\n\t", program_name); + (void)fprintio(stderr, fmt, io); if (!noerror) { count = 1; } if (align >= 0) { /* fill the rest of the ibuf with padding */ - memset( + (void)memset( &(io[0].buf)[io[0].bufuse], align, io[0].bs - io[0].bufuse @@ -342,25 +341,25 @@ int main(int argc, char *argv[]) { if (io[0].bs <= io[1].bs) { int n; - memcpy( /* saturate obuf */ + (void)memcpy( /* saturate obuf */ io[1].buf, io[0].buf, (io[1].bufuse = (n = MIN(io[0].bufuse, io[1].bs))) ); /* permute the copied units out of ibuf */ - memmove(io[0].buf, &(io[0].buf)[n], (io[0].bufuse -= n)); + (void)memmove(io[0].buf, &(io[0].buf)[n], (io[0].bufuse -= n)); } else /* if(io[0].bs > io[1].bs) */ { int n; /* drain what we can from ibuf */ - memcpy( + (void)memcpy( &(io[1].buf)[io[1].bufuse], io[0].buf, (n = MIN(io[0].bufuse, io[1].bs - io[1].bufuse)) ); io[1].bufuse += n; /* permute out the copied units */ - memmove(io[0].buf, &(io[0].buf)[n], io[0].bs - n); + (void)memmove(io[0].buf, &(io[0].buf)[n], io[0].bs - n); io[0].bufuse -= n; if(io[0].bs + io[1].bufuse <= io[1].bs && count != 1) { @@ -375,7 +374,7 @@ int main(int argc, char *argv[]) { if (Io_write(&io[1])->bufuse == t && !noerror && io[1].error == 0) { - Io_write(&io[1]); /* second chance */ + (void)Io_write(&io[1]); /* second chance */ } assert(io[1].error == 0 || io[1].bufuse == t); @@ -392,15 +391,15 @@ int main(int argc, char *argv[]) { } if (0 < io[1].bufuse /* && io[1].bufuse < t */) { - fprintf(stderr, "%s: Partial write:\n\t", program_name); - fprintio(stderr, fmt, io); + (void)fprintf(stderr, "%s: Partial write:\n\t", program_name); + (void)fprintio(stderr, fmt, io); if(!noerror) { count = 1; } } } } - fprintio(stderr, fmt, io); + (void)fprintio(stderr, fmt, io); for (i = 0; i < (sizeof io) / (sizeof *io); ++i) { if (io[i].error) { return oserr(io[i].fn, io[i].error); } From 162c6411b3a8313b83e6c032111d8667aada14ba Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 29 Jul 2024 11:08:30 -0600 Subject: [PATCH 282/343] mm(1): remove terminate macro --- src/mm.c | 43 ++++++++----------------------------------- 1 file changed, 8 insertions(+), 35 deletions(-) diff --git a/src/mm.c b/src/mm.c index d148446..a9c45b3 100644 --- a/src/mm.c +++ b/src/mm.c @@ -88,25 +88,6 @@ oserr(char *s, char *r) { return EX_OSERR; } -/* Hijacks i and j from main and destructs the files[2] struct used by main by - * closing its files and freeing its files and names arrays, returning retval - * from main. */ -#define terminate \ - for (i = 0; i < 2; ++i) { \ - for (j = 0; j < files[i].s; ++j) { \ - if ( \ - files[i].files[j] != stdin \ - && files[i].files[j] != stdout \ - && files[i].files[j] != stderr \ - ) { \ - fclose(files[i].files[j]); \ - } \ - } \ - free(files[i].files); \ - free(files[i].names); \ - } \ - return retval - static int usage(char *argv0) { (void)fprintf( @@ -163,8 +144,7 @@ int main(int argc, char *argv[]) { break; } - retval = oserr(program_name, "-e"); - terminate; + return oserr(program_name, "-e"); case 'i': if ( (strcmp(optarg, "-") == 0 @@ -172,8 +152,7 @@ int main(int argc, char *argv[]) { || Files_open(&files[0], optarg) != NULL ) { break; } - retval = oserr(program_name, optarg); - terminate; + return oserr(program_name, optarg); case 'o': if ( (strcmp(optarg, "-") == 0 @@ -190,27 +169,21 @@ int main(int argc, char *argv[]) { } } - retval = oserr(program_name, optarg); - terminate; + return oserr(program_name, optarg); case 'n': if (signal(SIGINT, SIG_IGN) != SIG_ERR) { break; } - retval = oserr(program_name, "-n"); - terminate; + return oserr(program_name, "-n"); case 'u': k = 1; break; default: - retval = usage(program_name); - terminate; + return usage(program_name); } } } - if (optind != argc) { - retval = usage(program_name); - terminate; - } + if (optind != argc) { return usage(program_name); } files[0].s += files[0].s == 0; files[1].s += files[1].s == 0; @@ -258,11 +231,11 @@ int main(int argc, char *argv[]) { files[1].names[k] = files[1].names[k+1]; } - if(--files[1].s == 0) { terminate; } + if(--files[1].s == 0) { return retval; } } } } } - terminate; + return retval; } From 5545846c92f310bbb74e70c184f2b467e9fea701 Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 29 Jul 2024 11:10:17 -0600 Subject: [PATCH 283/343] dj(1): fix fprintio signature --- src/dj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dj.c b/src/dj.c index 1d12844..cb8b1db 100644 --- a/src/dj.c +++ b/src/dj.c @@ -118,7 +118,7 @@ oserr(char *e, int n) { /* Prints statistics regarding the use of dj, particularly partially and * completely read and written records. */ -static void +static int fprintio(FILE *stream, char *fmt, struct Io io[2]) { return fprintf( stream, From 7b930363bf7bfc0ea429dbe80a5697b830b1fab7 Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 29 Jul 2024 11:12:02 -0600 Subject: [PATCH 284/343] npc(1): fix syntax errors --- src/npc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/npc.c b/src/npc.c index b35aba4..7ef760a 100644 --- a/src/npc.c +++ b/src/npc.c @@ -25,7 +25,7 @@ char *program_name = "npc"; static int -ioerr(char *argv0, int err) { +ioerr(char *argv0) { perror(argv0); return EX_IOERR; @@ -68,7 +68,7 @@ int main(int argc, char *argv[]) { break; case '\n': if (showend && fputc('$', stdout) == EOF) { - return ioerr(argv[0]); } + return ioerr(argv[0]); } default: if (c >= ' ' || c == '\n' || (!showtab && c == '\t')) { From c554b96722634d09cf8441fdac065efa4e1971c6 Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 29 Jul 2024 11:13:58 -0600 Subject: [PATCH 285/343] swab(1): fix type errors --- src/swab.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/swab.rs b/src/swab.rs index 771d352..dd63587 100644 --- a/src/swab.rs +++ b/src/swab.rs @@ -75,20 +75,20 @@ fn main() -> ExitCode { if let Err(e) = output.write(&right) .and_then(|_| output.write(&left)) { err(&argv[0], e); - break EX_IOERR // write error + break ExitCode::from(EX_IOERR as u8) // write error } }, Ok(v) => { // partial read; partially write if let Err(e) = output.write(&buf[..v]) { err(&argv[0], e); - break EX_IOERR // write error + break ExitCode::from(EX_IOERR as u8) // write error } }, Err(e) if e.kind() == ErrorKind::Interrupted && force => continue, Err(e) => { err(&argv[0], e); - break EX_IOERR // read error (or signal) + break ExitCode::from(EX_IOERR as u8) // read error (or signal) } } } From a7b27f0d6ad57fa65e71306a44d7f76cbe795de5 Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 29 Jul 2024 11:14:48 -0600 Subject: [PATCH 286/343] strcmp(1): interpret all retvals --- src/strcmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strcmp.c b/src/strcmp.c index 16ec3ca..7f5f0ed 100644 --- a/src/strcmp.c +++ b/src/strcmp.c @@ -26,7 +26,7 @@ int main(int argc, char *argv[]) { int i; if (argc < 3) { - fprintf( + (void)fprintf( stderr, "Usage: %s string string...\n", argv[0] == NULL ? program_name : argv[0] From 7e347bebdf124fa9d10c65944aacef272b3f8d2d Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 29 Jul 2024 11:30:41 -0600 Subject: [PATCH 287/343] mm(1): interpret retvals --- src/mm.c | 83 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/src/mm.c b/src/mm.c index a9c45b3..56b8c95 100644 --- a/src/mm.c +++ b/src/mm.c @@ -82,8 +82,7 @@ Files_append(struct Files *files, FILE *file, char *name) { * appropriate for an OS error. */ static int oserr(char *s, char *r) { - - fprintf(stderr, "%s: %s: %s\n", s, r, strerror(errno)); + (void)fprintf(stderr, "%s: %s: %s\n", s, r, strerror(errno)); return EX_OSERR; } @@ -100,11 +99,7 @@ usage(char *argv0) { } int main(int argc, char *argv[]) { - int c; struct Files files[2]; /* {read, write} */ - size_t i; - size_t j; - size_t k; /* loop index but also unbuffer status */ int retval; /* Initializes the files structs with their default values, standard @@ -112,39 +107,41 @@ int main(int argc, char *argv[]) { * these initial values will be overwritten, so to, say, use mm(1) * equivalently to tee(1p), -o - will need to be specified before * additional files to ensure standard output is still written. */ - for (i = 0; i < 2; ++i) { + for (size_t i = 0; i < 2; ++i) { files[i].a = 0; files[i].s = 0; files[i].mode = fmode[i]; files[i].files = NULL; files[i].names = NULL; - Files_append( - &files[i], - i == 0 ? stdin : stdout, - i == 0 ? stdin_name : stdout_name - ); + if (Files_append( + &files[i], + i == 0 ? stdin : stdout, + i == 0 ? stdin_name : stdout_name + ) == NULL) { + return oserr(program_name, i == 0 ? stdin_name : stdout_name); + } files[i].s = 0; } - k = 0; - if (argc > 0) { + int c; + char unbuffered = 0; + program_name = argv[0]; while ((c = getopt(argc, argv, "aehi:no:u")) != -1) { - switch (c){ + switch (c) { case 'a': /* "rb+" -> "ab" */ files[1].mode[0] = 'a'; files[1].mode[2] = '\0'; break; case 'e': - if (Files_append(&files[1], stderr, stderr_name) != NULL) { - break; + if (Files_append(&files[1], stderr, stderr_name) == NULL) { + return oserr(program_name, stderr_name); } - - return oserr(program_name, "-e"); + break; case 'i': if ( (strcmp(optarg, "-") == 0 @@ -171,16 +168,28 @@ int main(int argc, char *argv[]) { return oserr(program_name, optarg); case 'n': - if (signal(SIGINT, SIG_IGN) != SIG_ERR) { break; } + if (signal(SIGINT, SIG_IGN) == SIG_ERR) { + return oserr(program_name, "-n"); + } - return oserr(program_name, "-n"); - case 'u': - k = 1; break; - default: - return usage(program_name); + case 'u': unbuffered = 1; break; + default: return usage(program_name); } } + + if (unbuffered) { /* Unbuffer files. */ + for ( + size_t i = 0; + i < files[0].s; + setvbuf(files[0].files[i++], NULL, _IONBF, 0) + ); + for ( + size_t i = 0; + i < files[1].s; + setvbuf(files[1].files[i++], NULL, _IONBF, 0) + ); + } } if (optind != argc) { return usage(program_name); } @@ -188,26 +197,18 @@ int main(int argc, char *argv[]) { files[0].s += files[0].s == 0; files[1].s += files[1].s == 0; - /* Unbuffer files. */ - if (k) { - for ( - i = 0; i < files[0].s; setvbuf(files[0].files[i++], NULL, _IONBF, 0) - ); - for ( - i = 0; i < files[1].s; setvbuf(files[1].files[i++], NULL, _IONBF, 0) - ); - } retval = EX_OK; /* Actual program loop. */ - for (i = 0; i < files[0].s; ++i) { /* iterate ins */ + for (size_t i = 0; i < files[0].s; ++i) { /* iterate ins */ + int c; + while ((c = getc(files[0].files[i])) != EOF) { /* iterate chars */ - for (j = 0; j < files[1].s; ++j) { /* iterate outs */ - if (putc(c, files[1].files[j]) == EOF) { - /* notebook's full */ + for (size_t j = 0; j < files[1].s; ++j) { /* iterate outs */ + if (putc(c, files[1].files[j]) == EOF) { /* notebook's full */ retval = EX_IOERR; - fprintf( + (void)fprintf( stderr, "%s: %s: %s\n", program_name, @@ -216,7 +217,7 @@ int main(int argc, char *argv[]) { ); if (fclose(files[1].files[j]) == EOF) { - fprintf( + (void)fprintf( stderr, "%s: %s: %s\n", program_name, @@ -226,7 +227,7 @@ int main(int argc, char *argv[]) { } /* massage out the tense muscle */ - for(k = j--; k < files[1].s - 1; ++k){ + for(size_t k = j--; k < files[1].s - 1; ++k){ files[1].files[k] = files[1].files[k+1]; files[1].names[k] = files[1].names[k+1]; } From 8d23c7fbac378570ee3b24afd3340517e547e342 Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 29 Jul 2024 13:43:52 -0600 Subject: [PATCH 288/343] dj(1): better ASV formatting and comments --- src/dj.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/dj.c b/src/dj.c index cb8b1db..17f406c 100644 --- a/src/dj.c +++ b/src/dj.c @@ -49,10 +49,6 @@ struct Io { int fl; /* file opening flags */ }; -/* To be assigned to main:fmt and used with printio(). */ -static char *fmt_asv = "%d\037%d\036%d\037%d\035%d\036%d\034"; -static char *fmt_human = "%d+%d > %d+%d; %d > %d\n"; - static char *stdin_name = ""; static char *stdout_name = ""; @@ -132,6 +128,18 @@ fprintio(FILE *stream, char *fmt, struct Io io[2]) { ); } +/* To be assigned to main:fmt and used with printio(). */ +static char *fmt_asv = + "%d" /* io[0].rec */ "\037" /* ASCII US */ + "%d" /* io[0].prec */ "\036" /* ASCII RS */ + "%d" /* io[1].rec */ "\037" /* ASCII US */ + "%d" /* io[1].prec */ "\035" /* ASCII GS */ + "%d" /* io[0].bytes */ "\036" /* ASCII RS */ + "%d" /* io[1].bytes */ "\034" /* ASCII FS */ + "\n" +; +static char *fmt_human = "%d+%d > %d+%d; %d > %d\n"; + /* Parses the string s to an integer, returning either the integer or in the * case of an error a negative integer. This is used for argument parsing * (e.g. -B [int]) in dj and no negative integer would be valid anyway. */ From 6c2b7b68fd503e75f86129b0ab238cad7e148695 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 29 Jul 2024 14:38:33 -0600 Subject: [PATCH 289/343] dj(1): more better comments --- src/dj.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/dj.c b/src/dj.c index 17f406c..d6f5fde 100644 --- a/src/dj.c +++ b/src/dj.c @@ -20,6 +20,7 @@ #include /* assert(3) */ #include /* errno */ #include /* open(2) */ +#include /* bool */ #include /* fprintf(3), stderr */ #include /* malloc(3), strtol(3), size_t */ #include /* memcpy(3), memmove(3), memset(3) */ @@ -28,8 +29,6 @@ * optarg, optind, STDIN_FILENO, STDOUT_FILENO */ #include /* S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR */ -extern int errno; - char *program_name = "dj"; /* dj uses two structures that respectively correspond to the reading and @@ -62,6 +61,7 @@ static int write_flags = O_WRONLY | O_CREAT; /* Macro to check if fd is stdin or stdout */ #define fdisstd(fd) ((fd) == STDIN_FILENO || (fd) == STDOUT_FILENO) +/* Completes one Io block read */ static struct Io * Io_read(struct Io *io) { int t; @@ -84,6 +84,7 @@ Io_read(struct Io *io) { return io; } +/* Completes one Io block write */ static struct Io * Io_write(struct Io *io) { int t; @@ -168,16 +169,16 @@ usage(char *argv0) { int main(int argc, char *argv[]) { int align; /* low 8b used, negative if no alignment is being done */ int count; /* -1 if dj(1) runs until no more reads are possible */ - char *fmt; /* == fmt_asv (default) or fmt_human (-H) */ - size_t i; /* side of io being modified */ - char noerror; /* 0=exits (default) 1=retries on partial reads or writes */ + char *fmt; /* set to fmt_asv (default) or fmt_human (-H) */ + size_t i; /* side of io (in or out) being modified */ + bool retry; /* false if exits on partial reads or writes */ struct Io io[2 /* { in, out } */]; /* Set defaults. */ align = -1; count = -1; fmt = fmt_asv; - noerror = 0; + retry = 0; for (i = 0; i < (sizeof io) / (sizeof *io); ++i) { io[i].bs = 1024 /* 1 KiB */; /* GNU dd(1) default; POSIX says 512B */ io[i].bufuse = 0; @@ -218,8 +219,9 @@ int main(int argc, char *argv[]) { } } - return oserr(optarg, errno); /* break; */ - case 'n': noerror = 1; break; /* retry failed reads once */ + return oserr(optarg, errno); + /* UNREACHABLE */ + case 'n': retry = 1; break; /* retry failed reads once */ case 'H': fmt = fmt_human; break; /* human-readable output */ case 'a': /* input buffer padding */ if (optarg[0] == '\0' || optarg[1] == '\0') { @@ -233,12 +235,12 @@ int main(int argc, char *argv[]) { if (c == 'c' && (count = parse(optarg)) >= 0) { break; } i = (c >= 'A' && c <= 'Z'); - c |= 0x20; /* 0b 0010 0000 (ASCII make lowercase) */ + c |= 0x20; /* 0b 0010 0000 (ASCII) make lowercase */ - if ( + if ( /* if -b or -s is parsed out correctly */ (c == 'b' && (io[i].bs = parse(optarg)) > 0) || (c == 's' && (io[i].seek = parse(optarg)) >= 0) - ) { break; } + ) { break; } /* don't error */ /* FALLTHROUGH */ default: @@ -277,7 +279,7 @@ int main(int argc, char *argv[]) { (t = io[1].bufuse = MIN(io[1].bs, io[1].seek)) /* saturate block */ ); - if (Io_write(&io[1])->bufuse == t && !noerror && io[1].error == 0) { + if (Io_write(&io[1])->bufuse == t && !retry && io[1].error == 0) { (void)Io_write(&io[1]); /* second chance */ } @@ -286,7 +288,7 @@ int main(int argc, char *argv[]) { if (io[1].bufuse == t) { break; } /* all writes failed! */ } - io[1].bufuse = 0; + io[1].bufuse = 0; /* reset after hard seek */ if (io[1].seek > 0) { /* hard seeking failed */ (void)fprintio(stderr, fmt, io); @@ -309,7 +311,7 @@ int main(int argc, char *argv[]) { } t = io[0].bufuse; - if (Io_read(&io[0])->bufuse == t && !noerror && io[0].error == 0) { + if (Io_read(&io[0])->bufuse == t && !retry && io[0].error == 0) { (void)Io_read(&io[0]); /* second chance */ } @@ -321,7 +323,7 @@ int main(int argc, char *argv[]) { (void)fprintf(stderr, "%s: Partial read:\n\t", program_name); (void)fprintio(stderr, fmt, io); - if (!noerror) { count = 1; } + if (!retry) { count = 1; } if (align >= 0) { /* fill the rest of the ibuf with padding */ @@ -380,7 +382,7 @@ int main(int argc, char *argv[]) { t = io[1].bufuse; if (Io_write(&io[1])->bufuse == t - && !noerror + && !retry && io[1].error == 0) { (void)Io_write(&io[1]); /* second chance */ } @@ -402,7 +404,7 @@ int main(int argc, char *argv[]) { (void)fprintf(stderr, "%s: Partial write:\n\t", program_name); (void)fprintio(stderr, fmt, io); - if(!noerror) { count = 1; } + if(!retry) { count = 1; } } } } From fd13a7f1899922e60a25a8504b39c50d6c2e78f8 Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 29 Jul 2024 14:43:21 -0600 Subject: [PATCH 290/343] swab(1): fix imports to be consistent --- src/swab.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/swab.rs b/src/swab.rs index dd63587..f4abc9d 100644 --- a/src/swab.rs +++ b/src/swab.rs @@ -24,12 +24,11 @@ use std::{ }; extern crate getopt; -use getopt::GetOpt; - extern crate sysexits; -use sysexits::{ EX_IOERR, EX_OK, EX_USAGE }; - extern crate strerror; + +use getopt::GetOpt; +use sysexits::{ EX_IOERR, EX_OK, EX_USAGE }; use strerror::StrError; fn err(s: &str, e: Error) { eprintln!("{}: {}", s, e.strerror()); } From 6bbccb3776da30be99b97753e1edbfe6939dac7c Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 29 Jul 2024 21:14:45 -0600 Subject: [PATCH 291/343] fop(1): fix minor optind bug, add some comments --- src/fop.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/fop.rs b/src/fop.rs index bbca85e..9f547b1 100644 --- a/src/fop.rs +++ b/src/fop.rs @@ -33,7 +33,7 @@ use sysexits::{ EX_DATAERR, EX_IOERR, EX_UNAVAILABLE, EX_USAGE }; fn main() { let argv = args().collect::>(); let mut d = '\u{1E}'.to_string(); /* ASCII record separator */ - let mut optind = 0; + let mut optind = 1; let usage = format!( "Usage: {} [-d delimiter] index command [args...]", @@ -54,6 +54,12 @@ fn main() { }; } + /* parse the specified index as a number we can use */ + let index = argv[optind].parse::().unwrap_or_else(|e| { + eprintln!("{}: {}: {}", argv[0], argv[1], e); + exit(EX_DATAERR); + }); + /* index of the argv[0] for the operator command */ let command_arg = optind as usize + 1; @@ -63,12 +69,7 @@ fn main() { exit(EX_USAGE); }); - /* parse the specified index as a number we can use */ - let index = argv[optind].parse::().unwrap_or_else(|e| { - eprintln!("{}: {}: {}", argv[0], argv[1], e); - exit(EX_DATAERR); - }); - + /* read entire standard input into memory */ let mut buf = String::new(); if let Err(e) = stdin().read_to_string(&mut buf) { eprintln!("{}: {}", argv[0], e.strerror()); From 4aeba9d13f784c558f688887292bb0945d5d2959 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 29 Jul 2024 23:04:08 -0600 Subject: [PATCH 292/343] Makefile: uses dirname(1) to get normalized prefix, adds libraries to RUSTFLAGS, fixes typo --- Makefile | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 94d0b78..418b564 100644 --- a/Makefile +++ b/Makefile @@ -17,8 +17,7 @@ DESTDIR ?= dist PREFIX ?= /usr/local # normalized prefix -PREFIX_N != (test -d $(PREFIX) && [ '-' != $(PREFIX) ] \ - && CDPATH= cd -P -- $(PREFIX) && pwd -P) +PREFIX_N != dirname $(PREFIX)/. MANDIR != [ $(PREFIX_N) = / ] && printf '/usr/share/man\n' \ || printf '/share/man\n' SYSEXITS != printf '\043include \n' | cpp -M - | tr ' ' '\n' \ @@ -26,7 +25,7 @@ SYSEXITS != printf '\043include \n' | cpp -M - | tr ' ' '\n' \ CC ?= cc RUSTC ?= rustc -RUSTLIBS = --extern getopt=build/o/libgetopt.rlib \ +RUSTFLAGS += --extern getopt=build/o/libgetopt.rlib \ --extern sysexits=build/o/libsysexits.rlib \ --extern strerror=build/o/libstrerror.rlib CFLAGS += -I$(SYSEXITS) @@ -120,7 +119,7 @@ build/bin/mm: src/mm.rs build rustlibs .PHONY: npc npc: build/bin/npc build/bin/npc: src/npc.c build - $(CC) $(CFLAGAS) -o $@ src/npc.c + $(CC) $(CFLAGS) -o $@ src/npc.c .PHONY: rpn rpn: build/bin/rpn From 18aac061131eb4d13be497c97330865898f6cd68 Mon Sep 17 00:00:00 2001 From: emma Date: Thu, 1 Aug 2024 00:06:39 -0600 Subject: [PATCH 293/343] Makefile: changes test usage --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 418b564..fd15366 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ PREFIX ?= /usr/local # normalized prefix PREFIX_N != dirname $(PREFIX)/. -MANDIR != [ $(PREFIX_N) = / ] && printf '/usr/share/man\n' \ +MANDIR != test $(PREFIX_N) -eq / && printf '/usr/share/man\n' \ || printf '/share/man\n' SYSEXITS != printf '\043include \n' | cpp -M - | tr ' ' '\n' \ | sed -n 's/sysexits\.h//p' || printf 'include\n' From 0b0bd9bd76873ac7418107929d823eea306bb750 Mon Sep 17 00:00:00 2001 From: emma Date: Thu, 1 Aug 2024 13:12:54 -0600 Subject: [PATCH 294/343] Makefile: fixes test and removes references to the RUSTLIBS variable --- Makefile | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index fd15366..7b19a86 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ PREFIX ?= /usr/local # normalized prefix PREFIX_N != dirname $(PREFIX)/. -MANDIR != test $(PREFIX_N) -eq / && printf '/usr/share/man\n' \ +MANDIR != test $(PREFIX_N) = / && printf '/usr/share/man\n' \ || printf '/share/man\n' SYSEXITS != printf '\043include \n' | cpp -M - | tr ' ' '\n' \ | sed -n 's/sysexits\.h//p' || printf 'include\n' @@ -99,22 +99,22 @@ build/bin/false: src/false.c build .PHONY: fop fop: build/bin/fop build/bin/fop: src/fop.rs build rustlibs - $(RUSTC) $(RUSTFLAGS) $(RUSTLIBS) -o $@ src/fop.rs + $(RUSTC) $(RUSTFLAGS) -o $@ src/fop.rs .PHONY: hru hru: build/bin/hru build/bin/hru: src/hru.rs build rustlibs - $(RUSTC) $(RUSTFLAGS) $(RUSTLIBS) -o $@ src/hru.rs + $(RUSTC) $(RUSTFLAGS) -o $@ src/hru.rs .PHONY: intcmp intcmp: build/bin/intcmp build/bin/intcmp: src/intcmp.rs build rustlibs - $(RUSTC) $(RUSTFLAGS) $(RUSTLIBS) -o $@ src/intcmp.rs + $(RUSTC) $(RUSTFLAGS) -o $@ src/intcmp.rs .PHONY: mm mm: build/bin/mm build/bin/mm: src/mm.rs build rustlibs - $(RUSTC) $(RUSTFLAGS) $(RUSTLIBS) -o $@ src/mm.rs + $(RUSTC) $(RUSTFLAGS) -o $@ src/mm.rs .PHONY: npc npc: build/bin/npc @@ -124,7 +124,7 @@ build/bin/npc: src/npc.c build .PHONY: rpn rpn: build/bin/rpn build/bin/rpn: src/rpn.rs build rustlibs - $(RUSTC) $(RUSTFLAGS) $(RUSTLIBS) -o $@ src/rpn.rs + $(RUSTC) $(RUSTFLAGS) -o $@ src/rpn.rs .PHONY: scrut scrut: build/bin/scrut @@ -144,7 +144,7 @@ build/bin/strcmp: src/strcmp.c build .PHONY: swab swab: build/bin/swab build/bin/swab: src/swab.rs build rustlibs - $(RUSTC) $(RUSTFLAGS) $(RUSTLIBS) -o $@ src/swab.rs + $(RUSTC) $(RUSTFLAGS) -o $@ src/swab.rs .PHONY: true true: build/bin/true From ce8a0a5be38957ec76d75c64b34b51ae8b877217 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 2 Aug 2024 17:29:30 -0600 Subject: [PATCH 295/343] tests: converted to Makefiles --- Makefile | 11 ++++++-- tests/bonsai/dj.mk | 42 +++++++++++++++++++++++++++++ tests/bonsai/dj.sh | 29 -------------------- tests/bonsai/{false.sh => false.mk} | 13 ++++++--- tests/bonsai/fop.mk | 31 +++++++++++++++++++++ tests/bonsai/fop.sh | 21 --------------- tests/bonsai/hru.mk | 35 ++++++++++++++++++++++++ tests/bonsai/hru.sh | 26 ------------------ tests/bonsai/intcmp.mk | 36 +++++++++++++++++++++++++ tests/bonsai/intcmp.sh | 25 ----------------- tests/bonsai/mm.mk | 27 +++++++++++++++++++ tests/bonsai/{npc.sh => npc.mk} | 20 +++++++++----- tests/bonsai/strcmp.mk | 31 +++++++++++++++++++++ tests/bonsai/strcmp.sh | 16 ----------- tests/bonsai/test_env | 5 ---- tests/bonsai/{true.sh => true.mk} | 12 ++++++--- tests/locales/en_US.UTF-8 | 4 --- tests/locales/tok | 5 ---- tests/test.sh | 38 -------------------------- tests/{bonsai/mm.sh => tests.mk} | 16 +++++------ 20 files changed, 249 insertions(+), 194 deletions(-) create mode 100755 tests/bonsai/dj.mk delete mode 100755 tests/bonsai/dj.sh rename tests/bonsai/{false.sh => false.mk} (68%) create mode 100755 tests/bonsai/fop.mk delete mode 100755 tests/bonsai/fop.sh create mode 100755 tests/bonsai/hru.mk delete mode 100755 tests/bonsai/hru.sh create mode 100755 tests/bonsai/intcmp.mk delete mode 100755 tests/bonsai/intcmp.sh create mode 100755 tests/bonsai/mm.mk rename tests/bonsai/{npc.sh => npc.mk} (70%) create mode 100755 tests/bonsai/strcmp.mk delete mode 100755 tests/bonsai/strcmp.sh delete mode 100644 tests/bonsai/test_env rename tests/bonsai/{true.sh => true.mk} (71%) delete mode 100644 tests/locales/en_US.UTF-8 delete mode 100644 tests/locales/tok delete mode 100755 tests/test.sh rename tests/{bonsai/mm.sh => tests.mk} (51%) mode change 100755 => 100644 diff --git a/Makefile b/Makefile index 6e554a4..6c6d555 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,13 @@ RUSTLIBS = --extern getopt=build/o/libgetopt.rlib \ --extern strerror=build/o/libstrerror.rlib CFLAGS += -I$(SYSEXITS) +# testing requires the absolute path to the bin directory set +BIN = build/bin +include tests/tests.mk + +.PHONY: default +default: all test + .PHONY: all all: dj false fop hru intcmp mm npc rpn scrut str strcmp swab true @@ -53,8 +60,8 @@ install: dist cp -r $(DESTDIR)/* / .PHONY: test -test: all build /tmp/getopt - tests/test.sh +test: all $(TESTS) /tmp/getopt + @echo $(TESTS) /tmp/getopt /tmp/getopt: src/libgetopt.rs diff --git a/tests/bonsai/dj.mk b/tests/bonsai/dj.mk new file mode 100755 index 0000000..9c27927 --- /dev/null +++ b/tests/bonsai/dj.mk @@ -0,0 +1,42 @@ +# Copyright (c) 2024 DTB +# Copyright (c) 2024 Emma Tebibyte +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +.PRAGMA: command_comment + +/dev/full: +/dev/null: + +.PHONY: dj_tests +dj_tests: dj_full dj_help dj_null # dj_skip_stdin + +.PHONY: dj_full +# Linux has a /dev/full pseudodevice useful for testing errors. +dj_full: $(BIN)/dj /dev/full + case "$$(uname)" in \ + Linux) \ + $(BIN)/dj -Hi /dev/zero -o /dev/full 2>&1 \ + | xargs -I out test '1+0 > 0+0; 1024 > 0' = out \ + ;; \ + esac + +.PHONY: dj_help +dj_help: $(BIN)/dj + ! $(BIN)/dj -h + +.PHONY: dj_null +# Read nothing from /dev/null, write nothing to /dev/null. +dj_null: $(BIN)/dj /dev/null + $(BIN)/dj -Hi /dev/null -o /dev/null 2>&1 \ + | xargs -I out test '0+0 > 0+0; 0 > 0' = out + +# .PHONY: dj_skip_stdin +# dj_skip_stdin: $(BIN)/dj + # Test skipping stdin. + #dd count=1 bs=1024 /dev/null \ + # | $(BIN)/dj -H -s 24 -o /dev/null 2>&1 \ + # | xargs -I out test '1+0 > 1+0; 1024 > 1000' = out diff --git a/tests/bonsai/dj.sh b/tests/bonsai/dj.sh deleted file mode 100755 index 9919d60..0000000 --- a/tests/bonsai/dj.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/sh -# Copyright (c) 2024 DTB -# Copyright (c) 2024 Emma Tebibyte -# SPDX-License-Identifier: FSFAP -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice and this -# notice are preserved. This file is offered as-is, without any warranty. - -. tests/bonsai/test_env - -! dj -h - -# Linux has a /dev/full pseudodevice useful for testing errors. -case "$(uname)" in -Linux) - dj -Hi /dev/zero -o /dev/full 2>&1 \ - | xargs -I out "$BIN"/strcmp '1+0 > 0+0; 1024 > 0' out - ;; -esac - -# Read nothing from /dev/null, write nothing to /dev/null. -dj -Hi /dev/null -o /dev/null 2>&1 \ - | xargs -I out "$BIN"/strcmp '0+0 > 0+0; 0 > 0' out - -# Test skipping stdin. -#dd count=1 bs=1024 /dev/null \ -# | dj -H -s 24 -o /dev/null 2>&1 \ -# | xargs -I out "$BIN"/strcmp '1+0 > 1+0; 1024 > 1000' out diff --git a/tests/bonsai/false.sh b/tests/bonsai/false.mk similarity index 68% rename from tests/bonsai/false.sh rename to tests/bonsai/false.mk index 3ad0e94..e3d19ae 100755 --- a/tests/bonsai/false.sh +++ b/tests/bonsai/false.mk @@ -1,4 +1,3 @@ -#!/bin/sh # Copyright (c) 2024 DTB # Copyright (c) 2024 Emma Tebibyte # SPDX-License-Identifier: FSFAP @@ -7,7 +6,13 @@ # permitted in any medium without royalty provided the copyright notice and this # notice are preserved. This file is offered as-is, without any warranty. -. tests/bonsai/test_env +.PHONY: false_tests +false_tests: false_test false_help -! false -! false -h +.PHONY: false +false_test: $(BIN)/false + ! $(BIN)/false + +.PHONY: false_help +false_help: $(BIN)/false + ! $(BIN)/false -h diff --git a/tests/bonsai/fop.mk b/tests/bonsai/fop.mk new file mode 100755 index 0000000..a22ca46 --- /dev/null +++ b/tests/bonsai/fop.mk @@ -0,0 +1,31 @@ +# Copyright (c) 2024 Emma Tebibyte +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +.PHONY: fop_tests +fop_tests: fop_help fop_functionality fop_delimiter fop_fail + +.PHONY: fop_delimiter +fop_delimiter: $(BIN)/fop + test "$$(printf 'test0 test1 test2\n' | $(BIN)/fop -d' ' 2 sed 's/2/4/g')" \ + = 'test0 test1 test4' + test "$$(printf 'meowsetwoofsetribbit\n' \ + | $(BIN)/fop -d 'set' 1 sed 's/woof/meow/g')" = 'meowsetmeowsetribbit' + +.PHONY: fop_fail +fop_fail: $(BIN)/fop + ! printf 'test\n' | $(BIN)/fop 1 cat + ! printf 'test\n' | $(BIN)/fop 'test' cat + ! printf 'test\n' | $(BIN)/fop -d'test' cat + +.PHONY: fop_functionality +fop_functionality: $(BIN)/fop + test "$$(printf 'test0␞test1␞test2\n' | $(BIN)/fop 1 sed 's/1/4/g')" \ + = 'test0␞test4␞test2' + +.PHONY: fop_help +fop_help: $(BIN)/fop + ! $(BIN)/fop -h diff --git a/tests/bonsai/fop.sh b/tests/bonsai/fop.sh deleted file mode 100755 index 2cb2533..0000000 --- a/tests/bonsai/fop.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh -# Copyright (c) 2024 Emma Tebibyte -# SPDX-License-Identifier: FSFAP -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice and this -# notice are preserved. This file is offered as-is, without any warranty. - -. tests/bonsai/test_env - -! fop -h - -"$BIN/strcmp" "$(printf 'test0␞test1␞test2\n' | fop 1 sed 's/1/4/g')" \ - 'test0␞test4␞test2' - -"$BIN/strcmp" "$(printf 'test0 test1 test2\n' | fop -d' ' 2 sed 's/2/4/g')" \ - 'test0 test1 test4' - -! printf 'test\n' | fop 1 cat -! printf 'test\n' | fop 'test' cat -! printf 'test\n' | fop -d'test' cat diff --git a/tests/bonsai/hru.mk b/tests/bonsai/hru.mk new file mode 100755 index 0000000..9d200e5 --- /dev/null +++ b/tests/bonsai/hru.mk @@ -0,0 +1,35 @@ +# Copyright (c) 2024 Emma Tebibyte +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +NAME = hru +TARGET = $(NAME)_tests +BINARY = $(BIN)/$(NAME) + +.PHONY: hru_tests +hru_tests: $(BIN)/hru + +.PHONY: hru_functionality +hru_functionality: $(BIN)/hru + test "$(printf '1234\n' | $(BIN)/hru)" = '1.2 kB' + test "$(printf '0\n' | $(BIN)/hru)" = '0 B' + +.PHONY: $(NAME_help) +hru_help: $(BIN)/hru + ! $(BIN)/hru -h + +.PHONY: hru_negative +hru_negative: $(BIN)/hru + ! printf '%s\n' '-1' | $(BIN)/hru + +.PHONY: hru_regressions +hru_regressions: $(BIN)/hru + n=1; \ + while true; \ + do n="$$(($$n * 10))"; \ + printf '%s\n' "$$n" | $(BIN)/hru || break; \ + done; \ + printf 'Max float: %s\n' "$$n" diff --git a/tests/bonsai/hru.sh b/tests/bonsai/hru.sh deleted file mode 100755 index 51bf7c1..0000000 --- a/tests/bonsai/hru.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh -# Copyright (c) 2024 Emma Tebibyte -# SPDX-License-Identifier: FSFAP -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice and this -# notice are preserved. This file is offered as-is, without any warranty. - -. tests/bonsai/test_env - -alias strcmp="$BIN/strcmp" -alias rpn="$BIN/rpn" - -strcmp "$(printf '1234\n' | hru)" '1.2 kB' -strcmp "$(printf '0\n' | hru)" '0 B' - -# doesn’t currently work but would be useful for testing for regressions -#n=1 -#while "$BIN/true"; do -# n="$(rpn "$n" 10 ×)" -# -# printf '%s\n' "$n" | hru || break -#done -#printf 'integer limit: ~%s\n' "$(rpn "$n" 10 ÷)" - -! printf '%s\n' '-1' | hru diff --git a/tests/bonsai/intcmp.mk b/tests/bonsai/intcmp.mk new file mode 100755 index 0000000..53f4282 --- /dev/null +++ b/tests/bonsai/intcmp.mk @@ -0,0 +1,36 @@ +# Copyright (c) 2024 DTB +# Copyright (c) 2024 Emma Tebibyte +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +.PHONY: intcmp_tests +intcmp_tests: intcmp_e intcmp_g intcmp_l + +.PHONY: intcmp_e +intcmp_e: $(BIN)/intcmp + $(BIN)/intcmp -e 3 3 3 + ! $(BIN)/intcmp -e 1 2 3 + +.PHONY: intcmp_g +intcmp_g: $(BIN)/intcmp + $(BIN)/intcmp -g 3 2 1 + ! $(BIN)/intcmp -g 1 3 3 + $(BIN)/intcmp -ge 3 3 1 + ! $(BIN)/intcmp -ge 1 2 3 + +.PHONY: intcmp_l +intcmp_l: $(BIN)/intcmp + $(BIN)/intcmp -l 1 2 3 + ! $(BIN)/intcmp -l 3 3 1 + $(BIN)/intcmp -le 1 3 3 + ! $(BIN)/intcmp -le 3 2 1 + +.PHONY: intcmp_combined +intcmp_combined: $(BIN)/intcmp + $(BINARY) -gl 1 2 3 + ! $(BINARY) -gl 3 3 3 + $(BINARY) -egl 3 1 1 2 + ! $(BINARY) -egl foo diff --git a/tests/bonsai/intcmp.sh b/tests/bonsai/intcmp.sh deleted file mode 100755 index e3cdcb7..0000000 --- a/tests/bonsai/intcmp.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh -# Copyright (c) 2024 DTB -# Copyright (c) 2024 Emma Tebibyte -# SPDX-License-Identifier: FSFAP -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice and this -# notice are preserved. This file is offered as-is, without any warranty. - -. tests/bonsai/test_env - -intcmp -e 3 3 3 -intcmp -g 3 2 1 -intcmp -l 1 2 3 -intcmp -ge 3 3 1 -intcmp -le 1 3 3 -intcmp -gl 1 2 3 -intcmp -egl 3 1 1 2 -! intcmp -e 1 2 3 -! intcmp -g 1 3 3 -! intcmp -l 3 3 1 -! intcmp -ge 1 2 3 -! intcmp -le 3 2 1 -! intcmp -gl 3 3 3 -! intcmp -egl foo diff --git a/tests/bonsai/mm.mk b/tests/bonsai/mm.mk new file mode 100755 index 0000000..6117330 --- /dev/null +++ b/tests/bonsai/mm.mk @@ -0,0 +1,27 @@ +# Copyright (c) 2024 E$(NAME)a Tebibyte +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +NAME = mm +TARGET = $(NAME)_tests +BINARY = $(BIN)/$(NAME) + +.PHONY: mm_tests +mm_tests: mm_args mm_help mm_stderr + +.PHONY: mm_args +# mm(1) will error if positional arguments are given without -i or -o +mm_args: $(BIN)/mm + ! $(BIN)/mm argument + +.PHONY: mm_help +mm_help: $(BIN)/mm + ! $(BIN)/mm -h + +.PHONY: mm_stderr +# check if stderr is empty upon specifying -e +mm_stderr: $(BIN)/mm + ! test "$$(printf 'test\n' | $(BIN)/mm -i - -e 2>&1 >/dev/null)" = "test" diff --git a/tests/bonsai/npc.sh b/tests/bonsai/npc.mk similarity index 70% rename from tests/bonsai/npc.sh rename to tests/bonsai/npc.mk index aa66b4f..5f110de 100755 --- a/tests/bonsai/npc.sh +++ b/tests/bonsai/npc.mk @@ -1,20 +1,28 @@ #!/bin/sh # Copyright (c) 2024 DTB +# Copyright (c) 2024 Emma Tebibyte # SPDX-License-Identifier: FSFAP # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice and this # notice are preserved. This file is offered as-is, without any warranty. -. tests/bonsai/test_env +.PRAGMA: command_comment -! npc -h +.PHONY: npc_tests +npc_tests: npc_args npc_help +.PHONY: npc_args # arg parsing -npc -e +# Copyright (c) 2024 Emma Tebibyte +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +NAME = strcmp +TARGET = $(NAME)_tests +BINARY = $(BIN)/$(NAME) + +.PHONY: strcmp_tests +strcmp_tests: strcmp_equals strcmp_help strcmp_nocmp strcmp_unequals + +.PHONY: strcmp_equals +strcmp_equals: $(BIN)/strcmp + $(BIN)/strcmp equals equals + $(BIN)/strcmp - - + +.PHONY: strcmp_help +strcmp_help: $(BIN)/strcmp + ! $(BIN)/strcmp -h + +.PHONY: strcmp_nocmp +strcmp_nocmp: $(BIN)/strcmp + ! $(BIN)/strcmp nocmp + +.PHONY: strcmp_unequals +strcmp_unequals: $(BIN)/strcmp + ! $(BIN)/strcmp unequals equals diff --git a/tests/bonsai/strcmp.sh b/tests/bonsai/strcmp.sh deleted file mode 100755 index 9d9024e..0000000 --- a/tests/bonsai/strcmp.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -# Copyright (c) 2024 DTB -# Copyright (c) 2024 Emma Tebibyte -# SPDX-License-Identifier: FSFAP -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice and this -# notice are preserved. This file is offered as-is, without any warranty. - -. tests/bonsai/test_env - -strcmp equals equals -! strcmp inequals equals -strcmp - - -! strcmp -h -! strcmp nocmp diff --git a/tests/bonsai/test_env b/tests/bonsai/test_env deleted file mode 100644 index aaf2b50..0000000 --- a/tests/bonsai/test_env +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -set -ex - -alias "$UTIL=$BIN/$UTIL" diff --git a/tests/bonsai/true.sh b/tests/bonsai/true.mk similarity index 71% rename from tests/bonsai/true.sh rename to tests/bonsai/true.mk index 413d758..fb6e82c 100755 --- a/tests/bonsai/true.sh +++ b/tests/bonsai/true.mk @@ -7,7 +7,13 @@ # permitted in any medium without royalty provided the copyright notice and this # notice are preserved. This file is offered as-is, without any warranty. -. tests/bonsai/test_env +.PHONY: true_tests +true_tests: true_test -true -true -h +.PHONY: true_help +true_help: $(BIN)/true + $(BIN)/true -h + +.PHONY: true_test +true_test: $(BIN)/true + $(BIN)/true diff --git a/tests/locales/en_US.UTF-8 b/tests/locales/en_US.UTF-8 deleted file mode 100644 index 95e2efb..0000000 --- a/tests/locales/en_US.UTF-8 +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -export RUN_ERR='Run this script in the root of the project' -export TEST_STR='Testing utility' diff --git a/tests/locales/tok b/tests/locales/tok deleted file mode 100644 index 7770742..0000000 --- a/tests/locales/tok +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -export RUN_ERR="ilo ni li ken ala pali lon ma ni. sina ken kepeken ona lon ma \ -sewi" -export TEST_STR='ilo pali' diff --git a/tests/test.sh b/tests/test.sh deleted file mode 100755 index bc68c65..0000000 --- a/tests/test.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh - -# Copyright (c) 2023–2024 Emma Tebibyte -# SPDX-License-Identifier: FSFAP -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice and this -# notice are preserved. This file is offered as-is, without any warranty. - -set -e - -. "tests/locales/$LANG" - -export BIN=build/bin - -if ! ls Makefile >/dev/null 2>&1 -then - printf '%s: %s\n' "$0" "$RUN_ERR" 1>&2 - exit 1 -fi - -for script in tests/bonsai/*.sh; do - export UTIL="$(printf '%s\n' "$script" \ - | sed -e 's/\.sh//g' -e 's;tests\/bonsai\/;;g')" - - printf '%s: %s: %s\n' "$0" "$UTIL" "$TEST_STR" - "$script" - printf '\n' -done - -for test_util in tests/posix/*.sh; do - realutil="$(command -v "$(printf '%s\n' "$test" | sed 's/\.sh$//g')")" - export realutil - export PATH="$BIN:$PATH" - printf '%s: %s: %s\n' "$0" "$test" "$TEST_STR" - "$test_util" - printf '\n' -done diff --git a/tests/bonsai/mm.sh b/tests/tests.mk old mode 100755 new mode 100644 similarity index 51% rename from tests/bonsai/mm.sh rename to tests/tests.mk index 43f3a1c..04f3680 --- a/tests/bonsai/mm.sh +++ b/tests/tests.mk @@ -1,19 +1,15 @@ -#!/bin/sh # Copyright (c) 2024 Emma Tebibyte # SPDX-License-Identifier: FSFAP # # Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice and this +# permitted in any medium without royalty provided the copyright notice and this # notice are preserved. This file is offered as-is, without any warranty. -. tests/bonsai/test_env -exec 3>&1 +#TESTFILES != for file in tests/bonsai/*.mk tests/posix/*.mk; do printf '%s ' "$$file"; done; +TESTFILES != for file in tests/bonsai/*.mk; do printf '%s ' "$$file"; done; -! mm -h +TESTS != printf '%s\n' "$(TESTFILES)" | xargs -n1 basename \ + | sed 's/\.mk/_tests/g' -# mm(1) will error if positional arguments are given without -i or -o -! mm argument - -# check if stderr is empty upon specifying -e -! "$BIN/strcmp" "$(printf 'test\n' | mm -i - -e 2>&1 1>&3)" '' +include $(TESTFILES) From bd09d169496a972606ed88701ee9505ee1f6b5fa Mon Sep 17 00:00:00 2001 From: DTB Date: Fri, 2 Aug 2024 18:22:45 -0600 Subject: [PATCH 296/343] tests: bonsai/dj.mk: comment more --- tests/bonsai/dj.mk | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/bonsai/dj.mk b/tests/bonsai/dj.mk index 9c27927..402abd6 100755 --- a/tests/bonsai/dj.mk +++ b/tests/bonsai/dj.mk @@ -12,7 +12,7 @@ /dev/null: .PHONY: dj_tests -dj_tests: dj_full dj_help dj_null # dj_skip_stdin +dj_tests: dj_help dj_full dj_null # dj_skip_stdin .PHONY: dj_full # Linux has a /dev/full pseudodevice useful for testing errors. @@ -20,7 +20,8 @@ dj_full: $(BIN)/dj /dev/full case "$$(uname)" in \ Linux) \ $(BIN)/dj -Hi /dev/zero -o /dev/full 2>&1 \ - | xargs -I out test '1+0 > 0+0; 1024 > 0' = out \ + | tee /dev/tty \ + | xargs -I out test '1+0 > 0+0; 1024 > 0' = out \ ;; \ esac @@ -32,11 +33,16 @@ dj_help: $(BIN)/dj # Read nothing from /dev/null, write nothing to /dev/null. dj_null: $(BIN)/dj /dev/null $(BIN)/dj -Hi /dev/null -o /dev/null 2>&1 \ + | tee /dev/tty \ | xargs -I out test '0+0 > 0+0; 0 > 0' = out +# This test currently fails. This is probably due to dj(1) being stale relative +# to the main harakit branch. TODO: Reassess once the testing branch is merged. # .PHONY: dj_skip_stdin +# # Test skipping stdin. # dj_skip_stdin: $(BIN)/dj - # Test skipping stdin. - #dd count=1 bs=1024 /dev/null \ - # | $(BIN)/dj -H -s 24 -o /dev/null 2>&1 \ - # | xargs -I out test '1+0 > 1+0; 1024 > 1000' = out +# # Pipe 1024B of '\0' into dj(1); skip the first 24B; expect 1000B written. +# dd count=1 bs=1024 /dev/null \ +# | $(BIN)/dj -H -s 24 -o /dev/null 2>&1 \ +# | tee /dev/tty \ +# | xargs -I out test '1+0 > 1+0; 1024 > 1000' = out From 91de98cea3025ca3e2a65d4298f910ab0e1d8f6d Mon Sep 17 00:00:00 2001 From: DTB Date: Fri, 2 Aug 2024 18:28:24 -0600 Subject: [PATCH 297/343] tests: bonsai/intcmp.mk: make tests more relevant to failure cases --- tests/bonsai/intcmp.mk | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/tests/bonsai/intcmp.mk b/tests/bonsai/intcmp.mk index 53f4282..57afae0 100755 --- a/tests/bonsai/intcmp.mk +++ b/tests/bonsai/intcmp.mk @@ -7,30 +7,39 @@ # notice are preserved. This file is offered as-is, without any warranty. .PHONY: intcmp_tests -intcmp_tests: intcmp_e intcmp_g intcmp_l +intcmp_tests: intcmp_help intcmp_e intcmp_g intcmp_l intcmp_combined + +.PHONY: intcmp_help +intcmp_help: $(BIN)/intcmp + ! $(BIN)/intcmp -h .PHONY: intcmp_e intcmp_e: $(BIN)/intcmp - $(BIN)/intcmp -e 3 3 3 - ! $(BIN)/intcmp -e 1 2 3 + $(BIN)/intcmp -e 3 3 3 # == + ! $(BIN)/intcmp -e 1 2 3 # < + ! $(BIN)/intcmp -e 3 2 1 # > .PHONY: intcmp_g intcmp_g: $(BIN)/intcmp - $(BIN)/intcmp -g 3 2 1 - ! $(BIN)/intcmp -g 1 3 3 - $(BIN)/intcmp -ge 3 3 1 - ! $(BIN)/intcmp -ge 1 2 3 + $(BIN)/intcmp -g 3 2 1 # > + ! $(BIN)/intcmp -g 3 3 3 # == + ! $(BIN)/intcmp -g 1 2 3 # < + $(BIN)/intcmp -ge 3 3 1 # >= + ! $(BIN)/intcmp -ge 1 2 3 # < .PHONY: intcmp_l intcmp_l: $(BIN)/intcmp - $(BIN)/intcmp -l 1 2 3 - ! $(BIN)/intcmp -l 3 3 1 - $(BIN)/intcmp -le 1 3 3 - ! $(BIN)/intcmp -le 3 2 1 + $(BIN)/intcmp -l 1 2 3 # < + ! $(BIN)/intcmp -l 3 3 3 # == + ! $(BIN)/intcmp -l 3 2 1 # > + $(BIN)/intcmp -le 1 3 3 # <= + ! $(BIN)/intcmp -le 3 2 1 # > .PHONY: intcmp_combined intcmp_combined: $(BIN)/intcmp - $(BINARY) -gl 1 2 3 - ! $(BINARY) -gl 3 3 3 - $(BINARY) -egl 3 1 1 2 - ! $(BINARY) -egl foo + $(BIN)/intcmp -gl 1 2 3 # < + $(BIN)/intcmp -gl 3 2 1 # > + $(BIN)/intcmp -gl 1 3 1 # != + ! $(BIN)/intcmp -gl 3 3 3 # == + $(BIN)/intcmp -egl 3 1 1 3 # >, ==, < + ! $(BIN)/intcmp -egl foo # huh? From ee7b7e89b2396eb3c330e0212326031558d75de9 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 2 Aug 2024 19:37:36 -0600 Subject: [PATCH 298/343] tests: bonsai/fop.mk: fixes record separators --- tests/bonsai/fop.mk | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/bonsai/fop.mk b/tests/bonsai/fop.mk index a22ca46..9013308 100755 --- a/tests/bonsai/fop.mk +++ b/tests/bonsai/fop.mk @@ -6,12 +6,16 @@ # notice are preserved. This file is offered as-is, without any warranty. .PHONY: fop_tests -fop_tests: fop_help fop_functionality fop_delimiter fop_fail +fop_tests: fop_functionality fop_delimiter fop_help fop_fail + +.PHONY: fop_help +fop_help: $(BIN)/fop + ! $(BIN)/fop -h .PHONY: fop_delimiter fop_delimiter: $(BIN)/fop - test "$$(printf 'test0 test1 test2\n' | $(BIN)/fop -d' ' 2 sed 's/2/4/g')" \ - = 'test0 test1 test4' + test "$$(printf 'test1 test1 test1\n' | $(BIN)/fop -d' ' 2 sed 's/2/4/g')" \ + = 'test1 test1 test4' test "$$(printf 'meowsetwoofsetribbit\n' \ | $(BIN)/fop -d 'set' 1 sed 's/woof/meow/g')" = 'meowsetmeowsetribbit' @@ -23,9 +27,5 @@ fop_fail: $(BIN)/fop .PHONY: fop_functionality fop_functionality: $(BIN)/fop - test "$$(printf 'test0␞test1␞test2\n' | $(BIN)/fop 1 sed 's/1/4/g')" \ - = 'test0␞test4␞test2' - -.PHONY: fop_help -fop_help: $(BIN)/fop - ! $(BIN)/fop -h + test "$$(printf 'test1\036test1\036test1\n' | $(BIN)/fop 1 sed 's/1/4/g')" \ + = "$$(printf 'test1\036test4\036test1\n')" From 588680406a8e08fae6a645ee2a63b99827fd185f Mon Sep 17 00:00:00 2001 From: DTB Date: Sat, 3 Aug 2024 07:29:04 -0600 Subject: [PATCH 299/343] tests: bonsai/npc.mk: full ASCII test coverage --- tests/bonsai/npc.mk | 70 ++++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/tests/bonsai/npc.mk b/tests/bonsai/npc.mk index 5f110de..8b10fdf 100755 --- a/tests/bonsai/npc.mk +++ b/tests/bonsai/npc.mk @@ -10,7 +10,11 @@ .PRAGMA: command_comment .PHONY: npc_tests -npc_tests: npc_args npc_help +npc_tests: npc_help npc_args npc_ascii + +.PHONY: npc_help +npc_help: $(BIN)/npc + ! $(BIN)/npc -h .PHONY: npc_args # arg parsing @@ -20,23 +24,49 @@ npc_args: $(BIN)/npc -et /dev/null \ -# | xargs "$BIN"/intcmp -e 8 \ -# && i="$(printf '20 + %s\n' "$i" | bc)" -#done +.PHONY: npc_ascii_controls +# (control characters) +npc_ascii_controls: + # ASCII 0x00 to 0x0a (before the newline, due to xargs(1p) issues) + awk 'BEGIN{ for (i = 0; i < 32; ++i) printf("%c", i); }' \ + | $(BIN)/npc \ + | head -n 1 \ + | xargs -I out test "^@^A^B^C^D^E^F^G^H" = out + + # ASCII 0x0a (otherwise the head|tail sequence won't work) to 0x1f + awk 'BEGIN{ for (i = 0; i < 32; ++i) printf("%c", i); print }' \ + | $(BIN)/npc \ + | head -n 2 \ + | tail -n 1 \ + | xargs -I out test "^K^L^M^N^O^P^Q^R^S^T^U^V^W^X^Y^Z^[^\^]^^^_" + +.PHONY: npc_ascii_symbols +# ASCII 0x1f to 0x3f (^_ and symbols) +npc_ascii_symbols: + # shell quoting olympics + awk 'BEGIN{ for (i = 31; i < 64; ++i) printf("%c", i); print }' \ + | $(BIN)/npc \ + | sed -e s"/\'/\\\'/g" -e 's/"/\\"/g' \ + | xargs -I out test "^_ !\"#$$%&'()*+,-./0123456789:;<=>?" = out + +.PHONY: npc_ascii_uppers +# ASCII 0x40 to 0x5f (uppercases) +npc_ascii_uppers: + awk 'BEGIN{ for (i = 64; i < 96; ++i) printf("%c", i); print }' \ + | $(BIN)/npc \ + | sed 's/\\/\\\\/' \ + | xargs -I out test @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ = out + +# This test is broken and will need closer inspection along with the npc(1) +# source. +# .PHONY: npc_ascii_lowers +# # ASCII 0x60 to 0x7f (lowercases) +# npc_ascii_lowers: +# awk 'BEGIN{ for (i = 96; i < 128; ++i) printf("%c", i); print }' \ +# | $(BIN)/npc \ +# | xargs -I out test "\`abcdefghijklmnopqrstuvwxyz{|}~^?" = out From 0f2d357476f1c3809a7641bd58d9b9691f6483f5 Mon Sep 17 00:00:00 2001 From: DTB Date: Sat, 3 Aug 2024 07:33:46 -0600 Subject: [PATCH 300/343] tests/bonsai: dj.mk: tee diagnostics to stderr instead of tty --- tests/bonsai/dj.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/bonsai/dj.mk b/tests/bonsai/dj.mk index 402abd6..bf8adf3 100755 --- a/tests/bonsai/dj.mk +++ b/tests/bonsai/dj.mk @@ -20,7 +20,7 @@ dj_full: $(BIN)/dj /dev/full case "$$(uname)" in \ Linux) \ $(BIN)/dj -Hi /dev/zero -o /dev/full 2>&1 \ - | tee /dev/tty \ + | tee /dev/stderr \ | xargs -I out test '1+0 > 0+0; 1024 > 0' = out \ ;; \ esac @@ -33,7 +33,7 @@ dj_help: $(BIN)/dj # Read nothing from /dev/null, write nothing to /dev/null. dj_null: $(BIN)/dj /dev/null $(BIN)/dj -Hi /dev/null -o /dev/null 2>&1 \ - | tee /dev/tty \ + | tee /dev/stderr \ | xargs -I out test '0+0 > 0+0; 0 > 0' = out # This test currently fails. This is probably due to dj(1) being stale relative @@ -44,5 +44,5 @@ dj_null: $(BIN)/dj /dev/null # # Pipe 1024B of '\0' into dj(1); skip the first 24B; expect 1000B written. # dd count=1 bs=1024 /dev/null \ # | $(BIN)/dj -H -s 24 -o /dev/null 2>&1 \ -# | tee /dev/tty \ +# | tee /dev/stderr \ # | xargs -I out test '1+0 > 1+0; 1024 > 1000' = out From acdbecf1786180c7e6b01462d685e5c543d7c057 Mon Sep 17 00:00:00 2001 From: DTB Date: Sat, 3 Aug 2024 21:36:53 -0600 Subject: [PATCH 301/343] tests: bonsai/scrut.mk: add tests --- tests/bonsai/scrut.mk | 46 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100755 tests/bonsai/scrut.mk diff --git a/tests/bonsai/scrut.mk b/tests/bonsai/scrut.mk new file mode 100755 index 0000000..e7f421e --- /dev/null +++ b/tests/bonsai/scrut.mk @@ -0,0 +1,46 @@ +#!/bin/sh +# Copyright (c) 2024 DTB +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +.PRAGMA: command_comment + +.PHONY: scrut_tests +scrut_tests: scrut_help scrut_options + +.PHONY: scrut_help +scrut_help: $(BIN)/scrut + ! $(BIN)/scrut -h + +.PHONY: scrut_options +# scrut tests file attributes, but files of a certain attribute aren't +# guaranteed to be present on a system. This test checks all of the files in +# harakit and, if test(1p) says a file matches a certain attribute, then checks +# scrut. +# opts are space-delimited (for command splitting), sel is not +scrut_options: $(BIN)/scrut + set -e; \ + opts="b c d e f g k p r s u w x L S"; \ + sel=; \ + find . -name .git -prune -o -print \ + | while read -r f; do \ + for opt in $$opts; \ + do if ! printf "%s\n" $$sel | grep $$opt >/dev/null; then \ + if test -$$opt "$$f"; then \ + if ! $(BIN)/scrut -$$opt "$$f"; \ + then printf "[!!] scrut -%s failed on %s.\n" \ + $$opt "$$f"; \ + fi; \ + sel="$$sel$$opt"; \ + printf "[OK] Tested scrut -%s using %s\n" \ + $$opt "$$f"; \ + fi; \ + fi; \ + done; \ + if printf "%s\n" "$$opts" | sed 's/ //g' | xargs test "$$sel" =; \ + then break; \ + fi; \ + done From cd5983b10b4dc32455a9d8a23919863136c3d537 Mon Sep 17 00:00:00 2001 From: DTB Date: Sun, 4 Aug 2024 09:05:20 -0600 Subject: [PATCH 302/343] tests/bonsai: intcmp.mk: add a comment --- tests/bonsai/intcmp.mk | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/bonsai/intcmp.mk b/tests/bonsai/intcmp.mk index 57afae0..e3c559e 100755 --- a/tests/bonsai/intcmp.mk +++ b/tests/bonsai/intcmp.mk @@ -13,6 +13,24 @@ intcmp_tests: intcmp_help intcmp_e intcmp_g intcmp_l intcmp_combined intcmp_help: $(BIN)/intcmp ! $(BIN)/intcmp -h +# These test that integer comparisons are working as they should. For the sake +# of readability (to facilitate faster skimming) these recipes follow a +# columned format: +# $binary -flags d d d d # op +# For flag meanings reference intcmp(1) (though they are somewhat self +# explanatory). d here refers to a decimal number; a mixture of 1s, 2s, and 3s +# (a particularly lovely number) arranged to demonstrate easily the operation +# under scrutiny. The commented op is the operation that is true for the given +# numbers. For example: +# $(BIN)/intcmp -e 3 3 3 3 # == +# op here is ==; 3 == 3 == 3 == 3. The flag being used is -e, to test for +# equality, so this test should succeed. +# ! $(BIN)/intcmp -l 3 2 1 # > +# op here is >; 3 > 2 > 1. The flag being used is -l, to test for each integer +# being less than the next, so intcmp should fail - hence the ! at the start of +# the invocation. If this test failed, intcmp(1) would be confusing -l for -g, +# so that would be a good place to start looking for bugs. + .PHONY: intcmp_e intcmp_e: $(BIN)/intcmp $(BIN)/intcmp -e 3 3 3 # == From e93d218b877990770e5d7ddfcb2b07afa9fbd7f5 Mon Sep 17 00:00:00 2001 From: DTB Date: Sun, 4 Aug 2024 09:14:19 -0600 Subject: [PATCH 303/343] tests/bonsai: str.mk: -h test --- tests/bonsai/str.mk | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100755 tests/bonsai/str.mk diff --git a/tests/bonsai/str.mk b/tests/bonsai/str.mk new file mode 100755 index 0000000..fac642e --- /dev/null +++ b/tests/bonsai/str.mk @@ -0,0 +1,15 @@ +# Copyright (c) 2024 DTB +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +.PRAGMA: command_comment + +.PHONY: str_tests +str_tests: str_help + +.PHONY: str_help +str_help: $(BIN)/str + ! $(BIN)/str -h From 3880abaa4fc4d0d3771bbfd8dd6ab226eebd6ee0 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 5 Aug 2024 13:47:12 -0600 Subject: [PATCH 304/343] tests: bonsai/rpn.mk: added rpn(1) test --- tests/bonsai/rpn.mk | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100755 tests/bonsai/rpn.mk diff --git a/tests/bonsai/rpn.mk b/tests/bonsai/rpn.mk new file mode 100755 index 0000000..2ac1243 --- /dev/null +++ b/tests/bonsai/rpn.mk @@ -0,0 +1,43 @@ +# Copyright (c) 2024 Emma Tebibyte +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +.PHONY: rpn_tests +rpn_tests: rpn_help rpn_add + +.PHONY: rpn_help +rpn_help: $(BIN)/rpn + ! $(BIN)/rpn -h + +.PHONY: rpn_add +rpn_add: $(BIN)/rpn + test "$$($(BIN)/rpn 1 2 +)" -eq 3 + test "$$($(BIN)/rpn 0.2 0.1 +)" = 0.3 + +.PHONY: rpn_sub +rpn_sub: $(BIN)/rpn + test "$$($(BIN)/rpn 23 5 -)" -eq 18 + test "$$($(BIN)/rpn 0.3 0.1)" = 0.2 + +.PHONY: rpn_mul +rpn_mul: $(BIN)/rpn + test "$$($(BIN)/rpn 1.2 3 '*')" = 3.6 + test "$$($(BIN)/rpn 0 3 '*')" -eq 0 + +.PHONY: rpn_div +rpn_div: $(BIN)/rpn + test "$$($(BIN)/rpn 12 5 /)" = 2.4 + test "$$($(BIN)/rpn 3 0 /)" -eq inf + +.PHONY: rpn_mod +rpn_mod: $(BIN)/rpn + test "$$($(BIN)/rpn 12 5 %)" -eq 2 + test "$$($(BIN)/rpn 9 4 %)" -eq 1 + +.PHONY: rpn_flr +rpn_flr: $(BIN)/rpn + test "$$($(BIN)/rpn 12 5 //)" -eq 2 + test "$$($(BIN)/rpn 9 4 //)" -eq 2 From 9412f95cb1414876e718cdbab4b65eff7ae36d6e Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 5 Aug 2024 21:16:18 -0600 Subject: [PATCH 305/343] tests: bonsai/str.mk: add str_isalpha test --- tests/bonsai/str.mk | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/bonsai/str.mk b/tests/bonsai/str.mk index fac642e..38ad9ca 100755 --- a/tests/bonsai/str.mk +++ b/tests/bonsai/str.mk @@ -8,8 +8,13 @@ .PRAGMA: command_comment .PHONY: str_tests -str_tests: str_help +str_tests: str_help str_isalpha .PHONY: str_help str_help: $(BIN)/str ! $(BIN)/str -h + +.PHONY: str_isalpha +str_isalpha: $(BIN)/str + $(BIN)/str isalpha c + ! $(BIN)/str isalpha 3 From a94884cc2ade776a86056bfa7e7716aa2674bf50 Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 7 Aug 2024 08:34:29 -0600 Subject: [PATCH 306/343] tests: bonsai/swab.mk: add example from tha man page --- tests/bonsai/swab.mk | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100755 tests/bonsai/swab.mk diff --git a/tests/bonsai/swab.mk b/tests/bonsai/swab.mk new file mode 100755 index 0000000..ff64c17 --- /dev/null +++ b/tests/bonsai/swab.mk @@ -0,0 +1,22 @@ +# Copyright (c) 2024 DTB +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +.PRAGMA: command_comment + +.PHONY: swab_tests +swab_tests: swab_help swab_examples + +.PHONY: swab_help +swab_help: $(BIN)/swab + ! $(BIN)/swab -h + +.PHONY: swab_examples +# These are the examples present in the man page. +swab_examples: $(BIN)/swab + printf 'hello world!\n' \ + | $(BIN)/swab \ + | xargs -I out test 'ehll oowlr!d' = out From a7f16b5a7e331fcbe3b64a75474f5fb877354d76 Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 7 Aug 2024 08:35:24 -0600 Subject: [PATCH 307/343] swab.1: Add note to keep example in tests --- docs/swab.1 | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/swab.1 b/docs/swab.1 index 42eef95..89cebb2 100644 --- a/docs/swab.1 +++ b/docs/swab.1 @@ -36,6 +36,7 @@ line: .RS printf 'hello world!\(rsn' | swab .RE +.\" If you change this, make sure to change it in tests/bonsai/swab.mk too. Produces the following output: From 0bc0ffa0a51401f11673b57da2062b26821d4ae5 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 7 Aug 2024 20:38:03 -0600 Subject: [PATCH 308/343] tests: bonsai/hru.mk: updates to not use old variables --- tests/bonsai/hru.mk | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/bonsai/hru.mk b/tests/bonsai/hru.mk index 9d200e5..618acb8 100755 --- a/tests/bonsai/hru.mk +++ b/tests/bonsai/hru.mk @@ -5,10 +5,6 @@ # permitted in any medium without royalty provided the copyright notice and this # notice are preserved. This file is offered as-is, without any warranty. -NAME = hru -TARGET = $(NAME)_tests -BINARY = $(BIN)/$(NAME) - .PHONY: hru_tests hru_tests: $(BIN)/hru From eb821715f7fdfda38900c5dd10ca91efedabd2e3 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 7 Aug 2024 20:45:26 -0600 Subject: [PATCH 309/343] tests: bonsai/hru.mk: fixes hru.mk more --- tests/bonsai/hru.mk | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/bonsai/hru.mk b/tests/bonsai/hru.mk index 618acb8..6f3a05f 100755 --- a/tests/bonsai/hru.mk +++ b/tests/bonsai/hru.mk @@ -6,17 +6,17 @@ # notice are preserved. This file is offered as-is, without any warranty. .PHONY: hru_tests -hru_tests: $(BIN)/hru +hru_tests: hru_help hru_functionality hru_negative hru_regression + +.PHONY: hru_help +hru_help: $(BIN)/hru + ! $(BIN)/hru -h .PHONY: hru_functionality hru_functionality: $(BIN)/hru test "$(printf '1234\n' | $(BIN)/hru)" = '1.2 kB' test "$(printf '0\n' | $(BIN)/hru)" = '0 B' -.PHONY: $(NAME_help) -hru_help: $(BIN)/hru - ! $(BIN)/hru -h - .PHONY: hru_negative hru_negative: $(BIN)/hru ! printf '%s\n' '-1' | $(BIN)/hru From 8e5090d13dcd56feddef261a8adcda10f9149c25 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 7 Aug 2024 22:03:32 -0600 Subject: [PATCH 310/343] tests: README: updates README --- tests/README | 64 ++++++++++++++++------------------------------------ 1 file changed, 20 insertions(+), 44 deletions(-) diff --git a/tests/README b/tests/README index ee370b8..7e7508c 100644 --- a/tests/README +++ b/tests/README @@ -1,57 +1,33 @@ -The testing suite contains two main trees (plus translations for strings used in -the shell scripts): the Bonsai tree and the POSIX tree: +The testing suite contains two trees: the Bonsai tree and the POSIX tree: . -├── bonsai -│   ├── test_env -│   ├── dj.sh -│   ├── false.sh -│   ├── fop.sh -│   ├── hru.sh -│   ├── intcmp.sh -│   ├── mm.sh -│   ├── strcmp.sh -│   └── true.sh -├── locales -│   ├── en_US.UTF-8 -│   └── tok -├── posix -│   ├── bin -│   │   ├── cat -│   │   ├── false -│   │   └── true -│   └── posix_env ├── README -└── test.sh +├── bonsai/ +│   ├── dj.mk +│   ├── false.mk +│   ├── fop.mk +│   └── ... +├── posix/ +└── tests.mk The Bonsai tree tests the functionality of Harakit utilities for regressions and other issues relating to compliance to our standards of practice. -The POSIX tree tests the use of Harakit utilities in place of the standard usage -of POSIX utilities. These scripts test the ability of Harakit to comply to POSIX -standards using its native utilities in shell scripts as a compatibility shim. -Each shell script in the top directory should contain a set of tests for each -POSIX utility and be named for that utility. The bin directory should contain -a set of shim scripts which will be imported into the path as POSIX utilities. -Each test will compare the behavior of the shim script to the real utility on -the system. +The POSIX tests are currently a work-in-progress. Their status in this +repository is uncertain. -Currently, due to the limitations of POSIX shell quoting, a subset of argument -parsing is supported: arguments containing characters from POSIX’s Portable -Filename Character Set [0]. +Both sets of tests also inherit the environment set by the top-level Makefile, +which sets the BIN variable to the build/bin directory at the root of the +project; therefore, each binary is located at $(BIN)/tool for idiomatic access. -The bonsai/test_env and posix/posix_env files contain prerequisite shared -environments for each of the tests. These scripts both contain lines which set -the shell to write all commands run in them (-x) and to fail if any command -fails (-e). See set(1p) for more information. +Each test contains a set of PHONY targets which are prefixed with the name of +the tool being tested and an underscore. The first target is tests, which +depends on all the other targets in the test file. These test files are each +included in the top Makefile, so they can be called from the root of the +repository. This also means that BIN can be set manually so that tests can be +run using make(1) inside of the tests directory: -Both sets of tests also inherit the environment set by the test.sh script, which -sets the $BIN environment variable to the bin directory at the root of the -project for easy and idiomatic access to the built Harakit binaries. When -calling the POSIX test scripts, test.sh also sets the variable $realutil to be -the absolute path to the currently tested utility’s counterpart on the system. - -[0] + $ make -f tests.mk BIN=../build/bin dj_tests -- Copyright © 2024 Emma Tebibyte From 7278a8fc41c7784074676851bab97762b364bc70 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 9 Aug 2024 18:00:25 -0600 Subject: [PATCH 311/343] Makefile: fixes testing import --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6c6d555..1b9b9bd 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,6 @@ CFLAGS += -I$(SYSEXITS) # testing requires the absolute path to the bin directory set BIN = build/bin -include tests/tests.mk .PHONY: default default: all test @@ -158,3 +157,5 @@ build/bin/swab: src/swab.rs build rustlibs true: build/bin/true build/bin/true: src/true.c build $(CC) $(CFLAGS) -o $@ src/true.c + +include tests/tests.mk From b76ff8fd90bba9e4a93178622b92f0dd398e9bd8 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 9 Aug 2024 23:50:31 -0600 Subject: [PATCH 312/343] tests, Makefile: cleaning up --- Makefile | 4 ++-- src/hru.rs | 6 +++++- tests/bonsai/fop.mk | 2 +- tests/bonsai/hru.mk | 9 +++++---- tests/bonsai/mm.mk | 2 +- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 5db506e..87bf566 100644 --- a/Makefile +++ b/Makefile @@ -57,6 +57,8 @@ dist: all docs install: dist cp -r $(DESTDIR)/* / +include tests/tests.mk + .PHONY: test test: all $(TESTS) /tmp/getopt @echo $(TESTS) @@ -156,5 +158,3 @@ build/bin/swab: src/swab.rs build rustlibs true: build/bin/true build/bin/true: src/true.c build $(CC) $(CFLAGS) -o $@ src/true.c - -include tests/tests.mk diff --git a/src/hru.rs b/src/hru.rs index c02d4c1..1ed5bdd 100644 --- a/src/hru.rs +++ b/src/hru.rs @@ -27,7 +27,7 @@ extern crate strerror; extern crate sysexits; use strerror::StrError; -use sysexits::{ EX_DATAERR, EX_IOERR, EX_SOFTWARE }; +use sysexits::{ EX_DATAERR, EX_IOERR, EX_SOFTWARE, EX_USAGE }; /* list of SI prefixes */ const LIST: [(u32, &str); 10] = [ @@ -76,6 +76,10 @@ fn convert(input: u128) -> Result<(f64, (u32, &'static str)), String> { fn main() -> ExitCode { let argv = args().collect::>(); + if let Some(_) = argv.get(1) { + eprintln!("Usage: {}", argv[0]); + return ExitCode::from(EX_USAGE as u8); + } let mut buf = String::new(); while let Ok(_) = stdin().read_line(&mut buf) { diff --git a/tests/bonsai/fop.mk b/tests/bonsai/fop.mk index 9013308..b538031 100755 --- a/tests/bonsai/fop.mk +++ b/tests/bonsai/fop.mk @@ -14,7 +14,7 @@ fop_help: $(BIN)/fop .PHONY: fop_delimiter fop_delimiter: $(BIN)/fop - test "$$(printf 'test1 test1 test1\n' | $(BIN)/fop -d' ' 2 sed 's/2/4/g')" \ + test "$$(printf 'test1 test1 test1\n' | $(BIN)/fop -d' ' 2 sed 's/1/4/g')" \ = 'test1 test1 test4' test "$$(printf 'meowsetwoofsetribbit\n' \ | $(BIN)/fop -d 'set' 1 sed 's/woof/meow/g')" = 'meowsetmeowsetribbit' diff --git a/tests/bonsai/hru.mk b/tests/bonsai/hru.mk index 6f3a05f..49d30cd 100755 --- a/tests/bonsai/hru.mk +++ b/tests/bonsai/hru.mk @@ -6,7 +6,7 @@ # notice are preserved. This file is offered as-is, without any warranty. .PHONY: hru_tests -hru_tests: hru_help hru_functionality hru_negative hru_regression +hru_tests: hru_help hru_functionality hru_negative hru_regressions .PHONY: hru_help hru_help: $(BIN)/hru @@ -14,8 +14,8 @@ hru_help: $(BIN)/hru .PHONY: hru_functionality hru_functionality: $(BIN)/hru - test "$(printf '1234\n' | $(BIN)/hru)" = '1.2 kB' - test "$(printf '0\n' | $(BIN)/hru)" = '0 B' + test "$$(printf '1234\n' | $(BIN)/hru)" = '1.2 kB' + test "$$(printf '0\n' | $(BIN)/hru)" = '0 B' .PHONY: hru_negative hru_negative: $(BIN)/hru @@ -25,7 +25,8 @@ hru_negative: $(BIN)/hru hru_regressions: $(BIN)/hru n=1; \ while true; \ - do n="$$(($$n * 10))"; \ + do \ printf '%s\n' "$$n" | $(BIN)/hru || break; \ + n="$$(($$n * 10))"; \ done; \ printf 'Max float: %s\n' "$$n" diff --git a/tests/bonsai/mm.mk b/tests/bonsai/mm.mk index 6117330..2b1fea6 100755 --- a/tests/bonsai/mm.mk +++ b/tests/bonsai/mm.mk @@ -24,4 +24,4 @@ mm_help: $(BIN)/mm .PHONY: mm_stderr # check if stderr is empty upon specifying -e mm_stderr: $(BIN)/mm - ! test "$$(printf 'test\n' | $(BIN)/mm -i - -e 2>&1 >/dev/null)" = "test" + ! test "$$(printf 'test\n' | $(BIN)/mm -e 2>&1 >/dev/null)" = "test" From c7c71c725b48a1ea14bfae76927fb6781c149aab Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 12:49:35 -0600 Subject: [PATCH 313/343] libopenbsd(3): adds pledge(2) and unveil(2) support for Rust; Makefile, include: adds conditional compilation --- Makefile | 15 +++++--- include/FreeBSD.mk | 6 ++++ include/Linux.mk | 6 ++++ include/OpenBSD.mk | 13 +++++++ src/libopenbsd.rs | 88 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 include/FreeBSD.mk create mode 100644 include/Linux.mk create mode 100644 include/OpenBSD.mk create mode 100644 src/libopenbsd.rs diff --git a/Makefile b/Makefile index 87bf566..0a9a4fe 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,9 @@ DESTDIR ?= dist PREFIX ?= /usr/local +# for conditionally compiling OS features +OS != uname + # normalized prefix PREFIX_N != dirname $(PREFIX)/. MANDIR != test $(PREFIX_N) = / && printf '/usr/share/man\n' \ @@ -26,8 +29,8 @@ SYSEXITS != printf '\043include \n' | cpp -M - | tr ' ' '\n' \ CC ?= cc RUSTC ?= rustc RUSTFLAGS += --extern getopt=build/o/libgetopt.rlib \ - --extern sysexits=build/o/libsysexits.rlib \ - --extern strerror=build/o/libstrerror.rlib + --extern strerror=build/o/libstrerror.rlib \ + --extern sysexits=build/o/libsysexits.rlib CFLAGS += -I$(SYSEXITS) # testing requires the absolute path to the bin directory set @@ -74,9 +77,13 @@ docs: docs/ build "s/X\.X\.X/$$(git describe --tags --long | cut -d'-' -f1)/g")"; \ sed "s/$$original/$$title/g" <"$$file" >"build/$$file"; done + +# include OS feature libraries for compilation +include include/$(OS).mk + .PHONY: rustlibs -rustlibs: build/o/libsysexits.rlib build/o/libgetopt.rlib \ - build/o/libstrerror.rlib +rustlibs: build/o/libgetopt.rlib build/o/libstrerror.rlib \ + build/o/libsysexits.rlib $(OSLIB) build/o/libgetopt.rlib: build src/libgetopt.rs $(RUSTC) $(RUSTFLAGS) --crate-type=lib --crate-name=getopt \ diff --git a/include/FreeBSD.mk b/include/FreeBSD.mk new file mode 100644 index 0000000..8d679b4 --- /dev/null +++ b/include/FreeBSD.mk @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Emma Tebibyte +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. diff --git a/include/Linux.mk b/include/Linux.mk new file mode 100644 index 0000000..8d679b4 --- /dev/null +++ b/include/Linux.mk @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Emma Tebibyte +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. diff --git a/include/OpenBSD.mk b/include/OpenBSD.mk new file mode 100644 index 0000000..9624629 --- /dev/null +++ b/include/OpenBSD.mk @@ -0,0 +1,13 @@ +# Copyright (c) 2024 Emma Tebibyte +# SPDX-License-Identifier: FSFAP +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice and this +# notice are preserved. This file is offered as-is, without any warranty. + +OSLIB = build/o/libopenbsd.rlib +RUSTFLAGS += --extern openbsd=$(OSLIB) + +$(OSLIB): src/libopenbsd.rs + $(RUSTC) $(RUSTFLAGS) --crate-type=lib --crate-name=openbsd \ + -o $@ src/libopenbsd.rs diff --git a/src/libopenbsd.rs b/src/libopenbsd.rs new file mode 100644 index 0000000..7d98d10 --- /dev/null +++ b/src/libopenbsd.rs @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2024 Emma Tebibyte + * 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::{ + ffi::{ CString, c_int }, + io::Error, + ptr::null, +}; + +mod openbsd { + use std::ffi::{ c_char, c_int }; + extern "C" { + pub fn pledge(arg1: *const c_char, arg2: *const c_char) -> c_int; + + pub fn unveil(arg1: *const c_char, arg2: *const c_char) -> c_int; + + pub fn __errno() -> *mut c_int; + } +} + +pub struct Promises(*const i8); + +impl Promises { + pub fn new(promises: &str) -> Self { + let p = CString::new(promises).unwrap(); + + Promises(p.into_raw() as *const i8) + } +} + +pub fn pledge( + promises: Option, execpromises: Option +) -> Result<(), Error> { + /* From pledge(2): + * + * Passing NULL to promises or execpromises specifies to not change + * the current value. */ + let arg1 = promises.unwrap_or(Promises(null())).0; + let arg2 = execpromises.unwrap_or(Promises(null())).0; + + unsafe { + match openbsd::pledge(arg1, arg2) { + -1 => Err(Error::from_raw_os_error(*openbsd::__errno())), + 0 => Ok(()), + _ => panic!(), /* unreachable */ + } + } +} + +pub struct UnveilPerms(CString); + +impl UnveilPerms { + pub fn new(permissions: Vec) -> Self { + if permissions.is_empty() { + return UnveilPerms(CString::new("").unwrap()); + } + + UnveilPerms( + CString::new(permissions.iter().collect::()).unwrap() + ) + } +} + +pub fn unveil(path: Option<&str>, permissions: Option) -> c_int { + let path_c = path.map(CString::new).map(Result::unwrap); + let arg1 = path_c.map(|p| p.into_raw() as *const i8).unwrap_or(null()); + + let arg2 = permissions + .map(|p| p.0.into_raw() as *const i8) + .unwrap_or(null()); + + unsafe { openbsd::unveil(arg1, arg2) } +} From 1f59a9806eab226e65cecc9689d5951f55044647 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 12:50:15 -0600 Subject: [PATCH 314/343] dj(1): adds pledge(2) and unveil(2) support --- src/dj.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/dj.c b/src/dj.c index d6f5fde..ae33b2d 100644 --- a/src/dj.c +++ b/src/dj.c @@ -26,7 +26,8 @@ #include /* memcpy(3), memmove(3), memset(3) */ #include /* EX_OK, EX_OSERR, EX_USAGE */ #include /* close(2), getopt(3), lseek(2), read(2), write(2), - * optarg, optind, STDIN_FILENO, STDOUT_FILENO */ + * pledge(2), unveil(2), optarg, optind, STDIN_FILENO, + * STDOUT_FILENO */ #include /* S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR */ char *program_name = "dj"; @@ -123,7 +124,6 @@ fprintio(FILE *stream, char *fmt, struct Io io[2]) { io[0].rec, io[0].prec, io[1].rec, - io[1].prec, io[0].bytes, io[1].bytes ); @@ -167,6 +167,12 @@ usage(char *argv0) { } int main(int argc, char *argv[]) { +#ifdef __OpenBSD__ + if (pledge("cpath rpath stdio unveil wpath", NULL) == -1) { + return oserr("pledge", errno); + } +#endif + int align; /* low 8b used, negative if no alignment is being done */ int count; /* -1 if dj(1) runs until no more reads are possible */ char *fmt; /* set to fmt_asv (default) or fmt_human (-H) */ @@ -208,6 +214,16 @@ int main(int argc, char *argv[]) { break; } else { int fd; +#ifdef __OpenBSD__ + char *perms = "wc"; + + /* modify perms in-place to read-only */ + if (i == 0) { perms = "r"; } + + if (unveil(optarg, perms) == -1) { + return oserr("unveil", errno); + } +#endif if ( (fd = open(optarg, io[i].fl, creat_mode)) != -1 @@ -248,6 +264,9 @@ int main(int argc, char *argv[]) { } } } +#ifdef __OpenBSD__ + if (unveil(NULL, NULL) == -1) { return oserr("unveil", errno); } +#endif assert(io->fd != STDIN_FILENO || io->fl == read_flags); assert(io->fd != STDOUT_FILENO || io->fl == write_flags); From cf96a13419a191cae18e73e29551228a1da13165 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 12:50:51 -0600 Subject: [PATCH 315/343] true(1), false(1): adds pledge(2) and unveil(2) support --- src/false.c | 13 +++++++++++-- src/true.c | 12 ++++++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/false.c b/src/false.c index 3b6ec2a..1617b03 100644 --- a/src/false.c +++ b/src/false.c @@ -1,9 +1,18 @@ /* - * Copyright (c) 2023 Emma Tebibyte + * Copyright (c) 2023–2024 Emma Tebibyte * SPDX-License-Identifier: CC0 * * This work is marked with CC0 1.0. To view a copy of this license, visit * . */ -int main() { return 1; } +#ifdef __OpenBSD__ +# include /* pledge(2) */ +#endif + +int main() { +#ifdef __OpenBSD__ + pledge(NULL, NULL); +#endif +return 1; +} diff --git a/src/true.c b/src/true.c index ab8da96..eb16efd 100644 --- a/src/true.c +++ b/src/true.c @@ -1,9 +1,17 @@ /* - * Copyright (c) 2023 Emma Tebibyte + * Copyright (c) 2023–2024 Emma Tebibyte * SPDX-License-Identifier: CC0 * * This work is marked with CC0 1.0. To view a copy of this license, visit * . */ -int main() {} +#ifdef __OpenBSD__ +# include /* pledge(2) */ +#endif + +int main() { +#ifdef __OpenBSD__ + pledge(NULL, NULL); +#endif +} From 6c882f54cbe34a88ca1b24cf463b7bf15aa2c59c Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 12:51:25 -0600 Subject: [PATCH 316/343] fop(1): adds pledge support --- src/fop.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/fop.rs b/src/fop.rs index 9f547b1..66b7e82 100644 --- a/src/fop.rs +++ b/src/fop.rs @@ -30,11 +30,23 @@ use getopt::GetOpt; use strerror::StrError; use sysexits::{ EX_DATAERR, EX_IOERR, EX_UNAVAILABLE, EX_USAGE }; +#[cfg(target_os="openbsd")] use sysexits::EX_OSERR; +#[cfg(target_os="openbsd")] extern crate openbsd; +#[cfg(target_os="openbsd")] use openbsd::{ Promises, pledge }; + fn main() { let argv = args().collect::>(); let mut d = '\u{1E}'.to_string(); /* ASCII record separator */ let mut optind = 1; + if cfg!(target_os="openbsd") { + let promises = Promises::new("stdio proc exec"); + if let Err(e) = pledge(Some(promises), None) { + eprintln!("{}: {}", argv[0], e.strerror()); + exit(EX_OSERR); + } + } + let usage = format!( "Usage: {} [-d delimiter] index command [args...]", argv[0], From 25eb08eb842816e7e65c8f52baa20e13f36cf43a Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 13:04:41 -0600 Subject: [PATCH 317/343] Makefile, include: makes conditional compilation more robust --- Makefile | 5 +++-- include/Linux.mk | 6 ------ include/None.mk | 0 3 files changed, 3 insertions(+), 8 deletions(-) delete mode 100644 include/Linux.mk create mode 100644 include/None.mk diff --git a/Makefile b/Makefile index 0a9a4fe..1bdd5c9 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,8 @@ PREFIX ?= /usr/local # for conditionally compiling OS features OS != uname +OS_INCLUDE != test -e include/$(OS).mk && printf 'include/$(OS).mk\n' \ + || include/None.mk # normalized prefix PREFIX_N != dirname $(PREFIX)/. @@ -77,9 +79,8 @@ docs: docs/ build "s/X\.X\.X/$$(git describe --tags --long | cut -d'-' -f1)/g")"; \ sed "s/$$original/$$title/g" <"$$file" >"build/$$file"; done - # include OS feature libraries for compilation -include include/$(OS).mk +include $(OS_INCLUDE) .PHONY: rustlibs rustlibs: build/o/libgetopt.rlib build/o/libstrerror.rlib \ diff --git a/include/Linux.mk b/include/Linux.mk deleted file mode 100644 index 8d679b4..0000000 --- a/include/Linux.mk +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) 2024 Emma Tebibyte -# SPDX-License-Identifier: FSFAP -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice and this -# notice are preserved. This file is offered as-is, without any warranty. diff --git a/include/None.mk b/include/None.mk new file mode 100644 index 0000000..e69de29 From eae0b0352bc8a1cc09951ba65f39e645483c3bbe Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 13:07:46 -0600 Subject: [PATCH 318/343] dj(1): fixes small rebase mistake --- src/dj.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dj.c b/src/dj.c index ae33b2d..e4ddd71 100644 --- a/src/dj.c +++ b/src/dj.c @@ -124,6 +124,7 @@ fprintio(FILE *stream, char *fmt, struct Io io[2]) { io[0].rec, io[0].prec, io[1].rec, + io[1].prec, io[0].bytes, io[1].bytes ); From 70bec49127cac36aeaa140bfa2ae30eebca6f768 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 13:25:56 -0600 Subject: [PATCH 319/343] libopenbsd.rs(3): fixes API for unveil(2) --- src/libopenbsd.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/libopenbsd.rs b/src/libopenbsd.rs index 7d98d10..c16c51c 100644 --- a/src/libopenbsd.rs +++ b/src/libopenbsd.rs @@ -17,7 +17,7 @@ */ use std::{ - ffi::{ CString, c_int }, + ffi::CString, io::Error, ptr::null, }; @@ -76,7 +76,10 @@ impl UnveilPerms { } } -pub fn unveil(path: Option<&str>, permissions: Option) -> c_int { +pub fn unveil( + path: Option<&str>, + permissions: Option, +) -> Result<(), Error> { let path_c = path.map(CString::new).map(Result::unwrap); let arg1 = path_c.map(|p| p.into_raw() as *const i8).unwrap_or(null()); @@ -84,5 +87,11 @@ pub fn unveil(path: Option<&str>, permissions: Option) -> c_int { .map(|p| p.0.into_raw() as *const i8) .unwrap_or(null()); - unsafe { openbsd::unveil(arg1, arg2) } + unsafe { + match openbsd::unveil(arg1, arg2) { + -1 => Err(Error::from_raw_os_error(*openbsd::__errno())), + 0 => Ok(()), + _ => panic!(), /* unreachable */ + } + } } From 2f805cc9427ab3bc926389ed8a30bf48947fab5b Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 13:29:27 -0600 Subject: [PATCH 320/343] mm(1): adds support for pledge(2) and unveil(2) --- src/mm.rs | 48 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/src/mm.rs b/src/mm.rs index 41b7857..2d6bf17 100644 --- a/src/mm.rs +++ b/src/mm.rs @@ -33,6 +33,16 @@ use getopt::GetOpt; use strerror::StrError; use sysexits::{ EX_IOERR, EX_USAGE }; +#[cfg(target_os="openbsd")] use sysexits::EX_OSERR; +#[cfg(target_os="openbsd")] extern crate openbsd; +#[cfg(target_os="openbsd")] +use openbsd::{ + Promises, + UnveilPerms, + pledge, + unveil, +}; + use ArgMode::*; enum ArgMode { In, Out } @@ -41,6 +51,14 @@ fn main() -> ExitCode { let argv = args().collect::>(); let usage = format!("Usage: {} [-aetu] [-i input] [-o output]", argv[0]); + if cfg!(target_os="openbsd") { + let promises = Promises::new("rpath stdio unveil"); + if let Err(e) = pledge(Some(promises), None) { + eprintln!("{}: {}", argv[0], e.strerror()); + return ExitCode::from(EX_OSERR as u8); + } + } + let mut a = false; /* append to the file */ let mut e = false; /* use stderr as an output */ let mut t = true; /* do not truncate the file before writing */ @@ -58,11 +76,29 @@ fn main() -> ExitCode { Ok("t") => t = false, Ok("i") => { /* add inputs */ let input = opt.arg().unwrap(); + + if cfg!(target_os="openbsd") { + let perms = UnveilPerms::new(vec!['r']); + if let Err(e) = unveil(Some(&input), Some(perms)) { + eprintln!("{}: {}", argv[0], e.strerror()); + return ExitCode::from(EX_OSERR as u8); + } + } + ins.push(input); mode = Some(In); /* latest argument == -i */ }, Ok("o") => { /* add output */ let output = opt.arg().unwrap(); + + if cfg!(target_os="openbsd") { + let perms = UnveilPerms::new(vec!['w', 'c']); + if let Err(e) = unveil(Some(&output), Some(perms)) { + eprintln!("{}: {}", argv[0], e.strerror()); + return ExitCode::from(EX_OSERR as u8); + } + } + outs.push(output); mode = Some(Out); /* latest argument == -o */ }, @@ -86,11 +122,17 @@ fn main() -> ExitCode { Out => outs.push(arg.to_string()), }; } - } else { - eprintln!("{}", usage); - return ExitCode::from(EX_USAGE as u8); } + if cfg!(target_os="openbsd") { + if let Err(e) = unveil(None, None) { + eprintln!("{}: {}", argv[0], e.strerror()); + return ExitCode::from(EX_OSERR as u8); + } + } + + println!("{:?}", ins); + /* use stdin if no inputs are specified */ if ins.is_empty() { ins.push("-".to_string()); } From bda7c074b00a4b960b265abdbc3b43d6bfc74f7e Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 13:34:44 -0600 Subject: [PATCH 321/343] hru(1): adds support for pledge(2) --- src/hru.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/hru.rs b/src/hru.rs index 1ed5bdd..c6009a7 100644 --- a/src/hru.rs +++ b/src/hru.rs @@ -29,6 +29,10 @@ extern crate sysexits; use strerror::StrError; use sysexits::{ EX_DATAERR, EX_IOERR, EX_SOFTWARE, EX_USAGE }; +#[cfg(target_os="openbsd")] use sysexits::EX_OSERR; +#[cfg(target_os="openbsd")] extern crate openbsd; +#[cfg(target_os="openbsd")] use openbsd::{ Promises, pledge }; + /* list of SI prefixes */ const LIST: [(u32, &str); 10] = [ (3, "k"), /* kilo */ @@ -76,10 +80,20 @@ fn convert(input: u128) -> Result<(f64, (u32, &'static str)), String> { fn main() -> ExitCode { let argv = args().collect::>(); + if let Some(_) = argv.get(1) { eprintln!("Usage: {}", argv[0]); return ExitCode::from(EX_USAGE as u8); } + + if cfg!(target_os="openbsd") { + let promises = Promises::new("stdio"); + if let Err(e) = pledge(Some(promises), None) { + eprintln!("{}: {}", argv[0], e.strerror()); + return ExitCode::from(EX_OSERR as u8); + } + } + let mut buf = String::new(); while let Ok(_) = stdin().read_line(&mut buf) { From 2a75b8f8201696d03e0680bff7198327b8d1ae41 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 14:09:33 -0600 Subject: [PATCH 322/343] mm(1): removes leftover debug print --- src/mm.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mm.rs b/src/mm.rs index 2d6bf17..6f3bfa8 100644 --- a/src/mm.rs +++ b/src/mm.rs @@ -131,8 +131,6 @@ fn main() -> ExitCode { } } - println!("{:?}", ins); - /* use stdin if no inputs are specified */ if ins.is_empty() { ins.push("-".to_string()); } From d89707a47c986c8ccdc573201380bb049c9c2dba Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 14:20:38 -0600 Subject: [PATCH 323/343] mm(1): fixes mm without arguments not working --- src/mm.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/mm.rs b/src/mm.rs index 6f3bfa8..b99bf9e 100644 --- a/src/mm.rs +++ b/src/mm.rs @@ -131,6 +131,11 @@ fn main() -> ExitCode { } } + if ins.is_empty() && outs.is_empty() && argv.len() > optind { + eprintln!("Usage: {}", usage); + return ExitCode::from(EX_USAGE as u8); + } + /* use stdin if no inputs are specified */ if ins.is_empty() { ins.push("-".to_string()); } From e253cdf79c5d6d1a1038c4acac95c66c857dfaed Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 14:23:53 -0600 Subject: [PATCH 324/343] intcmp(1): fixes intcmp without options falling through to integer parsing --- src/intcmp.rs | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/intcmp.rs b/src/intcmp.rs index f504b50..b304ac0 100644 --- a/src/intcmp.rs +++ b/src/intcmp.rs @@ -1,5 +1,6 @@ /* * Copyright (c) 2023–2024 DTB + * Copyright (c) 2024 Emma Tebibyte * SPDX-License-Identifier: AGPL-3.0-or-later * * This program is free software: you can redistribute it and/or modify it under @@ -22,11 +23,18 @@ use std::{ }; extern crate getopt; -use getopt::GetOpt; - extern crate sysexits; + +use getopt::GetOpt; use sysexits::EX_USAGE; +#[cfg(target_os="openbsd")] use sysexits::EX_OSERR; +#[cfg(target_os="openbsd")] extern crate openbsd; +#[cfg(target_os="openbsd")] extern crate strerror; +#[cfg(target_os="openbsd")] use openbsd::{ Promises, pledge }; +#[cfg(target_os="openbsd")] use strerror::StrError; + + fn usage(s: &str) -> ExitCode { eprintln!("Usage: {} [-egl] integer integer...", s); ExitCode::from(EX_USAGE as u8) @@ -34,6 +42,15 @@ fn usage(s: &str) -> ExitCode { fn main() -> ExitCode { let argv = args().collect::>(); + + if cfg!(target_os="openbsd") { + let promises = Promises::new("stdio"); + if let Err(e) = pledge(Some(promises), None) { + eprintln!("{}: {}", argv[0], e.strerror()); + return ExitCode::from(EX_OSERR as u8); + } + } + let mut e = false; /* args can be == */ let mut g = false; /* args can be > */ let mut l = false; /* args can be < */ @@ -46,11 +63,13 @@ fn main() -> ExitCode { Ok("e") => e = true, Ok("g") => g = true, Ok("l") => l = true, - _ => { return usage(&argv[0]); }, + _ => return usage(&argv[0]), } optind = opt.ind(); } + if !e & !g & !l { return usage(&argv[0]); } + if argv.len() - optind < 2 /* see usage */ { return usage(&argv[0]); } let mut prev: Option = None; /* no previous operand */ @@ -59,8 +78,8 @@ fn main() -> ExitCode { for arg in argv.iter().skip(optind) { /* iterate operands */ match arg.parse::() { /* parse current operand */ Ok(n) => currn = n, - _ => { - eprintln!("{}: {}: Invalid integer", &argv[0], arg); + Err(e) => { + eprintln!("{}: {}: {}", &argv[0], arg, e); return ExitCode::from(EX_USAGE as u8); } } From 851f729ebd056aa9c2c5c5daa437d733b3c1038b Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 14:24:33 -0600 Subject: [PATCH 325/343] tests: bonsai/mm.mk, bonsai/intcmp.mk: updates for regression testing --- tests/bonsai/intcmp.mk | 6 +++++- tests/bonsai/mm.mk | 10 +++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/bonsai/intcmp.mk b/tests/bonsai/intcmp.mk index e3c559e..abcff03 100755 --- a/tests/bonsai/intcmp.mk +++ b/tests/bonsai/intcmp.mk @@ -7,7 +7,7 @@ # notice are preserved. This file is offered as-is, without any warranty. .PHONY: intcmp_tests -intcmp_tests: intcmp_help intcmp_e intcmp_g intcmp_l intcmp_combined +intcmp_tests: intcmp_help intcmp_none intcmp_e intcmp_g intcmp_l intcmp_combined .PHONY: intcmp_help intcmp_help: $(BIN)/intcmp @@ -31,6 +31,10 @@ intcmp_help: $(BIN)/intcmp # the invocation. If this test failed, intcmp(1) would be confusing -l for -g, # so that would be a good place to start looking for bugs. +.PHONY: intcmp_none +intcmp_none: $(BIN)/intcmp + ! $(BIN)/intcmp 1 2 + .PHONY: intcmp_e intcmp_e: $(BIN)/intcmp $(BIN)/intcmp -e 3 3 3 # == diff --git a/tests/bonsai/mm.mk b/tests/bonsai/mm.mk index 2b1fea6..2800460 100755 --- a/tests/bonsai/mm.mk +++ b/tests/bonsai/mm.mk @@ -5,13 +5,13 @@ # permitted in any medium without royalty provided the copyright notice and this # notice are preserved. This file is offered as-is, without any warranty. -NAME = mm -TARGET = $(NAME)_tests -BINARY = $(BIN)/$(NAME) - .PHONY: mm_tests mm_tests: mm_args mm_help mm_stderr +.PHONY: mm_none +mm_none: $(BIN)/mm + test "$$(printf 'meow\n' | $(BIN)/mm)" = meow + .PHONY: mm_args # mm(1) will error if positional arguments are given without -i or -o mm_args: $(BIN)/mm @@ -24,4 +24,4 @@ mm_help: $(BIN)/mm .PHONY: mm_stderr # check if stderr is empty upon specifying -e mm_stderr: $(BIN)/mm - ! test "$$(printf 'test\n' | $(BIN)/mm -e 2>&1 >/dev/null)" = "test" + test "$$(printf 'test\n' | $(BIN)/mm -e 2>&1 >/dev/null )" = "test" From 72ef8d00bcb7cbdc0eb77b39c6bdc521d0bd3010 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 15:22:07 -0600 Subject: [PATCH 326/343] npc(1): adds pledge(2) support --- src/npc.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/npc.c b/src/npc.c index 7ef760a..ca16171 100644 --- a/src/npc.c +++ b/src/npc.c @@ -19,8 +19,13 @@ #include /* fprintf(3), fputs(3), getc(3), perror(3), putc(3), stdin, * stdout, EOF */ -#include /* EX_IOERR, EX_OK, EX_USAGE */ -#include /* getopt(3) */ +#include /* EX_IOERR, EX_OK, EX_OSERR, EX_USAGE */ +#include /* pledge(2), getopt(3) */ + +#ifdef __OpenBSD__ +# include /* errno */ +# include /* strerror(3) */ +#endif char *program_name = "npc"; @@ -39,13 +44,22 @@ usage(char *argv0) { } int main(int argc, char *argv[]) { +#ifdef __OpenBSD__ + program_name = argv[0] == NULL ? program_name : argv[0]; + + if (pledge("stdio", NULL) == -1) { + (void)fprintf(stderr, "%s: %s\n", program_name, strerror(errno)); + return EX_OSERR; + } +#endif int c; char showend = 0; /* print a dollar sign before each newline */ char showtab = 0; /* prints tab characters in caret notation */ if (argc > 0) { +#ifndef __OpenBSD__ program_name = argv[0]; - +#endif while ((c = getopt(argc, argv, "et")) != -1) { switch (c){ case 'e': showend = 1; break; From 326c8f77d13683dd3e3aae5cb2cdd75993857efe Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 15:34:14 -0600 Subject: [PATCH 327/343] rpn(1): adds support for pledge(2) --- src/rpn.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/rpn.rs b/src/rpn.rs index 784e323..e4f725d 100644 --- a/src/rpn.rs +++ b/src/rpn.rs @@ -56,6 +56,12 @@ extern crate sysexits; use sysexits::EX_DATAERR; +#[cfg(target_os="openbsd")] use sysexits::EX_OSERR; +#[cfg(target_os="openbsd")] extern crate strerror; +#[cfg(target_os="openbsd")] extern crate openbsd; +#[cfg(target_os="openbsd")] use strerror::StrError; +#[cfg(target_os="openbsd")] use openbsd::{ Promises, pledge }; + #[derive(Clone, PartialEq, PartialOrd, Debug)] /* enum CalcType is a type containing operations used in the calculator */ enum CalcType { @@ -191,6 +197,15 @@ fn round_precise(value: &f64, precision: usize) -> f64 { fn main() -> ExitCode { let argv = args().collect::>(); + + if cfg!(target_os="openbsd") { + let promises = Promises::new("stdio"); + if let Err(e) = pledge(Some(promises), None) { + eprintln!("{}: {}", argv[0], e.strerror()); + return ExitCode::from(EX_OSERR as u8); + } + } + let mut stack = VecDeque::new(); let mut buf = String::new(); /* Set floating-point precision for correcting rounding errors based on From 0ddfa6e474fd2bb0854e4214fd46c771a7d13ba3 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 15:34:41 -0600 Subject: [PATCH 328/343] tests: bonsai/rpn.mk: fixes rpn_test target deps --- tests/bonsai/rpn.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/bonsai/rpn.mk b/tests/bonsai/rpn.mk index 2ac1243..3619692 100755 --- a/tests/bonsai/rpn.mk +++ b/tests/bonsai/rpn.mk @@ -6,7 +6,7 @@ # notice are preserved. This file is offered as-is, without any warranty. .PHONY: rpn_tests -rpn_tests: rpn_help rpn_add +rpn_tests: rpn_help rpn_add rpn_sub rpn_mul rpn_div rpn_mod rpn_flr .PHONY: rpn_help rpn_help: $(BIN)/rpn @@ -20,7 +20,7 @@ rpn_add: $(BIN)/rpn .PHONY: rpn_sub rpn_sub: $(BIN)/rpn test "$$($(BIN)/rpn 23 5 -)" -eq 18 - test "$$($(BIN)/rpn 0.3 0.1)" = 0.2 + test "$$($(BIN)/rpn 0.3 0.1 -)" = 0.2 .PHONY: rpn_mul rpn_mul: $(BIN)/rpn From 42010596de67b8cd590eb97bef3a66a60b2f95e6 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 17:17:42 -0600 Subject: [PATCH 329/343] scrut(1): adds support for pledge(2) and unveil(2) --- src/scrut.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/scrut.c b/src/scrut.c index 39fa698..8c7f321 100644 --- a/src/scrut.c +++ b/src/scrut.c @@ -20,8 +20,9 @@ #include /* fprintf(3), stderr, NULL */ #include /* EXIT_FAILURE, EXIT_SUCCESS */ #include /* memset(3), strchr(3) */ -#include /* EX_USAGE */ -#include /* access(3), getopt(3), F_OK, R_OK, W_OK, X_OK */ +#include /* EX_OSERR, EX_USAGE */ +#include /* access(3), getopt(3), pledge(2), unveil(2), F_OK, R_OK, + * W_OK, X_OK */ #include /* lstat(3), stat struct, S_ISBLK, S_ISCHR, S_ISDIR, * S_ISFIFO, S_ISGID, S_ISREG, S_ISLNK, S_ISSOCK, * S_ISUID, S_ISVTX */ @@ -40,7 +41,16 @@ usage(char *argv0) { int main(int argc, char *argv[]) { char sel[(sizeof opts) / (sizeof *opts)]; - if (argc < 2) { return usage(argv[0] == NULL ? program_name : argv[0]); } + program_name = argv[0] == NULL ? program_name : argv[0]; + +#ifdef __OpenBSD__ + if (pledge("rpath stdio unveil", NULL) == -1) { + perror(program_name); + return EX_OSERR; + } +#endif + + if (argc < 2) { return usage(program_name); } { /* option parsing */ char *p; @@ -66,6 +76,13 @@ int main(int argc, char *argv[]) { for (argv += optind ; *argv != NULL; ++argv) { struct stat buf; +#ifdef __OpenBSD__ + if (unveil(*argv, "r") == -1) { + perror(program_name); + return EX_OSERR; + } +#endif + if(access(*argv, F_OK) != 0 || lstat(*argv, &buf) == -1) { return EXIT_FAILURE; /* doesn't exist or isn't stattable */ } From 18dfd2093721e0cb6855ed3ef28d6355d06babdc Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 18:57:36 -0600 Subject: [PATCH 330/343] scrut(1): fixes buffer overflow on i386 systems --- src/scrut.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scrut.c b/src/scrut.c index 8c7f321..7eccaee 100644 --- a/src/scrut.c +++ b/src/scrut.c @@ -29,7 +29,7 @@ char *program_name = "scrut"; #define OPTS "bcdefgkprsuwxLS" -static char *opts = OPTS; +static char opts[] = OPTS; static int usage(char *argv0) { From 8699d04ccc73ba481505226b9e6bfff85a93c34c Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 19:00:32 -0600 Subject: [PATCH 331/343] str(1): updates to use pledge(2) --- src/str.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/str.c b/src/str.c index 9f7b351..35d19b1 100644 --- a/src/str.c +++ b/src/str.c @@ -22,7 +22,11 @@ #include /* fprintf(3) */ #include /* size_t, EXIT_FAILURE */ #include /* strcmp(3) */ -#include /* EX_USAGE */ +#include /* EX_OSERR, EX_USAGE */ + +#ifdef __OpenBSD__ +# include /* pledge(2) */ +#endif char *program_name = "str"; @@ -55,8 +59,16 @@ usage(char *argv0) { int main(int argc, char *argv[]) { size_t ctype; // selected from ctypes.h; index of ctype int retval; // initially fail but becomes success on the first valid char + program_name = argv[0] == NULL ? program_name : argv[0]; - if (argc < 3) { return usage(argv[0] == NULL ? program_name : argv[0]); } +#ifdef __OpenBSD__ + if (pledge("stdio", NULL) == -1) { + perror(program_name); + return EX_OSERR; + } +#endif + + if (argc < 3) { return usage(program_name); } for ( /* iterate ctypes */ ctype = 0; From 6c558654f3a6fd5fe360831436359805536d14e0 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 19:01:44 -0600 Subject: [PATCH 332/343] str(1): adds reference to perror(3) in include --- src/str.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/str.c b/src/str.c index 35d19b1..7b38ac8 100644 --- a/src/str.c +++ b/src/str.c @@ -19,7 +19,7 @@ #include #include /* NULL */ -#include /* fprintf(3) */ +#include /* fprintf(3), perror(2) */ #include /* size_t, EXIT_FAILURE */ #include /* strcmp(3) */ #include /* EX_OSERR, EX_USAGE */ From ea2efdf5b9416b029cb4822e8365c55069e50713 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 19:08:15 -0600 Subject: [PATCH 333/343] str(1): perror(2) -> perror(3) --- src/str.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/str.c b/src/str.c index 7b38ac8..9ed27c2 100644 --- a/src/str.c +++ b/src/str.c @@ -19,7 +19,7 @@ #include #include /* NULL */ -#include /* fprintf(3), perror(2) */ +#include /* fprintf(3), perror(3) */ #include /* size_t, EXIT_FAILURE */ #include /* strcmp(3) */ #include /* EX_OSERR, EX_USAGE */ From d6d9c2088e4a5178cc51f4d9629eb91ecb1de3f1 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 19:09:26 -0600 Subject: [PATCH 334/343] npc(1): uses perror(3) --- src/npc.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/npc.c b/src/npc.c index ca16171..5b6c5c9 100644 --- a/src/npc.c +++ b/src/npc.c @@ -22,11 +22,6 @@ #include /* EX_IOERR, EX_OK, EX_OSERR, EX_USAGE */ #include /* pledge(2), getopt(3) */ -#ifdef __OpenBSD__ -# include /* errno */ -# include /* strerror(3) */ -#endif - char *program_name = "npc"; static int @@ -48,7 +43,7 @@ int main(int argc, char *argv[]) { program_name = argv[0] == NULL ? program_name : argv[0]; if (pledge("stdio", NULL) == -1) { - (void)fprintf(stderr, "%s: %s\n", program_name, strerror(errno)); + perror(program_name); return EX_OSERR; } #endif From baa75a261950c78d6a719152b22636ecfb467d44 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 19:09:50 -0600 Subject: [PATCH 335/343] strcmp(1): implements use of pledge(2) --- src/strcmp.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/strcmp.c b/src/strcmp.c index f3dc25f..07919d5 100644 --- a/src/strcmp.c +++ b/src/strcmp.c @@ -16,20 +16,28 @@ * 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/. */ -#include /* fprintf(3), stderr */ -#include /* EX_OK, EX_USAGE */ +#include /* fprintf(3), perror(3), stderr */ +#include /* EX_OK, EX_OSERR, EX_USAGE */ + +#ifdef __OpenBSD__ +# include /* pledge(2) */ +#endif char *program_name = "strcmp"; int main(int argc, char *argv[]) { + program_name = argv[0] == NULL ? program_name : argv[0]; int i; +#ifdef __OpenBSD__ + if (pledge("stdio", NULL) != -1) { + perror(program_name); + return EX_OSERR; + } +#endif + if (argc < 3) { - (void)fprintf( - stderr, - "Usage: %s string string...\n", - argv[0] == NULL ? program_name : argv[0] - ); + (void)fprintf(stderr, "Usage: %s string string...\n", program_name); return EX_USAGE; } From 1003c82d23be6e6db28e163dc18245a2373768c5 Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 19:16:26 -0600 Subject: [PATCH 336/343] swab(1): uses pledge(2) --- src/swab.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/swab.rs b/src/swab.rs index 671f485..27ce9a5 100644 --- a/src/swab.rs +++ b/src/swab.rs @@ -32,6 +32,10 @@ use getopt::GetOpt; use sysexits::{ EX_IOERR, EX_OK, EX_OSERR, EX_USAGE }; use strerror::StrError; +#[cfg(target_os="openbsd")] extern crate openbsd; +#[cfg(target_os="openbsd")] use openbsd::{ Promises, pledge }; + + fn oserr(argv0: &str, e: Error) -> ExitCode { eprintln!("{}: {}", argv0, e.strerror()); ExitCode::from(EX_OSERR as u8) @@ -49,6 +53,14 @@ fn usage(s: &str) -> ExitCode { fn main() -> ExitCode { let argv = args().collect::>(); + + if cfg!(target_os="openbsd") { + let promises = Promises::new("stdio"); + if let Err(e) = pledge(Some(promises), None) { + return oserr(&argv[0], e); + } + } + let mut buf: Vec = Vec::new(); // holds the sequence getting swabbed let mut input = stdin(); let mut output = stdout().lock(); From a693ced9d94bd420230c2280f05593637c23d6eb Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 10 Aug 2024 19:18:52 -0600 Subject: [PATCH 337/343] strcmp(1): fixes typo --- src/strcmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strcmp.c b/src/strcmp.c index 07919d5..ea20b1e 100644 --- a/src/strcmp.c +++ b/src/strcmp.c @@ -30,7 +30,7 @@ int main(int argc, char *argv[]) { int i; #ifdef __OpenBSD__ - if (pledge("stdio", NULL) != -1) { + if (pledge("stdio", NULL) == -1) { perror(program_name); return EX_OSERR; } From b1a4a1a2b95c708009b1557dc03f453bd1ae8ddd Mon Sep 17 00:00:00 2001 From: DTB Date: Sat, 10 Aug 2024 22:03:59 -0600 Subject: [PATCH 338/343] dj(1): use entirely-stdio error messages for OpenBSD functions --- src/dj.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/dj.c b/src/dj.c index e4ddd71..ad1dc49 100644 --- a/src/dj.c +++ b/src/dj.c @@ -108,8 +108,10 @@ Io_write(struct Io *io) { } static int -oserr(char *e, int n) { - (void)fprintf(stderr, "%s: %s: %s\n", program_name, e, strerror(n)); +oserr(char *e, int n) { /* program_name: [failing component:] error */ + (void)fprintf(stderr, "%s: ", program_name); + if (e != NULL) { (void)fprintf(stderr, "%s: ", e); } + (void)fprintf(stderr, "%s\n", strerror(n)); return EX_OSERR; } @@ -170,7 +172,7 @@ usage(char *argv0) { int main(int argc, char *argv[]) { #ifdef __OpenBSD__ if (pledge("cpath rpath stdio unveil wpath", NULL) == -1) { - return oserr("pledge", errno); + return oserr(NULL", errno); } #endif @@ -222,7 +224,7 @@ int main(int argc, char *argv[]) { if (i == 0) { perms = "r"; } if (unveil(optarg, perms) == -1) { - return oserr("unveil", errno); + return oserr(NULL, errno); } #endif @@ -266,7 +268,7 @@ int main(int argc, char *argv[]) { } } #ifdef __OpenBSD__ - if (unveil(NULL, NULL) == -1) { return oserr("unveil", errno); } + if (unveil(NULL, NULL) == -1) { return oserr(NULL, errno); } #endif assert(io->fd != STDIN_FILENO || io->fl == read_flags); From 10b7f7706b5c89c19a1aed3dce95249d89ffe9db Mon Sep 17 00:00:00 2001 From: DTB Date: Sat, 10 Aug 2024 22:16:06 -0600 Subject: [PATCH 339/343] dj(1): tweak OpenBSD functions --- src/dj.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/dj.c b/src/dj.c index ad1dc49..6d6a117 100644 --- a/src/dj.c +++ b/src/dj.c @@ -170,12 +170,6 @@ usage(char *argv0) { } int main(int argc, char *argv[]) { -#ifdef __OpenBSD__ - if (pledge("cpath rpath stdio unveil wpath", NULL) == -1) { - return oserr(NULL", errno); - } -#endif - int align; /* low 8b used, negative if no alignment is being done */ int count; /* -1 if dj(1) runs until no more reads are possible */ char *fmt; /* set to fmt_asv (default) or fmt_human (-H) */ @@ -183,6 +177,12 @@ int main(int argc, char *argv[]) { bool retry; /* false if exits on partial reads or writes */ struct Io io[2 /* { in, out } */]; +#ifdef __OpenBSD__ + if (pledge("cpath rpath stdio unveil wpath", NULL) == -1) { + return oserr(NULL, errno); + } +#endif + /* Set defaults. */ align = -1; count = -1; @@ -217,13 +217,9 @@ int main(int argc, char *argv[]) { break; } else { int fd; + #ifdef __OpenBSD__ - char *perms = "wc"; - - /* modify perms in-place to read-only */ - if (i == 0) { perms = "r"; } - - if (unveil(optarg, perms) == -1) { + if (unveil(optarg, i == 0 ? "r" : "wc") == -1) { return oserr(NULL, errno); } #endif @@ -267,6 +263,7 @@ int main(int argc, char *argv[]) { } } } + #ifdef __OpenBSD__ if (unveil(NULL, NULL) == -1) { return oserr(NULL, errno); } #endif From da190f713cdc93dda6a24fafe0acc5e599706433 Mon Sep 17 00:00:00 2001 From: DTB Date: Sat, 10 Aug 2024 22:18:15 -0600 Subject: [PATCH 340/343] npc(1): tweak OpenBSD functions --- src/npc.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/npc.c b/src/npc.c index 5b6c5c9..cd488e5 100644 --- a/src/npc.c +++ b/src/npc.c @@ -39,22 +39,20 @@ usage(char *argv0) { } int main(int argc, char *argv[]) { -#ifdef __OpenBSD__ - program_name = argv[0] == NULL ? program_name : argv[0]; - - if (pledge("stdio", NULL) == -1) { - perror(program_name); - return EX_OSERR; - } -#endif int c; char showend = 0; /* print a dollar sign before each newline */ char showtab = 0; /* prints tab characters in caret notation */ - if (argc > 0) { -#ifndef __OpenBSD__ - program_name = argv[0]; +#ifdef __OpenBSD__ + if (pledge("stdio", NULL) == -1) { + perror(argv[0] == NULL ? program_name : argv[0]); + return EX_OSERR; + } #endif + + if (argc > 0) { + program_name = argv[0]; + while ((c = getopt(argc, argv, "et")) != -1) { switch (c){ case 'e': showend = 1; break; From 98c4d94f6d59e919b8a1e8af70eb44f948ed74f7 Mon Sep 17 00:00:00 2001 From: DTB Date: Sat, 10 Aug 2024 22:24:32 -0600 Subject: [PATCH 341/343] scrut(1): further error-proofing --- src/scrut.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/scrut.c b/src/scrut.c index 7eccaee..cfdd923 100644 --- a/src/scrut.c +++ b/src/scrut.c @@ -17,6 +17,7 @@ * along with this program. If not, see https://www.gnu.org/licenses/. */ +#include /* assert(3) */ #include /* fprintf(3), stderr, NULL */ #include /* EXIT_FAILURE, EXIT_SUCCESS */ #include /* memset(3), strchr(3) */ @@ -29,6 +30,7 @@ char *program_name = "scrut"; #define OPTS "bcdefgkprsuwxLS" +/* this is an array so main:sel's size can be known at compile time */ static char opts[] = OPTS; static int @@ -58,7 +60,10 @@ int main(int argc, char *argv[]) { memset(sel, '\0', sizeof sel); for (int c; (c = getopt(argc, argv, opts)) != -1;) { if ((p = strchr(opts, c)) == NULL) { return usage(argv[0]); } - else { sel[p - opts] = c; } + else { + assert(p - opts < sizeof sel / sizeof *sel); /* bounds check */ + sel[p - opts] = c; + } } /* straighten out selections; permute out nulls */ @@ -73,7 +78,7 @@ int main(int argc, char *argv[]) { if (optind == argc) { return usage(argv[0]); } - for (argv += optind ; *argv != NULL; ++argv) { + for (argv += optind ; *argv != NULL; argv = &argv[1]) { struct stat buf; #ifdef __OpenBSD__ From 4c8151674216cfaa0794ff8a7e63d81f992702d4 Mon Sep 17 00:00:00 2001 From: DTB Date: Sat, 10 Aug 2024 22:30:08 -0600 Subject: [PATCH 342/343] strcmp(1): further error-proofing --- src/strcmp.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/strcmp.c b/src/strcmp.c index ea20b1e..6d930d5 100644 --- a/src/strcmp.c +++ b/src/strcmp.c @@ -26,18 +26,22 @@ char *program_name = "strcmp"; int main(int argc, char *argv[]) { - program_name = argv[0] == NULL ? program_name : argv[0]; - int i; + unsigned int i; #ifdef __OpenBSD__ if (pledge("stdio", NULL) == -1) { - perror(program_name); + perror(argv[0] == NULL ? program_name : argv[0]); + return EX_OSERR; } #endif if (argc < 3) { - (void)fprintf(stderr, "Usage: %s string string...\n", program_name); + (void)fprintf( + stderr, + "Usage: %s string string...\n", + argv[0] == NULL ? program_name : argv[0] + ); return EX_USAGE; } From e0c985f7ff7bb9cdd86e5925a6dc058d040b065e Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 14 Aug 2024 00:32:28 -0600 Subject: [PATCH 343/343] libopenbsd.rs(3): uses c_char instead of i8 for portability --- src/libopenbsd.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libopenbsd.rs b/src/libopenbsd.rs index c16c51c..f3e60b9 100644 --- a/src/libopenbsd.rs +++ b/src/libopenbsd.rs @@ -17,7 +17,7 @@ */ use std::{ - ffi::CString, + ffi::{ CString, c_char }, io::Error, ptr::null, }; @@ -33,13 +33,13 @@ mod openbsd { } } -pub struct Promises(*const i8); +pub struct Promises(*const c_char); impl Promises { pub fn new(promises: &str) -> Self { let p = CString::new(promises).unwrap(); - Promises(p.into_raw() as *const i8) + Promises(p.into_raw() as *const c_char) } } @@ -81,10 +81,10 @@ pub fn unveil( permissions: Option, ) -> Result<(), Error> { let path_c = path.map(CString::new).map(Result::unwrap); - let arg1 = path_c.map(|p| p.into_raw() as *const i8).unwrap_or(null()); + let arg1 = path_c.map(|p| p.into_raw() as *const c_char).unwrap_or(null()); let arg2 = permissions - .map(|p| p.0.into_raw() as *const i8) + .map(|p| p.0.into_raw() as *const c_char) .unwrap_or(null()); unsafe {