137 Commits

Author SHA1 Message Date
51421b2128 dj.1, strcmp.1, swab.1: remove nonexistent roff macros 2024-06-06 00:14:55 -06:00
28823206bd Merge branch 'docs' (closes #81) 2024-06-05 23:22:57 -06:00
4d27a4976c swab.1: -f Ignores the SIGINT signal 2024-06-05 23:17:21 -06:00
8ce7890124 fop.1: removes Unicode representation of RS; hru.1: removes erroneous line break; mm.1: formatting & grammar; npc.1: dollar sign, not currency sign; rpn.1: syntax error; scrut.1: move description to DESCRIPTION; str.1: comma; swab.1: wording & escape codes; true.1: formatting 2024-06-05 23:07:15 -06:00
526185c2c3 swab.1: typo 2024-06-05 22:35:50 -06:00
ad6f9d565b dj.1: formats sysexits.h(3) reference 2024-06-05 20:39:37 -06:00
f3f3b7f9aa Merge branch 'coc' (closes #100) 2024-06-05 17:35:16 -06:00
d22d90b6ec Merge branch 'fop-delim' (closes #106) 2024-06-05 17:28:51 -06:00
516d10e21d CONDUCT: wording 2024-06-05 17:27:13 -06:00
3392d64e44 fop(1): literal record separator 2024-06-05 17:25:22 -06:00
11b1b424a0 dj.1: more clarification 2024-06-05 17:18:21 -06:00
3c0725f137 dj.1: adds DESCRIPTION and removes seek/skip confusion 2024-06-05 17:15:42 -06:00
46c4be5c59 CONDUCT: no llm contributions 2024-06-04 16:23:27 -06:00
f4cad598c4 docs: formatting 2024-06-04 16:11:33 -06:00
896b251434 hru.1: fixes formatting 2024-06-03 23:52:28 -06:00
fec61fee1b swab.1: fixes formatting 2024-06-03 23:47:14 -06:00
beff2d98c6 mm.1: fixed manpage reference formatting 2024-06-03 23:45:26 -06:00
e7ba74013b dj.1: fixes man page reference formatting 2024-06-03 23:21:00 -06:00
1211524dee Merge branch 'README-updates' 2024-06-03 23:08:02 -06:00
c32c554e03 docs: removed unnecessary comments 2024-06-03 23:07:19 -06:00
d6fb08019e CONDUCT: initial commit 2024-06-02 23:14:40 -06:00
642774bccf src: removed erroneous file 2024-06-02 19:21:56 -06:00
24b235e7c1 README: updated to make current 2024-06-02 19:15:23 -06:00
2dd6c0ded7 fop(1): adds the ability to use any string as a delimiter 2024-06-02 19:05:30 -06:00
70cbc52c93 docs: updates to use man(7) macros to fix formatting 2024-06-02 18:47:14 -06:00
b7f52902b6 dj.1: grammar & formatting 2024-05-24 10:21:06 -06:00
922ee71283 dj.1: fixes standard input section grammar 2024-05-24 10:14:53 -06:00
122a10257e dj.1: fixed option description locations 2024-05-24 10:13:59 -06:00
0660db3d02 dj.1: -c: better description 2024-05-24 10:13:17 -06:00
b4173a2327 dj.1: -o: better description 2024-05-24 10:06:15 -06:00
2137b0bf43 dj.1: -i: better description 2024-05-24 10:03:52 -06:00
d87f4b20a3 dj.1: -A: better description 2024-05-24 09:56:44 -06:00
c53f3fa617 dj.1: remove mention of KiB 2024-05-24 09:53:54 -06:00
432b19818e made dj options no longer alphabetized 2024-04-28 20:42:44 -06:00
9093b06166 Merge branch 'manpage-install' 2024-04-27 12:58:50 -06:00
DTB
6132c9bf47 Merge branch 'main' into scrut-sysexits 2024-04-26 19:37:34 -06:00
DTB
919b171400 scrut(1): conditionally include non-POSIX sysexits.h 2024-04-26 19:35:33 -06:00
DTB
8e38db92c7 scrut(1): update copyright header 2024-04-26 19:33:45 -06:00
DTB
adc9dbded5 scrut(1): changed return status 1 to EXIT_FAILURE 2024-04-26 19:30:33 -06:00
488351da39 scrut(1): changed return status 0 to EXIT_SUCCESS 2024-04-25 16:46:05 -06:00
d8b54fdbf5 Makefile: fixes erroneous whitespace 2024-04-25 12:43:31 -06:00
f6aac60aee Makefile: fixed manpage install location 2024-04-25 12:40:20 -06:00
187d9486b7 dj.1: debug output clarification 2024-04-18 08:44:44 -06:00
b41af1b578 dj.1: -c: grammar 2024-04-18 08:41:55 -06:00
ed284b9949 dj.1: -a: More specific wording 2024-04-18 08:40:29 -06:00
3cdade71e2 dj.1: -S whether or not the input is a stream is irrelevant 2024-04-18 08:38:48 -06:00
df16707b0e intcmp.1: -e permits adjacent integers to be equal to each other 2024-04-18 08:36:01 -06:00
DTB
61382c34d9 mm(1): error out when given positional arguments 2024-03-31 22:54:03 -06:00
8d9ac33566 Merge branch 'strerror' 2024-03-29 19:23:27 -06:00
b503d97625 Makefile: directory specification changes 2024-03-29 19:22:55 -06:00
13ee16173e fop.1: initial commit 2024-03-29 16:47:00 -06:00
5db09a5ca1 mm.1: cat(1p) and tee(1p) provide similar functionality 2024-03-29 16:30:06 -06:00
ce5a4dc4bd mm.1: removed STANDARD INPUT section 2024-03-29 16:29:27 -06:00
abc599148d mm.1: subsequent outputs are opened for appending 2024-03-29 16:26:41 -06:00
63c8ff8093 intcmp.1: compares integers to each other 2024-03-29 16:22:56 -06:00
9ea57a27b7 dj.1: stdin by default 2024-03-29 16:21:02 -06:00
4e33f945ae dj.1: null bytes 2024-03-29 16:17:48 -06:00
70b0c2f924 dj.1: fixed -d description 2024-03-29 16:14:27 -06:00
603d8ee1d8 str.1: remove extraneous former implementation information 2024-03-27 00:17:33 -06:00
cdd8e79b01 str.1: strings are not tested against each other 2024-03-27 00:16:51 -06:00
d3bfc7b1f5 npc.1: ASCII bytes 2024-03-27 00:16:15 -06:00
3cb37d830a mm.1: wording, consistency with dj.1 2024-03-27 00:14:34 -06:00
6158a39a4a dj.1: consistency with mm.1 2024-03-27 00:14:02 -06:00
a2188dc674 dj.1: fix -H description 2024-03-27 00:09:17 -06:00
49e2022e52 dj.1: -d, -i, -o, fixed descriptions 2024-03-27 00:08:43 -06:00
bb43533a37 dj.1: -A and -a: fix descriptions 2024-03-26 23:58:00 -06:00
f565f0530b dj.1: dd(1p) is not a disk utility 2024-03-26 23:53:10 -06:00
a1902df503 strcmp.1: Unicode is a proper noun 2024-03-26 23:50:16 -06:00
b562898a74 copyright 2024-03-27 09:21:19 +05:45
63a0c683f9 docs: remove unnecessary references to the name of each program 2024-03-26 19:22:30 -06:00
cf76fa94e6 mm.1: updated man page 2024-03-26 18:44:05 -06:00
a6fd1108c6 docs: fixed formatting of many manpages 2024-03-26 18:26:51 -06:00
d05d2fae05 Makefile: add a missing build target for npc(1) 2024-03-26 17:19:21 +05:45
d87b5d0958 hru(1), fop(1): changed to reflect strerror changes 2024-03-18 21:31:25 -06:00
1891c3e1aa strerror(3): created strerror() method 2024-03-18 21:30:43 -06:00
127192185f Merge branch 'dj-fix' (closes #66) 2024-03-18 21:01:48 -06:00
f81232685a Merge branch 'mm' 2024-03-18 20:56:06 -06:00
05b5a4480c Merge branch 'swab' (closes #22) 2024-03-18 20:53:08 -06:00
b356ac522f strerror(3): changed panic to 0 2024-03-18 20:45:53 -06:00
b2d56bbc9a Makefile: even more changes 2024-03-09 22:02:19 -07:00
2ad7140e1e Makefile: DESTDIR 2024-03-09 11:53:03 -07:00
8193e471f0 changes redundant .unwrap_or_else(panic!()) to .unwrap() 2024-03-03 17:26:40 -07:00
c392dbc680 Makefile: better deps; fop(1), hru(1), strerror(3): changed strerror wrapper function name 2024-03-02 10:16:32 -07:00
898044cd43 Makefile: better macro assignment 2024-03-01 23:51:36 -07:00
ca01ca4074 rpn(1): remove erroneous strerror(3) dependency 2024-03-01 23:14:58 -07:00
3e6dc5cc46 rpn(1): make error messages consistent with other tools 2024-03-01 23:14:18 -07:00
cf1d16f860 hru(1): changed to use strerror(3) 2024-03-01 23:12:44 -07:00
8f956d775c fop(1): changed to use strerror(3) 2024-03-01 23:10:28 -07:00
e81703c6e1 sterror(3): added library for C-like error messages; Makefile: some efficiency changes 2024-03-01 23:04:53 -07:00
DTB
135bf2a8eb mm(1), mm.1: bring source in line with documentation 2024-02-26 09:11:47 -07:00
DTB
d74bc715cf mm(1): fix full file handling 2024-02-26 09:02:58 -07:00
DTB
f14877118d Makefile: add swab(1) 2024-02-26 08:43:03 -07:00
DTB
bbac85daf8 swab(1): add copyright notice 2024-02-26 08:42:06 -07:00
DTB
1e041a52a2 swab.1: add swab(1) man page 2024-02-24 03:21:20 -07:00
DTB
e788947fc4 swab(1): add argument parsing 2024-02-24 03:04:05 -07:00
c97201fca9 Merge branch 'contributing-changes' 2024-02-23 23:20:16 -07:00
06fc461985 CONTRIBUTING: fixed random "utils" 2024-02-23 23:19:28 -07:00
e6b1db3f40 Merge branch 'hru' (closes #33) 2024-02-23 22:15:43 -07:00
ef1643660b hru(1): fixed lack of newline 2024-02-23 22:11:23 -07:00
b0636b416e Merge branch 'fop-trim' (closes #54, closes #58) 2024-02-23 22:05:56 -07:00
bd08ef479c hru(1): error handling tweaks 2024-02-23 21:58:23 -07:00
3cee3de900 fop(1): committing to Rust error messages 2024-02-23 21:46:50 -07:00
DTB
3f0d95fe8f swab(1): minimum viable program 2024-02-23 20:49:24 -07:00
DTB
58245c9484 dj(1): remove function pointer hijinks (fixes #66) 2024-02-22 19:27:14 -07:00
DTB
395205d4c6 mm.1: fix case in copyright thingy 2024-02-22 19:14:38 -07:00
90de1bf9a4 Makefile: RUSTFLAGS not RUSTCFLAGS 2024-02-18 20:03:04 -07:00
1c2e7ea14b Merge branch 'scrut-manpage' (fixes #49) 2024-02-18 15:20:13 -07:00
0d445c71f4 CONTRIBUTING: fixed wording and updated 2024-02-18 15:09:09 -07:00
ee3877b607 hru.1: update manpage to be more clear 2024-02-18 14:59:12 -07:00
0801d89128 hru(1): fixed kilo prefix 2024-02-18 14:49:09 -07:00
DTB
194b19f94b mm(1): add 2024-02-17 23:43:22 -07:00
DTB
e93745ef28 .editorconfig: remove stale configure config 2024-02-17 23:25:35 -07:00
DTB
abb8fdf935 Merge branch 'scrut-fix' 2024-02-17 23:15:07 -07:00
DTB
de9f8dc037 scrut.1: update man page based on review (see #62) 2024-02-17 23:12:39 -07:00
413ee49af4 hru.1: updated manpage with correct SI reference 2024-02-16 21:36:16 -07:00
dac7567405 Merge branch 'readme-changes' (closes #51 & closes #24) 2024-02-16 21:02:41 -07:00
97382b79fd README: changed dependency section and update copyright 2024-02-16 21:02:00 -07:00
DTB
bee0165074 scrut(1): add man page 2024-02-16 01:40:38 -07:00
DTB
64a1a19bd8 scrut(1): fix buffer overflow in option parsing 2024-02-16 01:13:37 -07:00
cc93389232 README: added cpp(1) as build dep 2024-02-15 17:39:26 -07:00
361f0ddb8b hru.1: added manpage for hru(1) 2024-02-14 23:31:54 -07:00
448211bbe2 fop(1): better newline removal (preserves existing newlines) 2024-02-14 23:05:39 -07:00
4c663bf9dd fop(1): closure fix 2024-02-14 22:55:28 -07:00
f8e3013563 fop(1): fixed trimming and handled unwraps (closes #58) 2024-02-14 22:53:45 -07:00
e3a0069180 hru(1): improved SI prefix logic 2024-02-14 00:07:06 -07:00
1299aefc39 hru(1): fixed overflow 2024-02-13 23:56:01 -07:00
d0205b71da hru(1): read stdin until EOF 2024-02-13 17:48:25 -07:00
1ee668aed6 hru(1): made it actually work 2024-02-13 17:32:31 -07:00
5b364e104e rpn(1): fixed exponentiation 2024-02-13 16:57:29 -07:00
d45e3410f8 CONTRIBUTING: fixed some small issues 2024-02-07 22:03:08 -07:00
452a1295e6 CONTRIBUTING: updated and added copyright info 2024-02-07 21:54:46 -07:00
fa686eefb9 hru(1): updated copyright year 2024-02-07 21:42:43 -07:00
42c5c5642e README: bullets 2024-02-07 21:38:32 -07:00
c753eeea9c README: added build information and copyright 2024-02-07 21:27:43 -07:00
be89e72c45 Makefile, hru(1): add hru(1) 2024-02-07 20:58:57 -07:00
d3470233ea Makefile, .gitignore, tests/cc-compat.sh: brought up-to-date 2024-02-07 20:13:45 -07:00
3e39739e88 Makefile: added rpn to all 2024-02-07 19:42:11 -07:00
28 changed files with 1523 additions and 471 deletions

View File

@@ -12,6 +12,3 @@ indent_size = 2
[*.sh] [*.sh]
indent_size = 2 indent_size = 2
[configure]
indent_size = 2

1
.gitignore vendored
View File

@@ -1,3 +1,2 @@
build/ build/
dist/ dist/
*.mk

83
CONDUCT Normal file
View File

@@ -0,0 +1,83 @@
Code of Conduct
This Code of Conduct is derived from the 10 Pāramitās of Theravadin Buddhism.
You can read more about them in Ṭhānissaro Bhikkhus Ten Perfections: A Study
Guide [0].
1. Generosity (Dāna)
Give contributions freely and willingly under the terms of the GNU Affero
General Public License, version 3 or later, or a compatible license.
2. Ethics (Sīla)
Do not use nonfree code or uncredited code in contributions. Do not contribute
code of dubious origins, such as code generated by large language models or
unlicensed snippets found online [1]. Do not take credit for others
contributions. Make sure to utilize the copyright header and license notice on
source files to credit yourself and others for their work.
3. Renunciation (Nekkhamma)
Stay committed to the principles of simplicity and interoperability embodied by
the project. Keep your personal will and desire out of the project, for it can
only prove harmful to its success.
4. Wisdom (Pañña)
Look to established sources for standards, best practices, and important
implementation details when setting new precedence. Follow the existing
precedence where it applies.
5. Energy (Viriya)
Focus on the currently-open, currently-assigned, and currently-in-progress
issues, pull requests, and other endeavors in order to keep yourself and others
from being overwhelmed with responsibility, either from your zeal or your
negligence.
If you notice an issue, open an issue as soon as you can. If you see a neglected
branch, open a pull request or comment on an existing one, if applicable. Be
diligent in your commitment to making this project work.
6. Patience (Khanti)
Be patient with maintainers and other contributors. We all have our own lives
going on and may need significant time to get to things.
7. Truthfulness (Sacca)
Communicate honestly and openly. Do not embellish facts to get your way. Make
sure to let maintainers know about any issues along the way and keep ample
communication channels open.
8. Determination (Adhiṭṭhāna)
Stay focused on long-term objectives and cultivate attainment to that
achievement by utilizing to the fullest extent possible the tools available to
you for managing the workload.
9. Loving-Kindness (Mettā)
Treat everyone with respect, even if they treat you poorly. This does not mean
you have to put up with abuse, but make sure to respond with kindness and with
love in your heart. Support and uplift maintainers and other contributors with
your words and actions.
Do not use angry or hateful language toward contributors, such as demeaning
phrases and slurs. Make sure that if you do not know the pronouns of a
contributor to ask for them and, in the meantime, use gender-neutral they/them
or equivalent pronouns.
10. Equanimity (Upekkhā)
Keep a balanced perspective on all suggestions and contributions and make
judgements not from a place of ego and personal preference but on their
usefulness and suitability to the project. Make sure to keep an eye on the
bigger picture as implementing individual features may seem intuitive at first
but scale poorly in practical use. Keep a level head about your own work: it is
not shameful to make a mistake in this vein, and fixing it usually leads to
more insight.
[0] <https://www.dhammatalks.org/books/#/books/TenPerfections/Section0001.html>
[1] <https://www.fsf.org/news/publication-of-the-fsf-funded-white-papers-on-questions-around-copilot>

View File

@@ -1,3 +1,5 @@
Make sure to read our code of conduct in the CONDUCT file.
When contributing a pull request to the main branch, please sign your commits When contributing a pull request to the main branch, please sign your commits
with a PGP key and add your name and the year to the bottom of the list of with a PGP key and add your name and the year to the bottom of the list of
copyright holders for the file. For example, an existing copyright header might copyright holders for the file. For example, an existing copyright header might
@@ -90,26 +92,44 @@ notice:
* USE OR OTHER DEALINGS IN THE SOFTWARE. * USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
When writing code, make sure lines never exceed 80 characters in width when Make sure lines never exceed 80 columns in width when using four-character
using four-character-wide indentation steps. indentation steps. This helps contributors with smaller screens, those using
side-by-side editor windows or panes, and those who have no text wrapping in
their editor or terminal.
For usage text and help messages, please do not implement a -h option. Just For usage text and help messages, do not implement a -h option. Instead, print
print usage information when any erroneous option is specified. Follow the usage information when any erroneous option is specified. Follow the NetBSD
NetBSD style guide for usage text output format [1]. style guide for the usage texts output format [1].
If committing a new source file for a utility, format the commit message like [1] <http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/share/misc/style>
this:
$ git commit -m 'tool(1): <information>' If committing a new source file, format the commit message following these
guidelines:
$ git commit -m 'tool(1): add feature x'
If committing a new library or header file: If committing a new library or header file:
$ git commit -m 'library(1): <information>' $ git commit -m 'library(3): fix overflow'
$ git commit -m 'header.h(3): add header.h(3)'
If committing a new manual page:
$ git commit -m 'tool.1: add author details'
If modifying some other file or directory: If modifying some other file or directory:
$ git commit -m 'README: clarification' $ git commit -m 'README: clarify'
$ git commit -m 'tests: posix: fixed bug #47' $ git commit -m 'tests/posix: fix bug #47'
$ git commit -m 'docs: tool(1): added author information'
etc. For multiple of these:
$ git commit -m 'Makefile, tool(1): add tool(1)'
$ git commit -m 'tool(1): add tool(1); library(3), library.3: add library(3)'
$ git commit -m 'tool(1): fix #42 & add feature x'
Commit messages should be written in the present tense.
--
This work © 20232024 by Emma Tebibyte is licensed under CC BY-SA 4.0. To view a
copy of this license, visit <http://creativecommons.org/licenses/by-sa/4.0/>

View File

@@ -1,6 +1,7 @@
# Copyright (c) 20232024 Emma Tebibyte <emma@tebibyte.media> # Copyright (c) 20232024 Emma Tebibyte <emma@tebibyte.media>
# Copyright (c) 20232024 DTB <trinity@trinity.moe> # Copyright (c) 20232024 DTB <trinity@trinity.moe>
# Copyright (c) 2023 Sasha Koshka <sashakoshka@tebibyte.media> # Copyright (c) 2023 Sasha Koshka <sashakoshka@tebibyte.media>
# Copyright (c) 2024 Aaditya Aryal <aryalaadi123@gmail.com>
# SPDX-License-Identifier: FSFAP # SPDX-License-Identifier: FSFAP
# #
# Copying and distribution of this file, with or without modification, are # Copying and distribution of this file, with or without modification, are
@@ -8,16 +9,28 @@
# notice are preserved. This file is offered as-is, without any warranty. # notice are preserved. This file is offered as-is, without any warranty.
.POSIX: .POSIX:
# if using BSD make(1), remove these pragmas because they break it
.PRAGMA: posix_202x # future POSIX standard support à la pdpmake(1) .PRAGMA: posix_202x # future POSIX standard support à la pdpmake(1)
.PRAGMA: command_comment # breaks without this? .PRAGMA: command_comment # breaks without this?
PREFIX=/usr/local DESTDIR ?= dist
PREFIX ?= /usr/local
CC=cc MANDIR != [ $(PREFIX) = / ] && printf '/usr/share/man\n' \
RUSTC=rustc || printf '/share/man\n'
SYSEXITS != printf '\043include <sysexits.h>\n' | cpp -M - | sed 's/ /\n/g' \
| sed -n 's/sysexits\.h//p' || printf 'include\n'
CC ?= cc
RUSTC ?= rustc
RUSTLIBS = --extern getopt=build/o/libgetopt.rlib \
--extern sysexits=build/o/libsysexits.rlib \
--extern strerror=build/o/libstrerror.rlib
CFLAGS += -I$(SYSEXITS)
.PHONY: all .PHONY: all
all: dj false fop intcmp scrut str strcmp true all: dj false fop hru intcmp mm npc rpn scrut str strcmp swab true
build: build:
# keep build/include until bindgen(1) has stdin support # keep build/include until bindgen(1) has stdin support
@@ -26,37 +39,40 @@ build:
.PHONY: clean .PHONY: clean
clean: clean:
rm -rf build/ dist/ rm -rf build dist
dist: all dist: all
mkdir -p dist/bin dist/share/man/man1 mkdir -p $(DESTDIR)/$(PREFIX)/bin $(DESTDIR)/$(PREFIX)/share/man/man1
cp build/bin/* dist/bin/ cp build/bin/* $(DESTDIR)/$(PREFIX)/bin
cp docs/*.1 dist/share/man/man1/ cp docs/*.1 $(DESTDIR)/$(PREFIX)/$(MANDIR)/man1
.PHONY: install .PHONY: install
install: dist install: dist
mkdir -p $(PREFIX) cp -r $(DESTDIR)/* /
cp -r dist/* $(PREFIX)/
.PHONY: test .PHONY: test
test: build test: build
tests/cc-compat.sh
tests/posix-compat.sh tests/posix-compat.sh
$(RUSTC) --test src/getopt-rs/lib.rs -o build/test/getopt $(RUSTC) --test src/getopt-rs/lib.rs -o build/test/getopt
build/o/libsysexits.rlib: build .PHONY: rustlibs
rustlibs: build/o/libsysexits.rlib build/o/libgetopt.rlib \
build/o/libstrerror.rlib
build/o/libgetopt.rlib: build src/getopt-rs/lib.rs
$(RUSTC) $(RUSTFLAGS) --crate-type=lib --crate-name=getopt \
-o $@ src/getopt-rs/lib.rs
build/o/libstrerror.rlib: build src/strerror.rs
$(RUSTC) $(RUSTFLAGS) --crate-type=lib -o $@ \
src/strerror.rs
build/o/libsysexits.rlib: build $(SYSEXITS)sysexits.h
# bandage solution until bindgen(1) gets stdin support # bandage solution until bindgen(1) gets stdin support
printf '#define EXIT_FAILURE 1\n' | cat - include/sysexits.h \ printf '#define EXIT_FAILURE 1\n' | cat - $(SYSEXITS)sysexits.h \
> build/include/sysexits.h > build/include/sysexits.h
bindgen --default-macro-constant-type signed --use-core --formatter=none \ bindgen --default-macro-constant-type signed --use-core --formatter=none \
"$$(printf '#include <sysexits.h>\n' \ build/include/sysexits.h | $(RUSTC) $(RUSTFLAGS) --crate-type lib -o $@ -
| cpp -M -idirafter "build/include" - \
| sed 's/ /\n/g' | grep sysexits.h)" \
| $(RUSTC) $(RUSTFLAGS) --crate-type lib -o build/o/libsysexits.rlib -
build/o/libgetopt.rlib: src/getopt-rs/lib.rs
$(RUSTC) $(RUSTCFLAGS) --crate-type=lib --crate-name=getopt \
-o build/o/libgetopt.rlib src/getopt-rs/lib.rs
.PHONY: dj .PHONY: dj
dj: build/bin/dj dj: build/bin/dj
@@ -70,22 +86,33 @@ build/bin/false: src/false.c build
.PHONY: fop .PHONY: fop
fop: build/bin/fop fop: build/bin/fop
build/bin/fop: src/fop.rs build build/o/libgetopt.rlib build/o/libsysexits.rlib build/bin/fop: src/fop.rs build rustlibs
$(RUSTC) $(RUSTFLAGS) --extern getopt=build/o/libgetopt.rlib \ $(RUSTC) $(RUSTFLAGS) $(RUSTLIBS) -o $@ src/fop.rs
--extern sysexits=build/o/libsysexits.rlib \
-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
.PHONY: intcmp .PHONY: intcmp
intcmp: build/bin/intcmp intcmp: build/bin/intcmp
build/bin/intcmp: src/intcmp.c build build/bin/intcmp: src/intcmp.c build
$(CC) $(CFLAGS) -o $@ src/intcmp.c $(CC) $(CFLAGS) -o $@ src/intcmp.c
.PHONY: mm
mm: build/bin/mm
build/bin/mm: src/mm.c build
$(CC) $(CFLAGS) -o $@ src/mm.c
.PHONY: npc
npc: build/bin/npc
build/bin/npc: src/npc.c build
$(CC) $(CFLAGAS) -o $@ src/npc.c
.PHONY: rpn .PHONY: rpn
rpn: build/bin/rpn rpn: build/bin/rpn
build/bin/rpn: src/rpn.rs build build/o/libsysexits.rlib build/bin/rpn: src/rpn.rs build rustlibs
$(RUSTC) $(RUSTFLAGS) \ $(RUSTC) $(RUSTFLAGS) $(RUSTLIBS) -o $@ src/rpn.rs
--extern sysexits=build/o/libsysexits.rlib \
-o $@ src/rpn.rs
.PHONY: scrut .PHONY: scrut
scrut: build/bin/scrut scrut: build/bin/scrut
@@ -102,6 +129,13 @@ strcmp: build/bin/strcmp
build/bin/strcmp: src/strcmp.c build build/bin/strcmp: src/strcmp.c build
$(CC) $(CFLAGS) -o $@ src/strcmp.c $(CC) $(CFLAGS) -o $@ src/strcmp.c
.PHONY: swab
swab: build/bin/swab
build/bin/swab: src/swab.rs build build/o/libsysexits.rlib
$(RUSTC) $(RUSTFLAGS) --extern getopt=build/o/libgetopt.rlib \
--extern sysexits=build/o/libsysexits.rlib \
-o $@ src/swab.rs
.PHONY: true .PHONY: true
true: build/bin/true true: build/bin/true
build/bin/true: src/true.c build build/bin/true: src/true.c build

32
README
View File

@@ -17,6 +17,31 @@ purposes beyond its scope.
See docs/ for more on the specific utilities currently implemented. See docs/ for more on the specific utilities currently implemented.
Building
The coreutils require a POSIX-compliant environment to compile, including a C
compiler and preprocessor (cc(1) and cpp(1) by default), an edition 2023 Rust
compiler (rustc(1) by default), bindgen(1), and a POSIX-compliant make(1)
utility.
To build and install:
$ make
$ make PREFIX="/your/preferred/location" install
To build with a different compiler than the default:
$ make CC=clang
$ make RUSTC=gccrs
To test the utilities:
$ make test
To remove all untracked files:
$ make clean
Read More Read More
An Introduction to the Unix Shell An Introduction to the Unix Shell
@@ -30,3 +55,10 @@ Master Foo Discourses on the Unix-Nature
Shell Programming! Shell Programming!
<https://tldp.org/LDP/abs/html/why-shell.html> <https://tldp.org/LDP/abs/html/why-shell.html>
--
Copyright © 20232024 Emma Tebibyte <emma@tebibyte.media>
Copyright © 2024 DTB <trinity@trinity.moe>
This work is licensed under CC BY-SA 4.0. To view a copy of this license, visit
<http://creativecommons.org/licenses/by-sa/4.0/>.

250
docs/dj.1
View File

@@ -1,14 +1,13 @@
.\" Copyright (c) 2024 DTB <trinity@trinity.moe> .\" Copyright (c) 2024 DTB <trinity@trinity.moe>
.\" Copyright (c) 2024 Emma Tebibyte <emma@tebibyte.media>
.\" .\"
.\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license,
.\" visit <http://creativecommons.org/licenses/by-sa/4.0/>. .\" visit <http://creativecommons.org/licenses/by-sa/4.0/>.
.\"
.TH dj 1 .TH DJ 1
.SH NAME .SH NAME
dj \(en disk jockey dj \(en disk jockey
.\"
.SH SYNOPSIS .SH SYNOPSIS
dj dj
@@ -19,142 +18,167 @@ dj
.RB [ count ]) .RB [ count ])
.RB ( -i .RB ( -i
.R [ [\fBinput file\fP])
.B input file
.R ])
.RB ( -b .RB ( -b
.R [ [\fBinput block size\fP])
.B input block size
.R ])
.RB ( -s .RB ( -s
.R [ [\fBinput offset\fP])
.B input offset
.R ])
.RB ( -o .RB ( -o
.R [ [\fBoutput file\fP])
.B output file
.R ])
.RB ( -B .RB ( -B
.R [ [\fBoutput block size\fP])
.B output block size
.R ])
.RB ( -S .RB ( -S
.R [ [\fBoutput offset\fP])
.B output offset .\"
.R ]) .SH DESCRIPTION
.SH USAGE Perform precise read and write operations on files. This utility is useful for
reading and writing binary data to and from disks, hence the name.
The This manual page uses the terms \(lqskip\(rq and \(lqseek\(rq to refer to moving
.B -i to a specified byte by index in the input and output of the program
option takes a path as an argument to open and use in place of standard input. respectively. This language is inherited from the
The .BR dd (1p)
.B -o utility and is used here to decrease ambiguity.
option does the same in place of standard output. Dj does not truncate output
files and instead writes over the bytes in the existing file. When seeking or skipping to a byte, writing or reading starts at the byte
.PP immediately subsequent to the specified byte.
The .\"
.SH OPTIONS
.IP \fB-i\fP
Takes a file path as an argument and opens it for use as an input.
.IP \fB-b\fP
Takes a numeric argument as the size in bytes of the input buffer, with the
default being 1024.
.IP \fB-s\fP
Takes a numeric argument as the number of bytes to skip into the input
before starting to read. If the standard input is used, bytes read to this point
are discarded.
.IP \fB-o\fP
Takes a file path as an argument and opens it for use as an output.
.IP \fB-B\fP
Does the same as
.B -b .B -b
option takes a numeric argument as the size in bytes of the input buffer and but for the output buffer.
the .IP \fB-S\fP
.B -B Seeks a number of bytes through the output before starting to write from
option does the same for the output buffer, the default for both being 1024 the input. If the output is a stream, null characters are printed.
bytes, or one kibibyte (KiB). .IP \fB-a\fP
.PP Accepts a single literal byte with which input buffer is padded in the event
The of an incomplete read from the input file.
.B -s .IP \fB-A\fP
option takes a numeric argument as the number of bytes to skip into the input Specifying this option pads the input buffer with null bytes in the event of an
before starting to read, and the incomplete read. Equivalent to specifying
.B -S
option skips a number of bytes through the output before starting to write from
the input. If the input is a stream the bytes are read and discarded. If the
output is a stream, nul characters are printed.
.PP
The
.B -a .B -a
option takes one argument of one byte in length and pads the input buffer with with a null byte instead of a character.
that byte in the event that a read doesn't fill the input buffer, and the .IP \fB-c\fP
.B -A Specifies a number of reads to make. The default is zero, in which case the
option takes no arguments and pads with nuls. input is read until a partial or empty read is made.
The .IP \fB-d\fP
.B -c Prints invocation information before program execution as described in the
option specifies an amount of reads to make, and if 0 (the default) dj will DIAGNOSTICS section below. Each invocation increments the debug level of the
continue reading until a partial or empty read. program.
.PP .IP \fB-H\fP
On a partial or empty read, dj prints a diagnostic message (unless the Prints diagnostics messages in a human-readable manner as described in the
.B -q DIAGNOSTICS section below.
option is specified) and exits (unless the .IP \fB-n\fP
.B -n Retries failed reads once more before exiting.
option is specified, in which case only two consecutive empty reads will cause .IP \fB-q\fP
dj to exit). Suppresses error messages which print when a read or write is partial or
At exit, usage statistics are printed unless the option empty. Each invocation decrements the debug level of the program.
.B -q .\"
is specified a second time. The .SH STANDARD INPUT
.B -H
option will make these diagnostics human-readable.
The standard input shall be used as an input if no inputs are specified or if
one or more of the input files is \(lq-\(rq.
.\"
.SH DIAGNOSTICS .SH DIAGNOSTICS
The On a partial or empty read, a diagnostic message is printed (unless the
.B -d
option prints all information, user-specified or otherwise, before program
execution.
.PP
When dj exits, by default statistics are printed for input and output to
standard error in the following format:
.PP
.R {records read} {ASCII unit separator} {partial records read}
.R {ASCII record separator} {records written} {ASCII unit separator}
.R {partial records written} {ASCII group separator} {bytes read}
.R {ASCII record separator} {bytes written} {ASCII file separator}
.PP
If the
.B -H
option is specified dj instead uses this following format:
.PP
.R {records read} '+' {partial records read} '>' {records written}
.R '+' {partial records written} ';' {bytes read} '>' {bytes written}
.R {ASCII line feed}
.PP
The
.B -q .B -q
option suppresses error messages which print when a read or write is partial or option is specified) and the program exits (unless the
empty and when used twice suppresses diagnostic output entirely. .B -n
.PP option is specified).
In non-recoverable errors that don't pertain to dj's read-write cycle, a
diagnostic message is printed and dj exits with the appropriate sysexits(3)
status.
By default, statistics are printed for input and output to the standard error in
the following format:
.RS
{records read} {ASCII unit separator} {partial records read}
{ASCII record separator} {records written} {ASCII unit separator}
{partial records written} {ASCII group separator} {bytes read}
{ASCII record separator} {bytes written} {ASCII file separator}
.RE
This format for diagnostic output is designed to be machine-parseable for
convenience. For a more human-readable format, the
.B -H
option may be specified. In this event, the following format is used instead:
.RS
{records read} '+' {partial records read} '>' {records written}
'+' {partial records written} ';' {bytes read} '>' {bytes written}
{ASCII line feed}
.RE
If the
.B -d
option is specified, debug output will be printed at the beginning of
execution. This debug information contains information regarding how the program
was invoked. The following example is the result of running the program with
.B -d
as the only argument:
.RS
argv0=dj
in=<stdin> ibs=1024 skip=0 align=ff count=0
out=<stdout> obs=1024 seek=0 debug= 3 noerror=0
.RE
In non-recoverable errors that don\(cqt pertain to the read-write cycle, a
diagnostic message is printed and the program exits with the appropriate
.BR sysexits.h (3)
status.
.\"
.SH BUGS .SH BUGS
If If
.B -n .B -n
is specified along with a specified count, actual byte output may be lower than is specified along with the
expected (the product of the count multiplied by the input block size). If the .B -c
option and a count, actual byte output may be lower than expected (the product
of the count and the input block size). If the
.B -a .B -a
or or
.B -A .B -A
options are used this could make data written nonsensical. options are used, this could make data written nonsensical.
.PP .\"
.SH CAVEATS
Existing files are not truncated on ouput and are instead overwritten.
Many lowercase options have capitalized variants and vice-versa which can be Many lowercase options have capitalized variants and vice-versa which can be
confusing. Capitalized options tend to affect output or are more intense confusing. Capitalized options tend to affect output or are more intense
versions of lowercase options. versions of lowercase options.
.\"
.SH RATIONALE .SH RATIONALE
Dj was modeled after the dd utility specified in POSIX but adds additional This program was based on the
features: typical option formatting, allowing seeks to be specified in bytes .BR dd (1p)
rather than in blocks, allowing arbitrary bytes as padding, and printing in a utility as specified in POSIX. While character conversion may have been the
format that's easy to parse for machines. It also neglects character original intent of
conversion, which may be dd's original intent but is irrelevant to its modern .BR dd (1p),
use. it is irrelevant to its modern use. Because of this, this program eschews
character conversion and adds typical option formatting, allowing seeks to be
specified in bytes rather than in blocks, allowing arbitrary bytes as padding,
and printing in a format that\(cqs easy for machines to parse.
.\"
.SH COPYRIGHT .SH COPYRIGHT
Copyright (C) 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later Copyright \(co 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later
<https://gnu.org/licenses/agpl.html>. <https://gnu.org/licenses/agpl.html>.
.\"
.SH SEE ALSO .SH SEE ALSO
.BR dd (1p)
dd(1)

View File

@@ -1,35 +1,35 @@
.\" Copyright (c) 2022, 2024 DTB <trinity@trinity.moe> .\" Copyright (c) 2022, 2024 DTB <trinity@trinity.moe>
.\" Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media> .\" Copyright (c) 20232024 Emma Tebibyte <emma@tebibyte.media>
.\" .\"
.\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license,
.\" visit <http://creativecommons.org/licenses/by-sa/4.0/>. .\" visit <http://creativecommons.org/licenses/by-sa/4.0/>.
.\"
.TH FALSE 1 .TH FALSE 1
.SH NAME .SH NAME
false \(en do nothing, unsuccessfully false \(en do nothing, unsuccessfully
.\"
.SH DESCRIPTION .SH DESCRIPTION
False does nothing regardless of operands or standard input. Do nothing regardless of operands or standard input. An exit code of 1 will
False will always return an exit code of 1. always be returned.
.\"
.SH RATIONALE .SH RATIONALE
False exists for the construction of control flow and loops based on a failure. In POSIX.1-2017,
.BR false (1p)
False functions as described in POSIX.1-2017. exists for the construction of control flow and loops based on a failure. This
implementation functions as described in that standard.
.\"
.SH AUTHOR .SH AUTHOR
Written by Emma Tebibyte <emma@tebibyte.media>. Written by Emma Tebibyte
.MT emma@tebibyte.media
.ME .
.\"
.SH COPYRIGHT .SH COPYRIGHT
This work is marked with CC0 1.0. To see a copy of this license, visit This work is marked with CC0 1.0. To see a copy of this license, visit
<http://creativecommons.org/publicdomain/zero/1.0>. <http://creativecommons.org/publicdomain/zero/1.0>.
.\"
.SH SEE ALSO .SH SEE ALSO
.BR true (1p)
true(1p)

60
docs/fop.1 Normal file
View File

@@ -0,0 +1,60 @@
.\" Copyright (c) 2024 DTB <trinity@trinity.moe>
.\" Copyright (c) 2024 Emma Tebibyte <emma@tebibyte.media>
.\"
.\" This work is licensed under CC BY-SA 4.0. To see a copy of this license,
.\" visit <http://creativecommons.org/licenses/by-sa/4.0/>.
.\"
.TH fop 1
.SH NAME
fop \(en field operator
.\"
.SH SYNOPSIS
fop
.RB ( -d )
.RB [ delimiter ]
.RB index
.RB program...
.\"
.SH DESCRIPTION
Performs operations on specified fields in input data.
.\"
.SH OPTIONS
.IP \fB-d\fP
Sets a delimiter by which the input data will be split into fields. The default
is an ASCII record separator.
.\"
.SH STANDARD INPUT
Data will be read from the standard input.
.\"
.SH CAVEATS
Field indices are zero-indexed, which may be unexpected behavior for some users.
.\"
.SH RATIONALE
With the assumption that tools will output data separated with ASCII field
separators, there is a need for the ability to modify select fields in this data
easily and quickly.
The idea for this utility originated in the fact that the GNU
.BR ls (1)
utility contains a
.B -h
option which enables human-readable units in file size outputs. This
functionality was broken out into
.BR hru (1),
but there was no easy way to modify the field in the ouput of
.BR ls (1p)
without creating a new tool.
.\"
.SH COPYRIGHT
Copyright \(co 2024 Emma Tebibyte. License AGPLv3+: GNU AGPL version 3 or later
<https://gnu.org/licenses/agpl.html>.
.\"
.SH SEE ALSO
.BR sed (1p)

67
docs/hru.1 Normal file
View File

@@ -0,0 +1,67 @@
.\" Copyright (c) 2024 Emma Tebibyte <emma@tebibyte.media>
.\"
.\" This work is licensed under CC BY-SA 4.0. To see a copy of this license,
.\" visit <http://creativecommons.org/licenses/by-sa/4.0/>.
.\"
.TH HRU 1
.SH NAME
hru \(en human readable units
.\"
.SH SYNOPSIS
hru
.\"
.SH DESCRIPTION
Convert counts to higher units.
The program will read byte counts in the form of whole numbers from the standard
input and write to the standard output the same number converted to a higher
unit of data as defined by the International System of Units.
The program will convert the byte count to the highest unit possible where the
value is greater than one.
.\"
.SH DIAGNOSTICS
If encountering non-integer characters in the standard input, the program will
exit with the appropriate error code as defined by
.BR sysexits.h (3)
and print an error message.
.\"
.SH RATIONALE
The GNU project\(cqs
.BR ls (1)
implementation contains a human-readable option (\fB-h\fP) that, when specified,
makes the tool print size information in a format more immediately
readable. This functionality is useful not only in the context of
.BR ls (1)
so the decision was made to split it into a new tool. The original functionality
in GNU\(cqs
.BR ls (1)
can be emulated with
.BR fop (1)
combined with this program.
.\"
.SH STANDARDS
The standard unit prefixes as specified by the Bureau International des Poids
et Mesures (BIPM) in the ninth edition of The International System of Units (SI)
are utilized for the ouput of conversions.
.\"
.SH AUTHOR
Written by Emma Tebibyte
.MT emma@tebibyte.media
.ME .
.\"
.SH COPYRIGHT
Copyright \(co 2024 Emma Tebibyte. License AGPLv3+: GNU AGPL version 3 or later
<https://gnu.org/licenses/agpl.html>.
.\"
.SH SEE ALSO
GNU
.BR ls (1),
The International System of Units (SI) 9th Edition

View File

@@ -1,78 +1,92 @@
.\" Copyright (c) 20232024 DTB <trinity@trinity.moe> .\" Copyright (c) 20232024 DTB <trinity@trinity.moe>
.\" Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media> .\" Copyright (c) 20232024 Emma Tebibyte <emma@tebibyte.media>
.\" .\"
.\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license,
.\" visit <http://creativecommons.org/licenses/by-sa/4.0/>. .\" visit <http://creativecommons.org/licenses/by-sa/4.0/>.
.\"
.TH intcmp 1 .TH INTCMP 1
.SH NAME .SH NAME
intcmp \(en compare integers intcmp \(en compare integers
.\"
.SH SYNOPSIS .SH SYNOPSIS
intcmp intcmp
.RB ( -eghl ) .RB ( -egl )
.RB [ integer ] .RB [ integer ]
.RB [ integer... ] .RB [ integer... ]
.SH DESCRIPTION .SH DESCRIPTION
Compare integers to each other.
.\"
.SH OPTIONS
Intcmp compares integers. .IP \fB-e\fP
Permits given integers to be equal to each other.
.IP \fB-g\fP
Permits a given integer to be greater than the following integer.
.IP \fB-l\fP
Permits a given integer to be less than the following integer.
.\"
.SH EXAMPLES
.SH USAGE
The -e option permits given integers to be equal to each other. If combined
with -g or -l, only adjacent integers in the argument sequence can be equal.
.PP
The -g option permits a given integer to be greater than the following integer.
.PP
The -l option permits a given integer to be less than the following integer.
.PP
It may help to think of the -e, -g, and -l options as equivalent to the It may help to think of the -e, -g, and -l options as equivalent to the
infix algebraic “=”, “>”, and “<” operators respectively, with each option infix algebraic \(lq=\(rq, \(lq>\(rq, and \(lq<\(rq operators respectively, with
putting its symbol between every given integer. For example, each option putting its symbol between every given integer. The following
example is equivalent to evaluating \(lq1 < 2 < 3\(rq:
\"
.RS
.R intcmp -l 1 2 3 .R intcmp -l 1 2 3
is equivalent to evaluating "1 < 2 < 3". .RE
.\"
.SH DIAGNOSTICS .SH DIAGNOSTICS
Intcmp exits 0 for a valid expression and 1 for an invalid expression. The program will exit with a status code of 0 for a valid expression and with a
.PP code of 1 for an invalid expression.
Intcmp prints a debug message and exits with the appropriate sysexits(3) error
code in the event of an error.
In the event of an error, a debug message will be printed and the program will
exit with the appropriate
.BR sysexits.h (3)
error code.
.\"
.SH BUGS .SH BUGS
There are multiple ways to express compound comparisons; “less than or equal -egl, \(lqequal to or less than or greater than\(rq, exits 0 no matter what for
to” can be -le or -el, for example. valid program usage and may be abused to function as an integer validator. Use
.PP .BR str (1)
The inequality comparison is -gl or -lg for “less than or greater than”; this instead.
is elegant but unintuitive. .\"
.PP .SH CAVEATS
-egl, "equal to or less than or greater than", exits 0 no matter what for valid
program usage and may be abused to function as an integer validator.
Use str(1) instead.
There are multiple ways to express compound comparisons; \(lqless than or equal
to\(rq can be -le or -el, for example.
The inequality comparison is -gl or -lg for \(lqless than or greater than\(rq;
this is elegant but unintuitive.
.\"
.SH RATIONALE .SH RATIONALE
The traditional tool for integer comparisons in POSIX and other Unix shells has The traditional tool for integer comparisons in POSIX and other Unix shells has
been test(1). This tool also handles string comparisons and file scrutiny. been
These parts of its functionality have been broken out into multiple utilities. .BR test (1).
This tool also handles string comparisons and file scrutiny. These parts of its
Strcmps functionality may be performed on a POSIX-compliant system with functionality have been broken out into multiple utilities.
test(1p).
This program\(cqs functionality may be performed on a POSIX-compliant system
with
.BR test (1p).
.\"
.SH AUTHOR .SH AUTHOR
Written by DTB <trinity@trinity.moe>. Written by DTB
.MT trinity@trinity.moe
.ME .
.\"
.SH COPYRIGHT .SH COPYRIGHT
.\"
Copyright © 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later Copyright \(co 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later
<https://gnu.org/licenses/gpl.html>. <https://gnu.org/licenses/gpl.html>.
.\"
.SH SEE ALSO .SH SEE ALSO
.BR scrut (1),
strcmp(1), scrut(1), str(1), test(1p) .BR strcmp (1),
.BR str (1),
.BR test (1p)

73
docs/mm.1 Normal file
View File

@@ -0,0 +1,73 @@
.\" Copyright (c) 2024 DTB <trinity@trinity.moe>
.\"
.\" This work is licensed under CC BY-SA 4.0. To see a copy of this license,
.\" visit <http://creativecommons.org/licenses/by-sa/4.0/>.
.\"
.TH mm 1
.SH NAME
mm \(en middleman
.\"
.SH SYNOPSIS
mm
.RB ( -aenu )
.RB ( -i
.RB [ input ])
.RB ( -o
.RB [ output ])
.\"
.SH DESCRIPTION
Catenate input files and write them to the start of each output file or stream.
.\"
.SH OPTIONS
.IP \fB-a\fP
Opens subsequent outputs for appending rather than updating.
.IP \fB-e\fP
Use the standard error as an output.
.IP \fB-i\fP
Opens a path as an input. If one or more of the input files is \(lq-\(rq or if
no inputs are specified, the standard input shall be used.
.IP \fB-o\fP
Opens a path as an output. If one or more of the output files is \(lq-\(rq or if
no outputs are specified, the standard output shall be used.
.IP \fB-u\fP
Ensures neither input or output will be buffered.
.IP \fB-n\fP
Causes SIGINT signals to be ignored.
.\"
.SH DIAGNOSTICS
If an output cannot be written to, an error occurs. Additional outputs are not
affected and writing to them continues.
When an error is encountered, a diagnostic message is printed and the program
exits with the appropriate
.BR sysexits.h (3)
status.
.\"
.SH CAVEATS
Existing files are not truncated on ouput and are instead overwritten.
.\"
.SH RATIONALE
The
.BR cat (1p)
and
.BR tee (1p)
programs specified in POSIX together provide similar functionality. The
separation of the two sets of functionality into separate APIs seemed
unncessary.
.\"
.SH COPYRIGHT
Copyright \(co 2024 DTB. License AGPLv3+: GNU AGPL version 3 or later
<https://gnu.org/licenses/agpl.html>.
.\"
.SH SEE ALSO
.BR cat (1p),
.BR dd (1),
.BR dj (1),
.BR tee (1p)

View File

@@ -1,68 +1,74 @@
.\" Copyright (c) 20232024 DTB <trinity@trinity.moe> .\" Copyright (c) 20232024 DTB <trinity@trinity.moe>
.\" Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media> .\" Copyright (c) 20232024 Emma Tebibyte <emma@tebibyte.media>
.\" .\"
.\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license,
.\" visit <http://creativecommons.org/licenses/by-sa/4.0/>. .\" visit <http://creativecommons.org/licenses/by-sa/4.0/>.
.\"
.TH npc 1 .TH NPC 1
.SH NAME .SH NAME
npc \(en show non-printing characters npc \(en show non-printing characters
.\"
.SH SYNOPSIS .SH SYNOPSIS
npc npc
.RB ( -eht ) .RB ( -et )
.\"
.SH DESCRIPTION .SH DESCRIPTION
Npc reads from standard input and writes to standard output, replacing non- Print normally non-printing characters.
printing characters with printable equivalents. Control characters print as a
carat ('^') followed by the character '@' through '_' corresponding to the The program reads from standard input and writes to standard output, replacing
character replaced (e.g. control-X becomes "^X"). The delete character (0x7F) non-printing characters with printable equivalents. Control characters print as
becomes "^?". Characters with the high bit set (>127) are printed as "M-" a carat ('^') followed by the character '@' through '_' corresponding to the
character replaced (e.g. control-X becomes '^X'). The delete character (0x7F)
becomes '^?'. Characters with the high bit set (>127) are printed as 'M-'
followed by the graphical representation for the same character without the followed by the graphical representation for the same character without the
high bit set. high bit set.
.PP .\"
The .SH USAGE
.B -e
option prints a currency sign ('$') before each line ending.
.PP
The
.B -t
option prints tab characters as "^I" rather than a literal horizontal tab.
.IP \fB-e\fP
Prints a dollar sign ('$') before each line ending.
.IP \fB-t\fP
Prints tab characters as '^I' rather than a literal horizontal tab.
.\"
.SH DIAGNOSTICS .SH DIAGNOSTICS
Npc prints a debug message and exits with the appropriate sysexits(3) error In the event of an error, a debug message will be printed and the program will
code in the event of an error, otherwise it exits successfully. exit with the appropriate
.BR sysexits.h (3)
error code.
.\"
.SH BUGS .SH BUGS
Npc operates in single-byte chunks regardless of intended encoding. The program operates in single-byte chunks regardless of intended encoding.
.\"
.SH RATIONALE .SH RATIONALE
POSIX currently lacks a way to display non-printing characters in the terminal POSIX currently lacks a way to display non-printing characters in the terminal
using a standard tool. A popular extension to cat(1p), the -v option, is the using a standard tool. A popular extension to
bandage solution GNU and other software suites use. .BR cat (1p),
the
This functionality should be a separate tool because its usefulness extends .B -v
beyond that of cat(1p). option, is the bandage solution GNU and other software suites use.
This functionality is a separate tool because its usefulness extends beyond that
of
.BR cat (1p).
.\"
.SH AUTHOR .SH AUTHOR
Written by DTB <trinity@trinity.moe>. Written by DTB
.MT trinity@trinity.moe
.ME .
.\"
.SH COPYRIGHT .SH COPYRIGHT
Copyright © 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later Copyright © 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later
<https://gnu.org/licenses/agpl.html>. <https://gnu.org/licenses/agpl.html>.
.\"
.SH SEE ALSO .SH SEE ALSO
.BR cat (1p),
cat(1p), cat-v(1) .BR cat-v (1),
.I UNIX Style, or cat -v Considered Harmful .I UNIX Style, or cat -v Considered Harmful
by Rob Pike by Rob Pike

View File

@@ -3,68 +3,82 @@
.\" .\"
.\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license,
.\" visit <http://creativecommons.org/licenses/by-sa/4.0/>. .\" visit <http://creativecommons.org/licenses/by-sa/4.0/>.
.\"
.TH rpn 1 .TH rpn 1
.SH NAME .SH NAME
rpn \(en reverse polish notation evaluation rpn \(en reverse polish notation evaluation
.\"
.SH SYNOPSIS .SH SYNOPSIS
rpn rpn
.RB [numbers...]\ [operators...] .RB [ numbers... ]
.RB [ operators... ]
.\"
.SH DESCRIPTION .SH DESCRIPTION
Rpn evaluates reverse polish notation expressions either read from the standard Evaluate reverse polish notation.
input or parsed from provided arguments. See the STANDARD INPUT section.
Upon evaluation, rpn will print the resulting number on the stack to the The program evaluates reverse polish notation expressions either read from the
standard input or parsed from provided arguments. See the STANDARD INPUT
section.
Upon evaluation, the program will print the resulting number on the stack to the
standard output. Any further specified numbers will be placed at the end of the standard output. Any further specified numbers will be placed at the end of the
stack. stack.
For information on for reverse polish notation syntax, see rpn(7). For information on for reverse polish notation syntax, see
.BR rpn (7).
.\"
.SH STANDARD INPUT .SH STANDARD INPUT
If arguments are passed to rpn, it interprets them as an expression to be If arguments are passed, they are interpreted as an expression to be
evaluated. Otherwise, it reads whitespace-delimited numbers and operations from evaluated. Otherwise, it reads whitespace-delimited numbers and operations from
the standard input. the standard input.
.\"
.SH DIAGNOSTICS .SH DIAGNOSTICS
If encountering a syntax error, rpn will exit with the appropriate error code In the event of an error, a debug message will be printed and the program will
as defined by sysexits.h(3) and print an error message. exit with the appropriate
.BR sysexits.h (3)
error code; however, in the event of a syntax error, the program will print an
error message and continue accepting input.
.\"
.SH CAVEATS .SH CAVEATS
Due to precision constraints and the way floats are represented in accordance Due to precision constraints and the way floats are represented in accordance
with the IEEE Standard for Floating Point Arithmetic (IEEE 754), floating-point with the IEEE Standard for Floating Point Arithmetic (\fIIEEE 754\fP),
arithmetic has rounding errors. This is somewhat curbed by using the floating-point arithmetic has rounding errors. This is somewhat curbed by using
machine epsilon as provided by the Rust standard library to which to round the machine epsilon as provided by the Rust standard library to which to round
numbers. Because of this, variation is expected in the number of decimal places numbers. Because of this, variation is expected in the number of decimal places
rpn can handle based on the platform and hardware of any given machine. the program can handle based on the platform and hardware of any given machine.
.\"
.SH RATIONALE .SH RATIONALE
An infix notation calculation utility, bc(1p), is included in the POSIX An infix notation calculation utility,
standard, but does not accept expressions as arguments; in scripts, any .BR bc (1p),
predefined, non-interactive input must be piped into the program. A dc(1) is included in the POSIX standard, but does not accept expressions as arguments;
pre-dates the standardized bc(1p), the latter originally being a preprocessor in scripts, any predefined, non-interactive input must be piped into the
for the former, and was included in UNIX v2 onward. While it implements reverse program. A
polish notation, it still suffers from being unable to accept an expression as .BR dc (1)
an argument. pre-dates the standardized
.BR bc (1p),
the latter originally being a preprocessor for the former, and was included in
UNIX v2 onward. While it implements reverse polish notation, it still suffers
from being unable to accept an expression as an argument.
.\"
.SH AUTHOR .SH AUTHOR
Written by Emma Tebibyte <emma@tebibyte.media>. Written by Emma Tebibyte
.MT emma@tebibyte.media
.ME .
.\"
.SH COPYRIGHT .SH COPYRIGHT
Copyright (c) 2024 Emma Tebibyte. License AGPLv3+: GNU AGPL version 3 or later Copyright (c) 2024 Emma Tebibyte. License AGPLv3+: GNU AGPL version 3 or later
<https://gnu.org/licenses/agpl.html>. <https://gnu.org/licenses/agpl.html>.
.\"
.SH SEE ALSO .SH SEE ALSO
.BR bc (1p),
bc(1p), dc(1), rpn(7), IEEE 754 .BR dc (1),
.BR rpn (7),
.I IEEE 754

86
docs/scrut.1 Normal file
View File

@@ -0,0 +1,86 @@
.\" Copyright (c) 2024 DTB <trinity@trinity.moe>
.\" Copyright (c) 2024 Emma Tebibyte <emma@tebibyte.media>
.\"
.\" This work is licensed under CC BY-SA 4.0. To see a copy of this license,
.\" visit <http://creativecommons.org/licenses/by-sa/4.0/>.
.\"
.TH scrut 1
.SH NAME
scrut \(en scrutinize file properties
.SH SYNOPSIS
scrut
.RB ( -LSbcdefgkprsuwx )
.RB [ file... ]
.\"
.SH DESCRIPTION
Determine if files comply with requirements. If the given files comply with the
specified requirements, the program will exit successfully. Otherwise, it exits
unsuccessfully.
.\"
.SH OPTIONS
.IP \fB-L\fB
Requires the given files to exist and be symbolic links.
.IP \fB-S\fP
Requires the given files to exist and be sockets.
.IP \fB-b\fP
Requires the given files to exist and be block special files.
.IP \fB-c\fP
Requires the given files to exist and be character special files.
.IP \fB-d\fP
Requires the given files to exist and be directories.
.IP \fB-e\fP
Requires the given files to exist, and is redundant to any other option.
.IP \fB-f\fP
Requires the given files to exist and be regular files.
.IP \fB-g\fP
Requires the given files to exist and have their set group ID flags set.
.IP \fB-k\fP
Requires the given files to exist and have their sticky bit set.
.IP \fB-p\fP
Requires the given files to exist and be named pipes.
.IP \fB-r\fP
Requires the given files to exist and be readable.
.IP \fB-u\fP
Requires the given files to exist and have their set user ID flags set.
.IP \fB-w\fP
Requires the given files to exist and be writable.
.IP \fB-x\fP
Requires the given files to exist and be executable.
.\"
.SH DIAGNOSTICS
When invoked incorrectly, a debug message will be printed and the program will
exit with the appropriate
.BR sysexits.h (3)
error code.
.\"
.SH RATIONALE
The
.BR test (1p)
utility contains functionality that was broken out into separate programs. Thus,
the scope of this program is narrower than it. Notably, the
.B -h
option is now invalid and therefore shows usage information instead of being an
alias to the modern
.B -L
option.
.\"
.SH AUTHOR
Written by DTB
.MT trinity@trinity.moe
.ME .
.\"
.SH COPYRIGHT
Copyright \(co 2024 DTB. License AGPLv3+: GNU AGPL version 3 or later
<https://gnu.org/licenses/agpl.html>.
.\"
.SH SEE ALSO
.BR access (3p),
.BR lstat (3p),
.BR test (1p)

View File

@@ -1,58 +1,60 @@
.\" Copyright (c) 20232024 DTB <trinity@trinity.moe> .\" Copyright (c) 20232024 DTB <trinity@trinity.moe>
.\" Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media> .\" Copyright (c) 20232024 Emma Tebibyte <emma@tebibyte.media>
.\" .\"
.\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license,
.\" visit <http://creativecommons.org/licenses/by-sa/4.0/>. .\" visit <http://creativecommons.org/licenses/by-sa/4.0/>.
.\"
.TH STR 1 .TH STR 1
.SH NAME .SH NAME
str \(en test the character types of string arguments str \(en test the character types of string arguments
.\"
.SH SYNOPSIS .SH SYNOPSIS
str str
.RB [ type ] .RB [ type ]
.RB [ string... ] .RB [ string... ]
.\"
.SH DESCRIPTION .SH DESCRIPTION
Str tests each character in an arbitrary quantity of string arguments against Test string arguments.
the function of the same name within ctype(3).
The tests in this program are equivalent to the functions with the same names in
.BR ctype.h (0p)
and are the methods by which string arguments are tested.
.\"
.SH DIAGNOSTICS .SH DIAGNOSTICS
Str exits successfully if all tests pass and unsuccessfully if a test failed. If all tests pass, the program will exit with an exit code of 0. If any of the
.PP tests fail, the program will exit unsuccessfully with an error code of 1.
Str will exit unsuccessfully if a string is empty, as none of its contents
passed the test.
.PP
Str will print a message to standard error and exit unsuccessfully if used
improperly.
.SH DEPRECATED FEATURES An empty string will cause an unsuccessful exit as none of its contents pass any
tests.
Str used to have an "isvalue" type as an extension to ctype(3). This was When invoked incorrectly, a debug message will be printed and the program will
removed in favor of using strcmp(1) to compare strings against the empty string exit with the appropriate
(''). .BR sysexits.h (3)
error code.
.\"
.SH CAVEATS
.SH BUGS There\(cqs no way of knowing which argument failed the test without re-testing
There's no way of knowing which argument failed the test without re-testing
arguments individually. arguments individually.
.PP
If a character in a string isn't valid ASCII str will exit unsuccessfully.
If a character in a string isn\(cqt valid ASCII, the program will exit
unsuccessfully.
.\"
.SH AUTHOR .SH AUTHOR
Written by DTB <trinity@trinity.moe>. Written by DTB
.MT trinity@trinity.moe
.ME .
.\"
.SH COPYRIGHT .SH COPYRIGHT
Copyright © 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later Copyright \(co 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later
<https://gnu.org/licenses/gpl.html>. <https://gnu.org/licenses/gpl.html>.
.\"
.SH SEE ALSO .SH SEE ALSO
.BR ctype (3p),
ctype(3p), strcmp(1), ascii(7) .BR strcmp(1),
.BR ascii(7)

View File

@@ -1,62 +1,75 @@
.\" Copyright (c) 20232024 DTB <trinity@trinity.moe> .\" Copyright (c) 20232024 DTB <trinity@trinity.moe>
.\" Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media> .\" Copyright (c) 20232024 Emma Tebibyte <emma@tebibyte.media>
.\" .\"
.\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license,
.\" visit <http://creativecommons.org/licenses/by-sa/4.0/>. .\" visit <http://creativecommons.org/licenses/by-sa/4.0/>.
.\"
.TH STRCMP 1 .TH STRCMP 1
.SH NAME .SH NAME
strcmp \(en compare strings strcmp \(en compare strings
.\"
.SH SYNOPSIS .SH SYNOPSIS
strcmp strcmp
.RM [ string ] .RM [ string ]
.RB [ strings... ] .RB [ strings... ]
.\"
.SH DESCRIPTION .SH DESCRIPTION
Strcmp checks whether the given strings are the same. Check whether string arguments are the same.
Strcmp exits successfully if the strings are identical. Otherwise, strcmp exits .\"
with the value 1 if an earlier string has a greater byte value than a later
string (e.g.
.R strcmp b a
)
and 255 if an earlier string has a lesser byte value (e.g.
.R strcmp a b
).
.SH DIAGNOSTICS .SH DIAGNOSTICS
Strcmp will print an error message and exit unsuccessfully with a status The program will exit successfully if the strings are identical. Otherwise, it
described in sysexits(3) if used incorrectly (given less than two operands). will exit with an error code of 1 if a string passed has a lesser byte value
than one of the prior strings:
.SH UNICODE .RS
strcmp b a
.RE
Strcmp will exit unsuccessfully if the given strings are not identical; and with an error code of 255 if it has a greater byte value than one of the
Unicode strings may need to be normalized if the intent is to check visual prior strings:
similarity and not byte similarity.
.RS
strcmp a b
.RE
When invoked incorrectly, a debug message will be printed and the program will
exit with the appropriate
.BR sysexits.h (3)
error code.
.\"
.SH CAVEATS
The program will exit unsuccessfully if the given strings are not identical;
therefore, Unicode strings may need to be normalized if the intent is to check
visual similarity and not byte similarity.
.\"
.SH RATIONALE .SH RATIONALE
The traditional tool for string comparisons in POSIX and other Unix shells has The traditional tool for string comparisons in POSIX and other Unix shells has
been test(1). This tool also handles integer comparisons and file scrutiny. been
These parts of its functionality have been broken out into multiple utilities. .BR test (1).
This tool also handles integer comparisons and file scrutiny. These parts of its
Strcmps functionality may be performed on a POSIX-compliant system with functionality have been broken out into multiple utilities.
test(1p).
This program\(cqs functionality may be performed on a POSIX-compliant system with
.BR test (1p).
.\"
.SH AUTHOR .SH AUTHOR
Written by DTB <trinity@trinity.moe>. Written by DTB
.MT trinity@trinity.moe
.ME .
.\"
.SH COPYRIGHT .SH COPYRIGHT
Copyright © 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later Copyright \(co 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later
<https://gnu.org/licenses/gpl.html>. <https://gnu.org/licenses/gpl.html>.
.\"
.SH SEE ALSO .SH SEE ALSO
.BR strcmp (3),
strcmp(3), intcmp(1), scrut(1), test(1p) .BR intcmp (1),
.BR scrut (1),
.BR test (1p)

73
docs/swab.1 Normal file
View File

@@ -0,0 +1,73 @@
.\" Copyright (c) 2024 DTB <trinity@trinity.moe>
.\" Copyright (c) 2024 Emma Tebibyte <emma@tebibyte.media>
.\"
.\" This work is licensed under CC BY-SA 4.0. To see a copy of this license,
.\" visit <http://creativecommons.org/licenses/by-sa/4.0/>.
.\"
.TH SWAB 1
.SH NAME
swab \(en swap bytes
.\"
.SH SYNOPSIS
swab
.RB ( -f )
.RB ( -w
.R [
.B word size
.R ])
.\"
.SH DESCRIPTION
Swap the latter and former halves of a block of bytes.
.\"
.SH OPTIONS
.IP \fB-f\fP
Ignore SIGINT signal.
.IP \fB-w\fP
Configures the word size; that is, the size in bytes of the block size
on which to operate. The default word size is 2. The word size must be
cleanly divisible by 2, otherwise the block of bytes being processed can\(cqt be
halved.
.\"
.SH EXAMPLES
The following
.BR sh (1p)
line:
.RS
printf 'hello world!\(rsn' | swab
.RE
Produces the following output:
.RS
ehll oowlr!d
.RE
.\"
.SH DIAGNOSTICS
In the event of an error, a debug message will be printed and the program will
exit with the appropriate
.BR sysexits.h (3)
error code.
.\"
.SH RATIONALE
This program was modeled and named after the conv=swab functionality specified
in the
.BR dd (1p)
utility. It additionally allows the word size to be configured.
This functionality is useful for fixing the endianness of binary files produced
on other machines.
.\"
.SH COPYRIGHT
Copyright \(co 2024 DTB. License AGPLv3+: GNU AGPL version 3 or later
<https://gnu.org/licenses/agpl.html>.
.\"
.SH SEE ALSO
.BR dd (1p)

View File

@@ -1,35 +1,36 @@
.\" Copyright (c) 2022, 2024 DTB <trinity@trinity.moe> .\" Copyright (c) 2022, 2024 DTB <trinity@trinity.moe>
.\" Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media> .\" Copyright (c) 20232024 Emma Tebibyte <emma@tebibyte.media>
.\" .\"
.\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, .\" This work is licensed under CC BY-SA 4.0. To see a copy of this license,
.\" visit <http://creativecommons.org/licenses/by-sa/4.0/>. .\" visit <http://creativecommons.org/licenses/by-sa/4.0/>.
.\"
.TH TRUE 1 .TH TRUE 1
.SH NAME .SH NAME
true \(en do nothing, successfully true \(en do nothing, successfully
.\"
.SH DESCRIPTION .SH DESCRIPTION
True does nothing regardless of operands or standard input. Do nothing regardless of operands or standard input. An exit code of 0 will
True will always return an exit code of 0. always be returned.
.\"
.SH RATIONALE .SH RATIONALE
True exists for the construction of control flow and loops based on a success. In \fIPOSIX.1-2017\fP,
.BR true (1p)
True functions as described in POSIX.1-2017. exists for the construction of control flow and loops based on a success. This
implementation functions as described in that standard.
.\"
.SH AUTHOR .SH AUTHOR
Written by Emma Tebibyte <emma@tebibyte.media>. Written by Emma Tebibyte
.MT emma@tebibyte.media
.ME .
.\"
.SH COPYRIGHT .SH COPYRIGHT
This work is marked with CC0 1.0. To see a copy of this license, visit This work is marked with CC0 1.0. To see a copy of this license, visit
<http://creativecommons.org/publicdomain/zero/1.0>. <http://creativecommons.org/publicdomain/zero/1.0>.
.\"
.SH SEE ALSO .SH SEE ALSO
.BR false (1p),
false(1p) .BR true (1p)

View File

@@ -203,28 +203,28 @@ Io_fdseek(struct Io *io){
if(!fdisstd(io->fd) && lseek(io->fd, io->seek, SEEK_SET) != -1) if(!fdisstd(io->fd) && lseek(io->fd, io->seek, SEEK_SET) != -1)
return -1; return -1;
else if(io->fl == write_flags){
memset(io->buf, '\0', io->bs);
/* This is a dirty trick; rather than testing conditions and operating
* likewise, because the parameters to read or write are going to be
* the same either way, just use a function pointer to keep track of
* the intended operation. */
op = (int (*)(int, void *, size_t))&write;
/* Function pointer casts are risky; this works because the difference
* is in the second parameter and only that write(2) makes the buffer
* const whereas read(2) does not. To avoid even the slightest
* undefined behavior comment out the cast, just be ready for a
* -Wincompatible-function-pointer-types if your compiler notices it.
*/
}else
op = &read;
/* We're going to cheat and use bufuse as the retval for write(2), which is /* repeated code to get the condition out of the loop */
* fine because it'll be zeroed as this function returns anyway. */ if(io->fl == write_flags){
do{ if( (io->bufuse = (*op)(io->fd, io->buf, MIN(io->bs, io->seek))) == 0) memset(io->buf, '\0', io->bs);
/* second chance */ /* We're going to cheat and use bufuse as the retval for write(2),
io->bufuse = (*op)(io->fd, io->buf, MIN(io->bs, io->seek)); * which is fine because it'll be zeroed as this function returns
}while((io->seek -= io->bufuse) > 0 && io->bufuse != 0); * anyway. */
do{
if((io->bufuse = write(io->fd, io->buf, MIN(io->bs, io->seek)))
== 0)
/* second chance */
io->bufuse = write(io->fd, io->buf, MIN(io->bs, io->seek));
}while((io->seek -= io->bufuse) > 0 && io->bufuse != 0);
}else if(io->fl == read_flags){
do{
if((io->bufuse = read(io->fd, io->buf, MIN(io->bs, io->seek)))
== 0)
/* second chance */
io->bufuse = read(io->fd, io->buf, MIN(io->bs, io->seek));
}while((io->seek -= io->bufuse) > 0 && io->bufuse != 0);
}else
return EX_SOFTWARE;
io->bufuse = 0; io->bufuse = 0;

View File

@@ -18,30 +18,26 @@
use std::{ use std::{
env::args, env::args,
io::{ Read, stdin, Write }, io::{ Read, stdin, stdout, Write },
process::{ Command, exit, Stdio }, process::{ Command, exit, Stdio },
}; };
extern crate sysexits;
extern crate getopt; extern crate getopt;
extern crate strerror;
extern crate sysexits;
use getopt::{ Opt, Parser }; use getopt::{ Opt, Parser };
use sysexits::{ EX_DATAERR, EX_USAGE }; use strerror::StrError;
use sysexits::{ EX_DATAERR, EX_IOERR, EX_UNAVAILABLE, EX_USAGE };
fn main() { fn main() {
let argv = args().collect::<Vec<String>>(); let argv = args().collect::<Vec<String>>();
let mut d = '␞'; let mut d = 0x1E.to_string();
let mut arg_parser = Parser::new(&argv, "d:"); let mut arg_parser = Parser::new(&argv, "d:");
while let Some(opt) = arg_parser.next() { while let Some(opt) = arg_parser.next() {
match opt { match opt {
Ok(Opt('d', Some(arg))) => { Ok(Opt('d', Some(arg))) => d = arg,
let arg_char = arg.chars().collect::<Vec<char>>();
if arg_char.len() > 1 {
eprintln!("{}: {}: Not a character.", argv[0], arg);
exit(EX_USAGE);
} else { d = arg_char[0]; }
},
_ => {}, _ => {},
}; };
} }
@@ -54,43 +50,65 @@ fn main() {
exit(EX_USAGE); exit(EX_USAGE);
}); });
let index = argv[index_arg].parse::<usize>().unwrap_or_else(|_| { let index = argv[index_arg].parse::<usize>().unwrap_or_else(|e| {
eprintln!("{}: {}: Not an integer.", argv[0], argv[1]); eprintln!("{}: {}: {}", argv[0], argv[1], e);
exit(EX_DATAERR); exit(EX_DATAERR);
}); });
let mut buf = String::new(); let mut buf = String::new();
stdin().read_to_string(&mut buf).unwrap(); let _ = stdin().read_to_string(&mut buf);
let mut fields = buf.split(d).collect::<Vec<&str>>(); let mut fields = buf.split(&d).collect::<Vec<&str>>();
let opts = argv.iter().clone().skip(command_arg + 1).collect::<Vec<&String>>(); let opts = argv
.iter()
.clone()
.skip(command_arg + 1)
.collect::<Vec<&String>>();
let mut spawned = Command::new(argv.get(command_arg).unwrap()) let mut spawned = Command::new(argv.get(command_arg).unwrap())
.args(opts) .args(opts)
.stdin(Stdio::piped()) .stdin(Stdio::piped())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.spawn() .spawn()
.unwrap(); .unwrap_or_else( |e| {
eprintln!("{}: {}: {}", argv[0], argv[command_arg], e.strerror());
exit(EX_UNAVAILABLE);
});
let field = fields.get(index).unwrap_or_else(|| { let field = fields.get(index).unwrap_or_else(|| {
eprintln!( eprintln!(
"{}: {}: No such index in input.", "{}: {}: No such index in input",
argv[0], argv[0],
index.to_string() index.to_string(),
); );
exit(EX_DATAERR); exit(EX_DATAERR);
}); });
if let Some(mut child_stdin) = spawned.stdin.take() { if let Some(mut child_stdin) = spawned.stdin.take() {
child_stdin.write_all(field.as_bytes()).unwrap(); let _ = child_stdin.write_all(field.as_bytes());
drop(child_stdin); drop(child_stdin);
} }
let output = spawned.wait_with_output().unwrap(); let output = spawned.wait_with_output().unwrap_or_else(|e| {
eprintln!("{}: {}: {}", argv[0], argv[command_arg], e.strerror());
exit(EX_IOERR);
});
let new_field = String::from_utf8(output.stdout).unwrap(); let mut replace = output.stdout.clone();
if replace.pop() != Some(b'\n') { replace = output.stdout; }
let new_field = String::from_utf8(replace).unwrap_or_else(|e| {
eprintln!("{}: {}: {}", argv[0], argv[command_arg], e);
exit(EX_IOERR);
});
fields[index] = &new_field; fields[index] = &new_field;
print!("{}", fields.join(&d.to_string())); stdout().write_all(
fields.join(&d.to_string()).as_bytes()
).unwrap_or_else(|e| {
eprintln!("{}: {}", argv[0], e.strerror());
exit(EX_IOERR);
});
} }

109
src/hru.rs Normal file
View File

@@ -0,0 +1,109 @@
/*
* Copyright (c) 20232024 Emma Tebibyte <emma@tebibyte.media>
* SPDX-License-Identifier: AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
use std::{
cmp::Ordering,
env::args,
io::{ stdin, stdout, Write },
process::{ ExitCode, exit },
};
extern crate strerror;
extern crate sysexits;
use strerror::StrError;
use sysexits::{ EX_DATAERR, EX_IOERR, EX_SOFTWARE };
const LIST: [(u32, &str); 10] = [
(3, "k"),
(6, "M"),
(9, "G"),
(12, "T"),
(15, "P"),
(18, "E"),
(21, "Z"),
(24, "Y"),
(27, "R"),
(30, "Q")
];
fn convert(input: u128) -> Result<(f64, (u32, &'static str)), String> {
let mut out = (input as f64, (0_u32, ""));
if input < 1000 { return Ok(out); }
for (n, p) in LIST {
let c = match 10_u128.checked_pow(n) {
Some(c) => c,
None => {
return Err(format!("10^{}: Integer overflow", n.to_string()));
},
};
match c.cmp(&input) {
Ordering::Less => {
out = (input as f64 / c as f64, (n, p));
},
Ordering::Equal => {
return Ok((input as f64 / c as f64, (n, p)));
},
Ordering::Greater => {},
};
}
Ok(out)
}
fn main() -> ExitCode {
let argv = args().collect::<Vec<String>>();
let mut buf = String::new();
while let Ok(_) = stdin().read_line(&mut buf) {
if buf.is_empty() { return ExitCode::SUCCESS; }
let n: u128 = match buf.trim().parse() {
Ok(f) => {
buf.clear();
f
},
Err(err) => {
eprintln!("{}: {}", argv[0], err);
return ExitCode::from(EX_DATAERR as u8);
},
};
let (number, prefix) = match convert(n) {
Ok(x) => x,
Err(err) => {
eprintln!("{}: {}", argv[0], err);
return ExitCode::from(EX_SOFTWARE as u8);
},
};
let si_prefix = format!("{}B", prefix.1);
let out = ((number * 10.0).round() / 10.0).to_string();
stdout().write_all(format!("{} {}\n", out, si_prefix).as_bytes())
.unwrap_or_else(|e| {
eprintln!("{}: {}", argv[0], e.strerror());
exit(EX_IOERR);
});
}
ExitCode::SUCCESS
}

236
src/mm.c Normal file
View File

@@ -0,0 +1,236 @@
/*
* Copyright (c) 2024 DTB <trinity@trinity.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
#include <errno.h> /* errno */
#include <signal.h> /* signal(2), SIG_ERR, SIG_IGN, SIGINT */
#include <stdio.h> /* fclose(3), fopen(3), fprintf(3), getc(3), putc(3),
* setvbuf(3), size_t, _IONBF, NULL */
#include <stdlib.h> /* free(3), realloc(3) */
#include <string.h> /* strcmp(3), strerror(3) */
#include <unistd.h> /* getopt(3) */
#if !defined EX_IOERR || !defined EX_OK || !defined EX_OSERR \
|| !defined EX_USAGE
# include <sysexits.h>
#endif
extern int errno;
/* This structure is how open files are tracked. */
struct Files{
size_t a; /* allocation */
size_t s; /* used size */
char *mode; /* file opening mode */
char **names; /* file names */
FILE **files; /* file pointers */
};
/* How much to grow the allocation when it's saturated. */
#ifndef ALLOC_INCREMENT
# define ALLOC_INCREMENT 1
#endif
/* How much to grow the allocation at program start. */
#ifndef ALLOC_INITIAL
# define ALLOC_INITIAL 10
#endif
/* pre-allocated strings */
static char *program_name = "<no argv[0]>";
static char *stdin_name = "<stdin>";
static char *stdout_name = "<stdout>";
static char *stderr_name = "<stderr>";
static char *(fmode[]) = { (char []){"rb"}, (char []){"rb+"} };
static char *wharsh = "wb";
/* Adds the open FILE pointer for the file at the path s to the files struct,
* returning the FILE if successful and NULL if not, allocating more memory in
* the files buffers as needed. */
static FILE *
Files_append(struct Files *files, FILE *file, char *name){
if(file == NULL || (files->s == files->a
&& ((files->files = realloc(files->files,
(files->a += (files->a == 0)
? ALLOC_INITIAL
: ALLOC_INCREMENT)
* sizeof *(files->files))) == NULL
|| (files->names = realloc(files->names,
files->a * sizeof *(files->names))) == NULL)))
return NULL;
files->names[files->s] = name;
return files->files[files->s++] = file;
}
/* Opens the file at the path p and puts it in the files struct, returning NULL
* if either the opening or the placement of the open FILE pointer fail. */
#define Files_open(files, p) \
Files_append((files), fopen((p), (files)->mode), (p))
/* Prints a diagnostic message based on errno and returns an exit status
* appropriate for an OS error. */
static int
oserr(char *s, char *r){
fprintf(stderr, "%s: %s: %s\n", s, r, strerror(errno));
return EX_OSERR;
}
/* Hijacks i and j from main and destructs the files[2] struct used by main by
* closing its files and freeing its files and names arrays, returning retval
* from main. */
#define terminate \
for(i = 0; i < 2; ++i){ \
for(j = 0; j < files[i].s; ++j) \
if(files[i].files[j] != stdin \
&& files[i].files[j] != stdout \
&& files[i].files[j] != stderr) \
fclose(files[i].files[j]); \
free(files[i].files); \
free(files[i].names); \
} \
return retval
/* Prints a usage text, in which s is the program being run (i.e. argv[0]), and
* returns an exit status appropriate for a usage error. */
int usage(char *s){
fprintf(stderr, "Usage: %s (-aenu) (-i [input])... (-o [output])...\n", s);
return EX_USAGE;
}
int main(int argc, char *argv[]){
int c;
struct Files files[2]; /* {read, write} */
size_t i;
size_t j;
size_t k; /* loop index but also unbuffer status */
int retval;
/* Initializes the files structs with their default values, standard
* input and standard output. If an input or an output is specified
* these initial values will be overwritten, so to, say, use mm(1)
* equivalently to tee(1p), -o - will need to be specified before
* additional files to ensure standard output is still written. */
for(i = 0; i < 2; ++i){
files[i].a = 0;
files[i].s = 0;
files[i].mode = fmode[i];
files[i].files = NULL;
files[i].names = NULL;
Files_append(&files[i], i == 0 ? stdin : stdout,
i == 0 ? stdin_name : stdout_name);
files[i].s = 0;
}
k = 0;
if(argc > 0)
program_name = argv[0];
if(argc > 1)
while((c = getopt(argc, argv, "aehi:no:u")) != -1)
switch(c){
case 'a': /* "rb+" -> "ab" */
files[1].mode[0] = 'a';
files[1].mode[2] = '\0';
break;
case 'e':
if(Files_append(&files[1], stderr, stderr_name) != NULL)
break;
retval = oserr(argv[0], "-e");
terminate;
case 'i':
if((strcmp(optarg, "-") == 0 && Files_append(&files[0],
stdin, stdin_name) != NULL)
|| Files_open(&files[0], optarg) != NULL)
break;
retval = oserr(argv[0], optarg);
terminate;
case 'o':
if((strcmp(optarg, "-") == 0 && Files_append(&files[1],
stdout, stdout_name) != NULL)
|| Files_open(&files[1], optarg) != NULL)
break;
/* does not exist, so try to create it */
if(errno == ENOENT){
files[1].mode = wharsh;
if(Files_open(&files[1], optarg) != NULL){
files[1].mode = fmode[1];
break;
}
}
retval = oserr(argv[0], optarg);
terminate;
case 'n':
if(signal(SIGINT, SIG_IGN) != SIG_ERR)
break;
retval = oserr(argv[0], "-n");
terminate;
case 'u':
k = 1;
break;
default:
retval = usage(argv[0]);
terminate;
}
if(optind != argc){
retval = usage(argv[0]);
terminate;
}
files[0].s += files[0].s == 0;
files[1].s += files[1].s == 0;
/* Unbuffer files. */
if(k){
for(i = 0;
i < files[0].s;
setvbuf(files[0].files[i++], NULL, _IONBF, 0));
for(i = 0;
i < files[1].s;
setvbuf(files[1].files[i++], NULL, _IONBF, 0));
}
retval = EX_OK;
/* Actual program loop. */
for(i = 0; i < files[0].s; ++i) /* iterate ins */
while((c = getc(files[0].files[i])) != EOF) /* iterate chars */
for(j = 0; j < files[1].s; ++j) /* iterate outs */
if(putc(c, files[1].files[j]) == EOF){
/* notebook's full */
retval = EX_IOERR;
fprintf(stderr, "%s: %s: %s\n",
program_name, files[1].names[j], strerror(errno));
if(fclose(files[1].files[j]) == EOF)
fprintf(stderr, "%s: %s: %s\n",
program_name, files[1].names[j], strerror(errno));
/* massage out the tense muscle */
for(k = j--; k < files[1].s - 1; ++k){
files[1].files[k] = files[1].files[k+1];
files[1].names[k] = files[1].names[k+1];
}
if(--files[1].s == 0)
terminate;
}
terminate;
}

View File

@@ -165,14 +165,14 @@ fn eval(
Subtract => stack.push_back(y - x), Subtract => stack.push_back(y - x),
Multiply => stack.push_back(y * x), Multiply => stack.push_back(y * x),
Divide => stack.push_back(y / x), Divide => stack.push_back(y / x),
Power => stack.push_back(x.powf(y)), Power => stack.push_back(y.powf(x)),
Floor => stack.push_back((y / x).floor()), Floor => stack.push_back((y / x).floor()),
Modulo => stack.push_back(y % x), Modulo => stack.push_back(y % x),
_ => {}, _ => {},
}; };
} else { } else {
return Err(EvaluationError { return Err(EvaluationError {
message: format!("{}: Unexpected operation.", op), message: format!("{}: Unexpected operation", op),
code: EX_DATAERR, code: EX_DATAERR,
}) })
} }

View File

@@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2023 DTB <trinity@trinity.moe> * Copyright (c) 20232024 DTB <trinity@trinity.moe>
* Copyright (c) 2024 Emma Tebibyte <emma@tebibyte.media>
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
* *
* This program is free software: you can redistribute it and/or modify it under * This program is free software: you can redistribute it and/or modify it under
@@ -17,13 +18,15 @@
*/ */
#include <stdio.h> /* fprintf(3), stderr, NULL */ #include <stdio.h> /* fprintf(3), stderr, NULL */
#include <stdlib.h> /* EXIT_FAILURE */ #include <stdlib.h> /* EXIT_FAILURE, EXIT_SUCCESS */
#include <string.h> /* strchr(3) */ #include <string.h> /* memset(3), strchr(3) */
#ifndef EX_USAGE
# include <sysexits.h>
#endif
#include <unistd.h> /* access(3), getopt(3), F_OK, R_OK, W_OK, X_OK */ #include <unistd.h> /* access(3), getopt(3), F_OK, R_OK, W_OK, X_OK */
#include <sys/stat.h> /* lstat(3), stat struct, S_ISBLK, S_ISCHR, S_ISDIR, #include <sys/stat.h> /* lstat(3), stat struct, S_ISBLK, S_ISCHR, S_ISDIR,
* S_ISFIFO, S_ISGID, S_ISREG, S_ISLNK, S_ISSOCK, * S_ISFIFO, S_ISGID, S_ISREG, S_ISLNK, S_ISSOCK,
* S_ISUID, S_ISVTX */ * S_ISUID, S_ISVTX */
#include <sysexits.h>
static char args[] = "bcdefghkprsuwxLS"; static char args[] = "bcdefghkprsuwxLS";
static char ops[(sizeof args) / (sizeof *args)]; static char ops[(sizeof args) / (sizeof *args)];
@@ -33,24 +36,31 @@ int main(int argc, char *argv[]){
struct stat buf; struct stat buf;
int c; int c;
size_t i; size_t i;
char *p;
if(argc < 2) if(argc < 2)
goto usage; goto usage;
i = 0; memset(ops, '\0', sizeof ops);
while((c = getopt(argc, argv, args)) != -1) while((c = getopt(argc, argv, args)) != -1)
if(strchr(args, c) == NULL) if((p = strchr(args, c)) == NULL)
goto usage; goto usage;
else else
ops[i++] = c; ops[p - args] = c;
ops[i] = '\0'; /* 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';
}
if(optind == argc) if(optind == argc)
goto usage; goto usage;
argv += optind; argv += optind;
do{ if(access(*argv, F_OK) != 0 || lstat(*argv, &buf) == -1) do{ if(access(*argv, F_OK) != 0 || lstat(*argv, &buf) == -1)
return 1; /* doesn't exist or isn't stattable */ return EXIT_FAILURE; /* doesn't exist or isn't stattable */
for(i = 0; ops[i] != '\0'; ++i) for(i = 0; ops[i] != '\0'; ++i)
if(ops[i] == 'e') if(ops[i] == 'e')
@@ -90,8 +100,8 @@ usage: fprintf(stderr, "Usage: %s (-%s) [file...]\n",
&& !S_ISLNK(buf.st_mode)) && !S_ISLNK(buf.st_mode))
|| (ops[i] == 'S' || (ops[i] == 'S'
&& !S_ISSOCK(buf.st_mode))) && !S_ISSOCK(buf.st_mode)))
return 1; return EXIT_FAILURE;
}while(*++argv != NULL); }while(*++argv != NULL);
return 0; return EXIT_SUCCESS;
} }

31
src/strerror.rs Normal file
View File

@@ -0,0 +1,31 @@
/*
* Copyright (c) 2024 Emma Tebibyte <emma@tebibyte.media>
* 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.
*/
use std::ffi::{ c_int, c_char, CStr };
pub trait StrError { fn strerror(&self) -> String; }
impl StrError for std::io::Error {
/* wrapper function for use in Rust */
fn strerror(&self) -> String {
/* Get the raw OS error. If its None, what the hell is going on‽ */
let errno = self.raw_os_error().unwrap_or(0) as c_int;
/* Get a CStr from the error message so that its referenced and then
* convert it to an owned value. If the string is not valid UTF-8,
* return that error instead. */
match unsafe { CStr::from_ptr(strerror(errno)) }.to_str() {
Ok(s) => s.to_owned(), // yay!! :D
Err(e) => e.to_string(), // awww :(
}
}
}
/* binding to strerror(3p) */
extern "C" { fn strerror(errnum: c_int) -> *mut c_char; }

90
src/swab.rs Normal file
View File

@@ -0,0 +1,90 @@
/*
* Copyright (c) 2024 DTB <trinity@trinity.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
use std::{
env::args,
io::{ stdin, stdout, Error, ErrorKind, Read, Write },
process::ExitCode,
vec::Vec
};
extern crate getopt;
use getopt::{ Opt, Parser };
extern crate sysexits;
use sysexits::{ EX_OK, EX_OSERR, EX_USAGE };
fn oserr(s: &str, e: Error) -> ExitCode {
eprintln!("{}: {}", s, e);
ExitCode::from(EX_OSERR as u8)
}
fn usage(s: &str) -> ExitCode {
eprintln!("Usage: {} (-f) (-w [wordsize])", s);
ExitCode::from(EX_USAGE as u8)
}
fn main() -> ExitCode {
let argv = args().collect::<Vec<String>>();
let mut buf: Vec<u8> = Vec::new();
let mut input = stdin();
let mut output = stdout().lock();
let mut opts = Parser::new(&argv, "fw:");
let mut force = false;
let mut wordsize: usize = 2;
loop {
match opts.next() {
None => break,
Some(opt) =>
match opt {
Ok(Opt('f', None)) => force = true,
Ok(Opt('w', Some(arg))) => {
match arg.parse::<usize>() {
Ok(w) if w % 2 == 0 => { wordsize = w; () },
_ => { return usage(&argv[0]); },
}
},
_ => { return usage(&argv[0]); }
}
}
}
buf.resize(wordsize, 0);
loop {
match input.read(&mut buf) {
Ok(0) => break ExitCode::from(EX_OK as u8),
Ok(v) if v == wordsize => {
let (left, right) = buf.split_at(v/2);
if let Err(e) = output.write(&right)
.and_then(|_| output.write(&left)) {
break oserr(&argv[0], e)
}
},
Ok(v) => {
if let Err(e) = output.write(&buf[..v]) {
break oserr(&argv[0], e)
}
},
Err(e) if e.kind() == ErrorKind::Interrupted && force => continue,
Err(e) => break oserr(&argv[0], e)
}
}
}

View File

@@ -1,40 +0,0 @@
#!/bin/sh
# Copyright (c) 20232024 Emma Tebibyte <emma@tebibyte.media>
# 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
if ! ls Makefile >/dev/null 2>&1
then
printf '%s: Run this script in the root of the project.\n' "$0" 1>&2
exit 64 # sysexits.h(3) EX_USAGE
fi
make clean
./configure clean
./configure
for CC in cc \
clang \
gcc \
'zig cc'
do
export CC
command -v "$(printf '%s\n' "$CC" | cut -d ' ' -f1)" >/dev/null 2>&1 \
|| continue
printf '%s: %s: Testing build.\n' "$0" "$CC"
make CC="$CC" && printf '%s: Build successful.\n' "$0"
ls -lA build/bin
make clean
printf '\n'
done