From cabe08bca4a8aeaaf155b7863e85cb8c6cbc6036 Mon Sep 17 00:00:00 2001 From: DTB Date: Thu, 29 Feb 2024 20:33:09 -0700 Subject: [PATCH 001/170] 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/170] 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/170] 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/170] 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 057f5571d6708a964e2b6cc60e10ff76d132cf92 Mon Sep 17 00:00:00 2001 From: emma Date: Wed, 24 Apr 2024 14:58:35 -0600 Subject: [PATCH 005/170] 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 006/170] 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 007/170] 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 008/170] 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 009/170] 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 010/170] 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 0113cf793de13298f6ec7986b43cb6a639289e18 Mon Sep 17 00:00:00 2001 From: emma Date: Thu, 25 Apr 2024 17:20:55 -0600 Subject: [PATCH 011/170] 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 012/170] 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 013/170] 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 014/170] 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 015/170] 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 8508479a5b0e76aee6ce99999dcacaa093dedf10 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 27 May 2024 22:07:17 -0600 Subject: [PATCH 016/170] 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 017/170] 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 018/170] 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 019/170] 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 020/170] 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 c88c41b21370a1866b3a2324a0c79f5bb208e06e Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 2 Jun 2024 20:14:06 -0600 Subject: [PATCH 021/170] 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 5cfccf75af614ca5838cfa5b889895a89fadccc3 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 7 Jun 2024 23:30:13 -0600 Subject: [PATCH 022/170] 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 45329ccb8cd9fe1118ec7c4d3854cb584d52ddad Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 7 Jul 2024 19:19:38 -0600 Subject: [PATCH 023/170] 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 aa819cabc242697fda8bc61ad89bd2c0a1b30396 Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 8 Jul 2024 22:24:18 -0600 Subject: [PATCH 024/170] 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 025/170] 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 6cf7fd979416ddac9c4e58ae1ac4336b95232118 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 12 Jul 2024 15:23:57 -0600 Subject: [PATCH 026/170] 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 027/170] 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 028/170] 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 029/170] 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 030/170] 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 031/170] 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 032/170] 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 033/170] 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 034/170] 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 035/170] 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 036/170] 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 037/170] 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 038/170] 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 039/170] 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 040/170] 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 041/170] 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 042/170] 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 043/170] 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 044/170] 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 045/170] 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 046/170] 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 047/170] 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 048/170] 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 049/170] 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 050/170] 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 051/170] 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 052/170] 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 053/170] 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 054/170] 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 055/170] 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 789046f69457fb58560f4dbdca32ca5733b30fb1 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 15 Jul 2024 13:03:30 -0600 Subject: [PATCH 056/170] 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 057/170] 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 058/170] 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 059/170] 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 060/170] 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 061/170] 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 062/170] 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 063/170] 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 064/170] 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 065/170] 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 066/170] 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 3ba6682ab3af10cf2c1e00a7e4f766f24abe4db7 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 19 Jul 2024 16:41:02 -0600 Subject: [PATCH 067/170] 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 068/170] 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 069/170] 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 070/170] 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 071/170] 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 072/170] 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 073/170] 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 074/170] 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 075/170] 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 076/170] 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 077/170] 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 078/170] 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 079/170] 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 080/170] 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 081/170] 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 082/170] 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 083/170] 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 084/170] 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 085/170] 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 086/170] 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 087/170] 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 088/170] 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 089/170] 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 090/170] 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 091/170] 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 092/170] 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 093/170] 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 094/170] 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 095/170] 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 096/170] 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 097/170] 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 098/170] 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 099/170] 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 100/170] 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 101/170] 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 102/170] 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 103/170] 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 104/170] 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 105/170] 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 106/170] 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 107/170] 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 108/170] 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 109/170] 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 110/170] 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 111/170] 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 112/170] 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 113/170] 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 114/170] 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 115/170] 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 116/170] 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 117/170] 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 118/170] 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 119/170] 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 120/170] 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 121/170] 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 122/170] 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 123/170] 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 124/170] 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 125/170] 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 126/170] 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 127/170] 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 128/170] 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 129/170] 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 130/170] 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 131/170] 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 132/170] 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 133/170] 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 134/170] 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 135/170] 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 136/170] 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 137/170] 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 138/170] 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 139/170] 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 140/170] 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 141/170] 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 142/170] 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 143/170] 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 144/170] 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 145/170] 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 146/170] 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 147/170] 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 148/170] 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 149/170] 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 150/170] 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 151/170] 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 152/170] 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 153/170] 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 154/170] 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 155/170] 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 156/170] 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 157/170] 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 158/170] 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 159/170] 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 160/170] 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 161/170] 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 { From 0c4923016e72cc534a01e0a21376c20d8994ed0b Mon Sep 17 00:00:00 2001 From: DTB Date: Tue, 13 Aug 2024 11:56:09 -0600 Subject: [PATCH 162/170] Makefile: replace include/None.mk with /dev/null --- Makefile | 2 +- include/None.mk | 0 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 include/None.mk diff --git a/Makefile b/Makefile index 1bdd5c9..5de9618 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ 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 + || printf '/dev/null\n' # normalized prefix PREFIX_N != dirname $(PREFIX)/. diff --git a/include/None.mk b/include/None.mk deleted file mode 100644 index e69de29..0000000 From 0fd66bff38bbb792eaaf2206e7048200cbcfd203 Mon Sep 17 00:00:00 2001 From: DTB Date: Tue, 13 Aug 2024 12:04:42 -0600 Subject: [PATCH 163/170] false(1), true(1): complete main prototype --- src/false.c | 5 +++-- src/true.c | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/false.c b/src/false.c index 1617b03..555a170 100644 --- a/src/false.c +++ b/src/false.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2023–2024 Emma Tebibyte + * Copyright (c) 2024 DTB * SPDX-License-Identifier: CC0 * * This work is marked with CC0 1.0. To view a copy of this license, visit @@ -10,9 +11,9 @@ # include /* pledge(2) */ #endif -int main() { +int main(void) { #ifdef __OpenBSD__ pledge(NULL, NULL); #endif -return 1; + return 1; } diff --git a/src/true.c b/src/true.c index eb16efd..0e2f91d 100644 --- a/src/true.c +++ b/src/true.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2023–2024 Emma Tebibyte + * Copyright (c) 2024 DTB * SPDX-License-Identifier: CC0 * * This work is marked with CC0 1.0. To view a copy of this license, visit @@ -10,7 +11,7 @@ # include /* pledge(2) */ #endif -int main() { +int main(void) { #ifdef __OpenBSD__ pledge(NULL, NULL); #endif From e2c03842a30a8a338131e7952cf5287d6588a640 Mon Sep 17 00:00:00 2001 From: DTB Date: Tue, 13 Aug 2024 12:13:47 -0600 Subject: [PATCH 164/170] intcmp(1): remove extra newline --- src/intcmp.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/intcmp.rs b/src/intcmp.rs index b304ac0..a7c045d 100644 --- a/src/intcmp.rs +++ b/src/intcmp.rs @@ -34,7 +34,6 @@ use sysexits::EX_USAGE; #[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) From a4a556a5b659d6c03d08cb066e2573fc6b225681 Mon Sep 17 00:00:00 2001 From: emma Date: Fri, 16 Aug 2024 18:43:51 -0600 Subject: [PATCH 165/170] mm(1): fixes extra file arguments not being unveil(2)ed --- src/mm.rs | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/mm.rs b/src/mm.rs index b99bf9e..d5f1563 100644 --- a/src/mm.rs +++ b/src/mm.rs @@ -76,29 +76,11 @@ 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 */ }, @@ -125,6 +107,25 @@ fn main() -> ExitCode { } if cfg!(target_os="openbsd") { + + for input in &ins { + 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); + } + } + + for output in &outs { + let perms = UnveilPerms::new(vec!['c', 'w']); + + if let Err(e) = unveil(Some(&output), Some(perms)) { + eprintln!("{}: {}", argv[0], e.strerror()); + return ExitCode::from(EX_OSERR as u8); + } + } + if let Err(e) = unveil(None, None) { eprintln!("{}: {}", argv[0], e.strerror()); return ExitCode::from(EX_OSERR as u8); From 821f5d09e9eb41cd38989dc91de958c77157fdee Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 17 Aug 2024 01:51:25 -0600 Subject: [PATCH 166/170] fop(1), hru(1), intcmp(1), mm(1), rpn(1), swab(1): fixes conditional compilation --- src/fop.rs | 2 +- src/hru.rs | 2 +- src/intcmp.rs | 2 +- src/mm.rs | 8 ++++---- src/rpn.rs | 2 +- src/swab.rs | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/fop.rs b/src/fop.rs index 66b7e82..7c8424e 100644 --- a/src/fop.rs +++ b/src/fop.rs @@ -39,7 +39,7 @@ fn main() { let mut d = '\u{1E}'.to_string(); /* ASCII record separator */ let mut optind = 1; - if cfg!(target_os="openbsd") { + #[cfg(target_os="openbsd")] { let promises = Promises::new("stdio proc exec"); if let Err(e) = pledge(Some(promises), None) { eprintln!("{}: {}", argv[0], e.strerror()); diff --git a/src/hru.rs b/src/hru.rs index c6009a7..e07ec39 100644 --- a/src/hru.rs +++ b/src/hru.rs @@ -86,7 +86,7 @@ fn main() -> ExitCode { return ExitCode::from(EX_USAGE as u8); } - if cfg!(target_os="openbsd") { + #[cfg(target_os="openbsd")] { let promises = Promises::new("stdio"); if let Err(e) = pledge(Some(promises), None) { eprintln!("{}: {}", argv[0], e.strerror()); diff --git a/src/intcmp.rs b/src/intcmp.rs index a7c045d..456f268 100644 --- a/src/intcmp.rs +++ b/src/intcmp.rs @@ -42,7 +42,7 @@ fn usage(s: &str) -> ExitCode { fn main() -> ExitCode { let argv = args().collect::>(); - if cfg!(target_os="openbsd") { + #[cfg(target_os="openbsd")] { let promises = Promises::new("stdio"); if let Err(e) = pledge(Some(promises), None) { eprintln!("{}: {}", argv[0], e.strerror()); diff --git a/src/mm.rs b/src/mm.rs index b99bf9e..755c382 100644 --- a/src/mm.rs +++ b/src/mm.rs @@ -51,7 +51,7 @@ fn main() -> ExitCode { let argv = args().collect::>(); let usage = format!("Usage: {} [-aetu] [-i input] [-o output]", argv[0]); - if cfg!(target_os="openbsd") { + #[cfg(target_os="openbsd")] { let promises = Promises::new("rpath stdio unveil"); if let Err(e) = pledge(Some(promises), None) { eprintln!("{}: {}", argv[0], e.strerror()); @@ -77,7 +77,7 @@ fn main() -> ExitCode { Ok("i") => { /* add inputs */ let input = opt.arg().unwrap(); - if cfg!(target_os="openbsd") { + #[cfg(target_os="openbsd")] { let perms = UnveilPerms::new(vec!['r']); if let Err(e) = unveil(Some(&input), Some(perms)) { eprintln!("{}: {}", argv[0], e.strerror()); @@ -91,7 +91,7 @@ fn main() -> ExitCode { Ok("o") => { /* add output */ let output = opt.arg().unwrap(); - if cfg!(target_os="openbsd") { + #[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()); @@ -124,7 +124,7 @@ fn main() -> ExitCode { } } - if cfg!(target_os="openbsd") { + #[cfg(target_os="openbsd")] { if let Err(e) = unveil(None, None) { eprintln!("{}: {}", argv[0], e.strerror()); return ExitCode::from(EX_OSERR as u8); diff --git a/src/rpn.rs b/src/rpn.rs index e4f725d..7669efb 100644 --- a/src/rpn.rs +++ b/src/rpn.rs @@ -198,7 +198,7 @@ fn round_precise(value: &f64, precision: usize) -> f64 { fn main() -> ExitCode { let argv = args().collect::>(); - if cfg!(target_os="openbsd") { + #[cfg(target_os="openbsd")] { let promises = Promises::new("stdio"); if let Err(e) = pledge(Some(promises), None) { eprintln!("{}: {}", argv[0], e.strerror()); diff --git a/src/swab.rs b/src/swab.rs index 27ce9a5..4dc86de 100644 --- a/src/swab.rs +++ b/src/swab.rs @@ -54,7 +54,7 @@ fn usage(s: &str) -> ExitCode { fn main() -> ExitCode { let argv = args().collect::>(); - if cfg!(target_os="openbsd") { + #[cfg(target_os="openbsd")] { let promises = Promises::new("stdio"); if let Err(e) = pledge(Some(promises), None) { return oserr(&argv[0], e); From 71d4d6ba05ee79f38ec7a3779a0e5579159b567a Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 17 Aug 2024 01:57:16 -0600 Subject: [PATCH 167/170] tests: bonsai/dj.mk, bonsai/rpn.mk: fixes testing on linux --- tests/bonsai/dj.mk | 2 +- tests/bonsai/rpn.mk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/bonsai/dj.mk b/tests/bonsai/dj.mk index bf8adf3..2b4ef6b 100755 --- a/tests/bonsai/dj.mk +++ b/tests/bonsai/dj.mk @@ -19,7 +19,7 @@ dj_tests: dj_help dj_full dj_null # dj_skip_stdin dj_full: $(BIN)/dj /dev/full case "$$(uname)" in \ Linux) \ - $(BIN)/dj -Hi /dev/zero -o /dev/full 2>&1 \ + ! $(BIN)/dj -Hi /dev/zero -o /dev/full 2>&1 \ | tee /dev/stderr \ | xargs -I out test '1+0 > 0+0; 1024 > 0' = out \ ;; \ diff --git a/tests/bonsai/rpn.mk b/tests/bonsai/rpn.mk index 3619692..6fecab9 100755 --- a/tests/bonsai/rpn.mk +++ b/tests/bonsai/rpn.mk @@ -30,7 +30,7 @@ rpn_mul: $(BIN)/rpn .PHONY: rpn_div rpn_div: $(BIN)/rpn test "$$($(BIN)/rpn 12 5 /)" = 2.4 - test "$$($(BIN)/rpn 3 0 /)" -eq inf + test "$$($(BIN)/rpn 3 0 /)" = inf .PHONY: rpn_mod rpn_mod: $(BIN)/rpn From e9058803d32629ecc5de2ad96c078a1a8dbdbf3a Mon Sep 17 00:00:00 2001 From: emma Date: Sat, 17 Aug 2024 14:58:56 -0600 Subject: [PATCH 168/170] mm(1): fixes to pledge(2) now; tests: bonsai/mm.mk: adds test for regression --- src/mm.rs | 2 +- tests/bonsai/mm.mk | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/mm.rs b/src/mm.rs index d5f1563..aee9aa2 100644 --- a/src/mm.rs +++ b/src/mm.rs @@ -52,7 +52,7 @@ fn main() -> ExitCode { let usage = format!("Usage: {} [-aetu] [-i input] [-o output]", argv[0]); if cfg!(target_os="openbsd") { - let promises = Promises::new("rpath stdio unveil"); + let promises = Promises::new("cpath rpath stdio unveil wpath"); if let Err(e) = pledge(Some(promises), None) { eprintln!("{}: {}", argv[0], e.strerror()); return ExitCode::from(EX_OSERR as u8); diff --git a/tests/bonsai/mm.mk b/tests/bonsai/mm.mk index 2800460..124d284 100755 --- a/tests/bonsai/mm.mk +++ b/tests/bonsai/mm.mk @@ -1,4 +1,4 @@ -# Copyright (c) 2024 E$(NAME)a Tebibyte +# Copyright (c) 2024 Emma Tebibyte # SPDX-License-Identifier: FSFAP # # Copying and distribution of this file, with or without modification, are @@ -6,7 +6,7 @@ # notice are preserved. This file is offered as-is, without any warranty. .PHONY: mm_tests -mm_tests: mm_args mm_help mm_stderr +mm_tests: mm_args mm_help mm_stderr mm_remaining .PHONY: mm_none mm_none: $(BIN)/mm @@ -25,3 +25,10 @@ mm_help: $(BIN)/mm # check if stderr is empty upon specifying -e mm_stderr: $(BIN)/mm test "$$(printf 'test\n' | $(BIN)/mm -e 2>&1 >/dev/null )" = "test" + +.PHONY: mm_remaining +# check to make sure remaining arguments are used +mm_remaining: $(BIN)/mm + test "$$($(BIN)/mm -i README COPYING)" = "$$(cat README COPYING)" + $(BIN)/mm -i README -o /tmp/mm_test0 /tmp/mm_test1 + diff /tmp/mm_test0 /tmp/mm_test1 From 334433536b6d1c9e4525c5f6f3d850c63951bad6 Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 21 Aug 2024 21:57:10 -0600 Subject: [PATCH 169/170] tests: bonsai/npc.mk: fix harrowing ordeal of a Linux error --- tests/bonsai/npc.mk | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/bonsai/npc.mk b/tests/bonsai/npc.mk index 8b10fdf..8b7f8ea 100755 --- a/tests/bonsai/npc.mk +++ b/tests/bonsai/npc.mk @@ -32,11 +32,30 @@ npc_ascii: npc_ascii_controls npc_ascii_symbols npc_ascii_uppers # \ .PHONY: npc_ascii_controls # (control characters) npc_ascii_controls: + # The following test prints the bytes 0x00 (inclusive) through 0x20 + # (exclusive) and pipes them through npc(1). npc(1) should then replace all + # non-printing, non-space (in the isspace(3p) sense) characters with their + # graphical carat-char counterparts (see the npc(1) man page). The head(1p) + # invocation then strips off everything past the first line (or past the + # first newline byte, 0x0A) and xargs(1p) is used to test(1p) the output + # against the known good answer. + + # Immediately before that newline, 0x09 is printed - in ASCII, the + # horizontal tab. If xargs' -I option is used, tr(1p) should used to delete + # that tab. If the tab is left as part of input, OpenBSD's xargs(1) + # implementation has been observed to strip it along with the other + # trailing whitespace (the newline), but Busybox's and GNU's xargs(1) + # implementations have been observed to leave the tab in. All three + # implementations strip off the trailing tab if `-I` is not used. The POSIX + # specification for `-I` is ambiguous as to which behavior is correct. + # This comment is the result of much bewilderment and debugging. + # 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 + | tr -d '\t' \ + | xargs test "^@^A^B^C^D^E^F^G^H" = # ASCII 0x0a (otherwise the head|tail sequence won't work) to 0x1f awk 'BEGIN{ for (i = 0; i < 32; ++i) printf("%c", i); print }' \ From 579ff65b67518f61a3658942a5df517533004f2f Mon Sep 17 00:00:00 2001 From: DTB Date: Wed, 21 Aug 2024 21:59:22 -0600 Subject: [PATCH 170/170] tests: bonsai/npc.mk: drop redundant tab removal --- tests/bonsai/npc.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/bonsai/npc.mk b/tests/bonsai/npc.mk index 8b7f8ea..b028c4d 100755 --- a/tests/bonsai/npc.mk +++ b/tests/bonsai/npc.mk @@ -54,7 +54,6 @@ npc_ascii_controls: awk 'BEGIN{ for (i = 0; i < 32; ++i) printf("%c", i); }' \ | $(BIN)/npc \ | head -n 1 \ - | tr -d '\t' \ | xargs test "^@^A^B^C^D^E^F^G^H" = # ASCII 0x0a (otherwise the head|tail sequence won't work) to 0x1f