Compare commits

..

78 Commits
0.10.0 ... docs

Author SHA1 Message Date
432b19818e made dj options no longer alphabetized 2024-04-28 20:42:44 -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
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
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
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
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
26 changed files with 1220 additions and 259 deletions

View File

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

1
.gitignore vendored
View File

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

View File

@@ -90,26 +90,44 @@ notice:
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
When writing code, make sure lines never exceed 80 characters in width when
using four-character-wide indentation steps.
Make sure lines never exceed 80 columns in width when using four-character
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
print usage information when any erroneous option is specified. Follow the
NetBSD style guide for usage text output format [1].
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 texts output format [1].
If committing a new source file for a utility, format the commit message like
this:
[1] <http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/share/misc/style>
$ 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:
$ 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:
$ git commit -m 'README: clarification'
$ git commit -m 'tests: posix: fixed bug #47'
$ git commit -m 'docs: tool(1): added author information'
$ git commit -m 'README: clarify'
$ git commit -m 'tests/posix: fix bug #47'
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

@@ -17,7 +17,7 @@ CC=cc
RUSTC=rustc
.PHONY: all
all: dj false fop intcmp scrut str strcmp true
all: dj false fop hru intcmp mm rpn scrut str strcmp swab true
build:
# keep build/include until bindgen(1) has stdin support
@@ -40,7 +40,6 @@ install: dist
.PHONY: test
test: build
tests/cc-compat.sh
tests/posix-compat.sh
$(RUSTC) --test src/getopt-rs/lib.rs -o build/test/getopt
@@ -55,7 +54,7 @@ build/o/libsysexits.rlib: build
| $(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 \
$(RUSTC) $(RUSTFLAGS) --crate-type=lib --crate-name=getopt \
-o build/o/libgetopt.rlib src/getopt-rs/lib.rs
.PHONY: dj
@@ -75,11 +74,23 @@ build/bin/fop: src/fop.rs build build/o/libgetopt.rlib build/o/libsysexits.rlib
--extern sysexits=build/o/libsysexits.rlib \
-o $@ src/fop.rs
.PHONY: hru
hru: build/bin/hru
build/bin/hru: src/hru.rs build build/o/libgetopt.rlib build/o/libsysexits.rlib
$(RUSTC) $(RUSTFLAGS) --extern getopt=build/o/libgetopt.rlib \
--extern sysexits=build/o/libsysexits.rlib \
-o $@ src/hru.rs
.PHONY: intcmp
intcmp: build/bin/intcmp
build/bin/intcmp: src/intcmp.c build
$(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: rpn
rpn: build/bin/rpn
build/bin/rpn: src/rpn.rs build build/o/libsysexits.rlib
@@ -102,6 +113,13 @@ strcmp: build/bin/strcmp
build/bin/strcmp: src/strcmp.c build
$(CC) $(CFLAGS) -o $@ src/strcmp.c
.PHONY: swab
swab: build/bin/swab
build/bin/swab: src/swab.rs build build/o/libsysexits.rlib
$(RUSTC) $(RUSTFLAGS) --extern getopt=build/o/libgetopt.rlib \
--extern sysexits=build/o/libsysexits.rlib \
-o $@ src/swab.rs
.PHONY: true
true: build/bin/true
build/bin/true: src/true.c build

32
README
View File

@@ -17,6 +17,31 @@ purposes beyond its scope.
See docs/ for more on the specific utilities currently implemented.
Building
The coreutils require a POSIX-compliant environment to compile, including a C
compiler and preprocessor (cc(1) and cpp(1) by default) with the -idirafter
flag, a 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
An Introduction to the Unix Shell
@@ -30,3 +55,10 @@ Master Foo Discourses on the Unix-Nature
Shell Programming!
<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/>.

197
docs/dj.1
View File

@@ -1,4 +1,5 @@
.\" 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/>.
@@ -44,87 +45,139 @@ dj
.B output offset
.R ])
.SH USAGE
.SH OPTIONS
The
.B -i
option takes a path as an argument to open and use in place of standard input.
The
.B -o
option does the same in place of standard output. Dj does not truncate output
files and instead writes over the bytes in the existing file.
.PP
The
.RS
Takes a file path as an argument to open and use as an input.
.RE
.B -b
option takes a numeric argument as the size in bytes of the input buffer and
the
.B -B
option does the same for the output buffer, the default for both being 1024
bytes, or one kibibyte (KiB).
.PP
The
.RS
Takes a numeric argument as the size in bytes of the input buffer, with the
default being 1024 bytes or one kibibyte (KiB).
.RE
.B -s
option takes a numeric argument as the number of bytes to skip into the input
before starting to read, and the
.RS
Takes a numeric argument as the number of bytes to skip into the input
before starting to read. If the standard input is used, bytes read to this point
are discarded.
.RE
.B -o
.RS
Takes a file path as an argument to open and use as an output.
.RE
.B -B
.RS
Does the same as
.B -b
but for the output buffer.
.RE
.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
.RS
Skips a number of bytes through the output before starting to write from
the input. If the output is a stream, null characters are printed.
.RE
.B -a
option takes one argument of one byte in length and pads the input buffer with
that byte in the event that a read doesn't fill the input buffer, and the
.B -A
option takes no arguments and pads with nuls.
The
.RS
Accepts a single literal byte with which input buffer is padded in the event
of an incomplete read from the input file.
.RE
.B -c
option specifies an amount of reads to make, and if 0 (the default) dj will
continue reading until a partial or empty read.
.PP
On a partial or empty read, dj prints a diagnostic message (unless the
.B -q
option is specified) and exits (unless the
.B -n
option is specified, in which case only two consecutive empty reads will cause
dj to exit).
At exit, usage statistics are printed unless the option
.B -q
is specified a second time. The
.RS
Specifies a number of reads to make. If set to zero (the default), reading will
continue until a partial or empty read is encountered.
.RE
.B -A
.RS
If the output is a stream, null bytes are printed. This option is equivalent to
specifying
.B -a
with a null byte instead of a character.
.RE
.B -d
.RS
Prints invocation information before program execution as described in the
DIAGNOSTICS section below. Each invocation increments the debug level of the
program.
.RE
.B -H
option will make these diagnostics human-readable.
.RS
Prints diagnostics messages in a human-readable manner as described in the
DIAGNOSTICS section below.
.RE
.B -n
.RS
Retries failed reads once more before exiting.
.RE
.B -q
.RS
Suppresses error messages which print when a read or write is partial or
empty. Each invocation decrements the debug level of the program.
.RE
.SH STANDARD INPUT
The standard input shall be used as an input if no inputs are specified one or
more of the input files is “-”.
.SH DIAGNOSTICS
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
On a partial or empty read, a diagnostic message is printed (unless the
.B -q
option is specified) and the program exits (unless the
.B -n
option is specified.
By default statistics are printed for input and output to the standard error in
the following format:
.RS
.R {records read} {ASCII unit separator} {partial records read}
.R {ASCII record separator} {records written} {ASCII unit separator}
.R {partial records written} {ASCII group separator} {bytes read}
.R {ASCII record separator} {bytes written} {ASCII file separator}
.PP
If the
.RE
This format for diagnostic output is designed to be machine-parseable for
convenience. For a more human-readable format, the
.B -H
option is specified dj instead uses this following format:
.PP
option may be specified. In this event, the following format is used instead:
.RS
.R {records read} '+' {partial records read} '>' {records written}
.R '+' {partial records written} ';' {bytes read} '>' {bytes written}
.R {ASCII line feed}
.PP
The
.B -q
option suppresses error messages which print when a read or write is partial or
empty and when used twice suppresses diagnostic output entirely.
.PP
In non-recoverable errors that don't pertain to dj's read-write cycle, a
diagnostic message is printed and dj exits with the appropriate sysexits(3)
status.
.RE
If the
.B -d
option is specified, debug output will be printed at the beginning of execution.
This debug information contains information regarding how the program was
invoked. The following example is the result of running the program with
.B -d
as the only argument:
.RS
.R argv0=dj
.R in=<stdin> ibs=1024 skip=0 align=ff count=0
.R out=<stdout> obs=1024 seek=0 debug= 3 noerror=0
.RE
In non-recoverable errors that dont pertain to the read-write cycle, a
diagnostic message is printed and the program exits with the appropriate
sysexits.h(3) status.
.SH BUGS
@@ -136,25 +189,29 @@ expected (the product of the count multiplied by the input block size). If the
or
.B -A
options are used this could make data written nonsensical.
.PP
Many lowercase options have capitalized variants and vice-versa which can be
confusing. Capitalized options tend to affect output or are more intense
versions of lowercase options.
.SH CAVEATS
Existing files are not truncated on ouput and are instead overwritten.
.SH RATIONALE
Dj was modeled after the dd utility specified in POSIX but adds additional
features: typical option formatting, allowing seeks to be specified in bytes
This program was based on the dd(1p) utility as specified in POSIX. While
character conversion may have been the original intent of dd(1p), it is
irrelevant to its modern use. Because of this, it eschews character conversion
and adds typical option formatting, allowing seeks to be specified in bytes
rather than in blocks, allowing arbitrary bytes as padding, and printing in a
format that's easy to parse for machines. It also neglects character
conversion, which may be dd's original intent but is irrelevant to its modern
use.
format thats easy to parse for machines.
.SH COPYRIGHT
Copyright (C) 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later
Copyright © 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later
<https://gnu.org/licenses/agpl.html>.
.SH SEE ALSO
dd(1)
dd(1p)

View File

@@ -1,5 +1,5 @@
.\" 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,
.\" visit <http://creativecommons.org/licenses/by-sa/4.0/>.
@@ -12,14 +12,13 @@ false \(en do nothing, unsuccessfully
.SH DESCRIPTION
False does nothing regardless of operands or standard input.
False will always return an exit code of 1.
Do nothing regardless of operands or standard input.
An exit code of 1 will always be returned.
.SH RATIONALE
False exists for the construction of control flow and loops based on a failure.
False functions as described in POSIX.1-2017.
In POSIX.1-2017, false(1p) exists for the construction of control flow and loops
based on a failure. This implementation functions as described in that standard.
.SH AUTHOR

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
.B -d
.RS
Sets a delimiter by which the input data will be split into fields. The default
is an ASCII record separator (␞).
.RE
.SH STANDARD INPUT
Data will be read from the standard input.
.SH CAVEATS
Field indices are zero-indexed, which may be unexpected behavior for some users.
.SH RATIONALE
With the assumption that tools will output data separated with ASCII field
separators, there is
The idea for this utility originated in the fact that GNU ls(1) utility contains
a
.B -h
option which enables human-readable units in file size outputs. This
functionality was broken out into hru(1), but there was no easy way to modify
the field in the ouput of ls(1p) without a new tool.
.SH COPYRIGHT
Copyright © 2024 Emma Tebibyte. License AGPLv3+: GNU AGPL version 3 or later
<https://gnu.org/licenses/agpl.html>.
.SH SEE ALSO
sed(1p)

59
docs/hru.1 Normal file
View File

@@ -0,0 +1,59 @@
.\" 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 sysexits.h(3) and print an
error message.
.SH RATIONALE
The GNU projects ls(1) implementation contains a human-readable option (-h)
that, when specified, makes the tool print size information in a format more
immediately readable. This functionality is useful not only in the context of
ls(1) so the decision was made to split it into a new tool. The original
functionality in GNUs ls(1) can be emulated with fop(1) combined with this
program.
.SH STANDARDS
The standard unit prefixes as specified by the Bureau International des Poids
et Mesures (BIPM) in the ninth edition of The International System of Units
(SI) are utilized for the ouput of conversions.
.SH AUTHOR
Written by Emma Tebibyte <emma@tebibyte.media>.
.SH COPYRIGHT
Copyright (c) 2024 Emma Tebibyte. License AGPLv3+: GNU AGPL version 3 or later
<https://gnu.org/licenses/agpl.html>.
.SH SEE ALSO
GNU ls(1), The International System of Units (SI) 9th Edition

View File

@@ -1,5 +1,5 @@
.\" 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,
.\" visit <http://creativecommons.org/licenses/by-sa/4.0/>.
@@ -13,45 +13,59 @@ intcmp \(en compare integers
.SH SYNOPSIS
intcmp
.RB ( -eghl )
.RB ( -egl )
.RB [ integer ]
.RB [ integer... ]
.SH DESCRIPTION
Intcmp compares integers.
Compare integers to each other.
.SH USAGE
The -e option permits given integers to be equal to each other. If combined
with -g or -l, only adjacent integers in the argument sequence can be equal.
.PP
The -g option permits a given integer to be greater than the following integer.
.PP
The -l option permits a given integer to be less than the following integer.
.PP
.B -e
.RS
Permits given integers to be equal to each other.
.RE
.B -g
.RS
Permits a given integer to be greater than the following integer.
.RE
.B -l
.RS
Permits a given integer to be less than the following integer.
.RE
.SH EXAMPLES
It may help to think of the -e, -g, and -l options as equivalent to the
infix algebraic “=”, “>”, and “<” operators respectively, with each option
putting its symbol between every given integer. For example,
putting its symbol between every given integer. The following example is
equivalent to evaluating “1 < 2 < 3”:
.RS
.R intcmp -l 1 2 3
is equivalent to evaluating "1 < 2 < 3".
.RE
.SH DIAGNOSTICS
Intcmp exits 0 for a valid expression and 1 for an invalid expression.
.PP
Intcmp prints a debug message and exits with the appropriate sysexits(3) error
code in the event of an error.
The program will exit with a status code of 0 for a valid expression and with a
code of 1 for an invalid expression.
In the event of an error, a debug message will be printed and the program will
exit with the appropriate sysexits.h(3) error code.
.SH BUGS
There are multiple ways to express compound comparisons; “less than or equal
to” can be -le or -el, for example.
.PP
The inequality comparison is -gl or -lg for “less than or greater than”; this
is elegant but unintuitive.
.PP
-egl, "equal to or less than or greater than", exits 0 no matter what for valid
-egl, equal to or less than or greater than, exits 0 no matter what for valid
program usage and may be abused to function as an integer validator.
Use str(1) instead.
@@ -61,7 +75,7 @@ The traditional tool for integer comparisons in POSIX and other Unix shells has
been test(1). This tool also handles string comparisons and file scrutiny.
These parts of its functionality have been broken out into multiple utilities.
Strcmps functionality may be performed on a POSIX-compliant system with
This programs functionality may be performed on a POSIX-compliant system with
test(1p).
.SH AUTHOR

88
docs/mm.1 Normal file
View File

@@ -0,0 +1,88 @@
.\" 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
.B -a
.RS
Opens subsequent outputs for appending rather than updating.
.RE
.B -e
.RS
Use the standard error as an output.
.RE
.B -i
.RS
Opens a path as an input. Without any inputs specified mm will use the
standard input. The standard input shall be used as an input if one or more of
the input files is “-”.
.RE
.B -o
.RS
Opens a path as an output. Without any outputs specified mm will use the
standard output. The standard output shall be used as an output if one or more
of the output files is “-”.
.RE
.B -u
.RS
Ensures neither input or output will be buffered.
.RE
.B -n
.RS
Causes SIGINT signals to be ignored.
.RE
.SH DIAGNOSTICS
If an output can no longer be written mm prints a diagnostic message, ceases
writing to that particular output, and if there are more outputs specified,
continues, eventually exiting unsuccessfully.
When an error is encountered, diagnostic message is printed and the program
exits with the appropriate sysexits.h(3) status.
.SH CAVEATS
Existing files are not truncated on ouput and are instead overwritten.
.SH RATIONALE
The cat(1p) and tee(1p) programs specified in POSIX together provide similar
functionality. The separation of the two sets of functionality into separate
APIs seemed unncessary.
.SH COPYRIGHT
Copyright (c) 2024 DTB. License AGPLv3+: GNU AGPL version 3 or later
<https://gnu.org/licenses/agpl.html>.
.SH SEE ALSO
cat(1p), dd(1), dj(1), tee(1p)

View File

@@ -1,5 +1,5 @@
.\" 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,
.\" visit <http://creativecommons.org/licenses/by-sa/4.0/>.
@@ -13,43 +13,50 @@ npc \(en show non-printing characters
.SH SYNOPSIS
npc
.RB ( -eht )
.RB ( -et )
.SH DESCRIPTION
Npc reads from standard input and writes to standard output, replacing non-
printing characters with printable equivalents. Control characters print as a
carat ('^') followed by the character '@' through '_' corresponding to the
character replaced (e.g. control-X becomes "^X"). The delete character (0x7F)
becomes "^?". Characters with the high bit set (>127) are printed as "M-"
Print normally non-printing characters.
The program reads from standard input and writes to standard output, replacing
non-printing characters with printable equivalents. Control characters print as
a carat ('^') followed by the character '@' through '_' corresponding to the
character replaced (e.g. control-X becomes '^X'). The delete character (0x7F)
becomes '^?'. Characters with the high bit set (>127) are printed as 'M-'
followed by the graphical representation for the same character without the
high bit set.
.PP
The
.SH USAGE
.B -e
option prints a currency sign ('$') before each line ending.
.PP
The
.RS
Prints a currency sign ('$') before each line ending.
.RE
.B -t
option prints tab characters as "^I" rather than a literal horizontal tab.
.RS
Prints tab characters as '^I' rather than a literal horizontal tab.
.RE
.SH DIAGNOSTICS
Npc prints a debug message and exits with the appropriate sysexits(3) error
code in the event of an error, otherwise it exits successfully.
In the event of an error, a debug message will be printed and the program will
exit with the appropriate sysexits.h(3) error code.
.SH BUGS
Npc operates in single-byte chunks regardless of intended encoding.
The program operates in single-byte chunks regardless of intended encoding.
.SH RATIONALE
POSIX currently lacks a way to display non-printing characters in the terminal
using a standard tool. A popular extension to cat(1p), the -v option, is the
bandage solution GNU and other software suites use.
using a standard tool. A popular extension to cat(1p), the
.B -v
option, is the bandage solution GNU and other software suites use.
This functionality should be a separate tool because its usefulness extends
beyond that of cat(1p).
This functionality is a separate tool because its usefulness extends beyond that
of cat(1p).
.SH AUTHOR

View File

@@ -17,10 +17,13 @@ rpn
.SH DESCRIPTION
Rpn evaluates reverse polish notation expressions either read from the standard
input or parsed from provided arguments. See the STANDARD INPUT section.
Evaluate reverse polish notation.
Upon evaluation, rpn will print the resulting number on the stack to the
The program evaluates reverse polish notation expressions either read from the
standard input or parsed from provided arguments. See the STANDARD INPUT
section.
Upon evaluation, the program will print the resulting number on the stack to the
standard output. Any further specified numbers will be placed at the end of the
stack.
@@ -28,14 +31,16 @@ For information on for reverse polish notation syntax, see rpn(7).
.SH STANDARD INPUT
If arguments are passed to rpn, it interprets them as an expression to be
evaluated. Otherwise, it reads whitespace-delimited numbers and operations from
the standard input.
If arguments are passed , they are interpreted as an expression to be evaluated.
Otherwise, it reads whitespace-delimited numbers and operations from the
standard input.
.SH DIAGNOSTICS
If encountering a syntax error, rpn will exit with the appropriate error code
as defined by sysexits.h(3) and print an error message.
In the event of a syntax error, the program will print an
In the event of an error, a debug message will be printed and the program will
exit with the appropriate sysexits.h(3) error code.
.SH CAVEATS
@@ -44,7 +49,7 @@ with the IEEE Standard for Floating Point Arithmetic (IEEE 754), floating-point
arithmetic has rounding errors. This is somewhat curbed by using the
machine epsilon as provided by the Rust standard library to which to round
numbers. Because of this, variation is expected in the number of decimal places
rpn can handle based on the platform and hardware of any given machine.
the program can handle based on the platform and hardware of any given machine.
.SH RATIONALE

124
docs/scrut.1 Normal file
View File

@@ -0,0 +1,124 @@
.\" 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 ( -bcdefgkprsuwxLS )
.RB [ file... ]
.SH DESCRIPTION
Determine if files comply with requirements.
.SH OPTIONS
.B -L
.RS
Requires the given files to exist and be symbolic links.
.RE
.B -S
.RS
Requires the given files to exist and be sockets.
.RE
.B -b
.RS
Requires the given files to exist and be block special files.
.RE
.B -c
.RS
Requires the given files to exist and be character special files.
.RE
.B -d
.RS
Requires the given files to exist and be directories.
.RE
.B -e
.RS
Requires the given files to exist, and is redundant to any other option.
.RE
.B -e
.RS
Requires the given files to exist and be regular files.
.RE
.B -g
.RS
Requires the given files to exist and have their set group ID flags set.
.RE
.B -k
.RS
Requires the given files to exist and have their sticky bit set.
.RE
.B -p
.RS
Requires the given files to exist and be named pipes.
.RE
.B -r
.RS
Requires the given files to exist and be readable.
.RE
.B -u
.RS
Requires the given files to exist and have their set user ID flags set.
.RE
.B -w
.RS
Requires the given files to exist and be writable.
.RE
.B -x
.RS
Requires the given files to exist and be executable.
.RE
.SH EXIT STATUS
If the given files comply with the specified requirements, the program will exit
successfully. If not, it exits unsuccessfully.
When invoked incorrectly, a debug message will be printed and the program will
exit with the appropriate sysexits.h(3) error code.
.SH STANDARDS
The test(1p) utility contains functionality that was broken out into separate
programs. Thus, the scope of this program is narrower than it. Notably, the
.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 <trinity@trinity.moe>.
.SH COPYRIGHT
Copyright © 2024 DTB. License AGPLv3+: GNU AGPL version 3 or later
<https://gnu.org/licenses/agpl.html>.
.SH SEE ALSO
access(3p), lstat(3p), test(1p)

View File

@@ -1,5 +1,5 @@
.\" 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,
.\" visit <http://creativecommons.org/licenses/by-sa/4.0/>.
@@ -18,30 +18,27 @@ str
.SH DESCRIPTION
Str tests each character in an arbitrary quantity of string arguments against
the function of the same name within ctype(3).
Test string arguments.
The tests in this program are equivalent to the functions with the same names in
ctype.h(0p) and are the methods by which string arguments are tested.
.SH DIAGNOSTICS
Str exits successfully if all tests pass and unsuccessfully if a test failed.
.PP
Str will exit unsuccessfully if a string is empty, as none of its contents
passed the test.
.PP
Str will print a message to standard error and exit unsuccessfully if used
improperly.
If all tests pass, the program will exit with an exit code of 0. If any of the
tests fail, the program will exit unsuccessfully with an error code of 1.
.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
removed in favor of using strcmp(1) to compare strings against the empty string
('').
When invoked incorrectly, a debug message will be printed and the program will
exit with the appropriate sysexits.h(3) error code.
.SH BUGS
There's no way of knowing which argument failed the test without re-testing
Theres no way of knowing which argument failed the test without re-testing
arguments individually.
.PP
If a character in a string isn't valid ASCII str will exit unsuccessfully.
.SH AUTHOR

View File

@@ -1,5 +1,5 @@
.\" 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,
.\" visit <http://creativecommons.org/licenses/by-sa/4.0/>.
@@ -18,26 +18,27 @@ strcmp
.SH DESCRIPTION
Strcmp checks whether the given strings are the same.
Strcmp exits successfully if the strings are identical. Otherwise, strcmp exits
with the value 1 if an earlier string has a greater byte value than a later
string (e.g.
Check whether string arguments are the same.
.SH DIAGNOSTICS
The program will exit successfully if the strings are identical. Otherwise, it
exits with the value 1 if an earlier string has a greater byte value than a
later string (e.g.
.R strcmp b a
)
and 255 if an earlier string has a lesser byte value (e.g.
.R strcmp a b
).
.SH DIAGNOSTICS
Strcmp will print an error message and exit unsuccessfully with a status
described in sysexits(3) if used incorrectly (given less than two operands).
When invoked incorrectly, a debug message will be printed and the program will
exit with the appropriate sysexits.h(3) error code.
.SH UNICODE
Strcmp will exit unsuccessfully if the given strings are not identical;
Unicode strings may need to be normalized if the intent is to check visual
similarity and not byte similarity.
The program will exit unsuccessfully if the given strings are not identical;
therefore, Unicode strings may need to be normalized if the intent is to check
visual similarity and not byte similarity.
.SH RATIONALE
@@ -45,7 +46,7 @@ The traditional tool for string comparisons in POSIX and other Unix shells has
been test(1). This tool also handles integer comparisons and file scrutiny.
These parts of its functionality have been broken out into multiple utilities.
Strcmps functionality may be performed on a POSIX-compliant system with
This programs functionality may be performed on a POSIX-compliant system with
test(1p).
.SH AUTHOR

77
docs/swab.1 Normal file
View File

@@ -0,0 +1,77 @@
.\" 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 USAGE
Swap the latter and former halves of a block of bytes.
.SH OPTIONS
.B -f
.RS
Ignore system call interruptions.
.RE
.B -w
.RS
Configures the word size; that is, the size in bytes of the block size
on which to operate. By default the word size is 2. The word size must be
cleanly divisible by 2, otherwise the block of bytes being processed can't be
halved.
.RE
.SH EXAMPLES
The following sh(1p) line:
.RS
.R printf 'hello world!\n' | swab
.RE
Produces the following output:
.RS
.R ehll oowlr!d
.RE
.SH DIAGNOSTICS
In the event of an error, a debug message will be printed and the program will
exit with the appropriate sysexits.h(3) error code.
.SH RATIONALE
This program was modeled and named after the
.R conv=swab
functionality specified in the dd(1p) utility. It additionally allows the word
size to be configured.
This functionality is useful for fixing the endianness of binary files produced
on other machines.
.SH COPYRIGHT
Copyright (c) 2024 DTB. License AGPLv3+: GNU AGPL version 3 or later
<https://gnu.org/licenses/agpl.html>.
.SH SEE ALSO
dd(1p)

View File

@@ -1,5 +1,5 @@
.\" 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,
.\" visit <http://creativecommons.org/licenses/by-sa/4.0/>.
@@ -12,14 +12,13 @@ true \(en do nothing, successfully
.SH DESCRIPTION
True does nothing regardless of operands or standard input.
True will always return an exit code of 0.
Do nothing regardless of operands or standard input.
An exit code of 0 will always be returned.
.SH RATIONALE
True exists for the construction of control flow and loops based on a success.
True functions as described in POSIX.1-2017.
In POSIX.1-2017, true(1p) exists for the construction of control flow and loops
based on a success. This implementation functions as described in that standard.
.SH AUTHOR

View File

@@ -203,28 +203,28 @@ Io_fdseek(struct Io *io){
if(!fdisstd(io->fd) && lseek(io->fd, io->seek, SEEK_SET) != -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
* fine because it'll be zeroed as this function returns anyway. */
do{ if( (io->bufuse = (*op)(io->fd, io->buf, MIN(io->bs, io->seek))) == 0)
/* second chance */
io->bufuse = (*op)(io->fd, io->buf, MIN(io->bs, io->seek));
}while((io->seek -= io->bufuse) > 0 && io->bufuse != 0);
/* repeated code to get the condition out of the loop */
if(io->fl == write_flags){
memset(io->buf, '\0', io->bs);
/* We're going to cheat and use bufuse as the retval for write(2),
* which is fine because it'll be zeroed as this function returns
* anyway. */
do{
if((io->bufuse = write(io->fd, io->buf, MIN(io->bs, io->seek)))
== 0)
/* second chance */
io->bufuse = write(io->fd, io->buf, MIN(io->bs, io->seek));
}while((io->seek -= io->bufuse) > 0 && io->bufuse != 0);
}else if(io->fl == read_flags){
do{
if((io->bufuse = read(io->fd, io->buf, MIN(io->bs, io->seek)))
== 0)
/* second chance */
io->bufuse = read(io->fd, io->buf, MIN(io->bs, io->seek));
}while((io->seek -= io->bufuse) > 0 && io->bufuse != 0);
}else
return EX_SOFTWARE;
io->bufuse = 0;

View File

@@ -18,7 +18,7 @@
use std::{
env::args,
io::{ Read, stdin, Write },
io::{ Read, stdin, stdout, Write },
process::{ Command, exit, Stdio },
};
@@ -26,7 +26,7 @@ extern crate sysexits;
extern crate getopt;
use getopt::{ Opt, Parser };
use sysexits::{ EX_DATAERR, EX_USAGE };
use sysexits::{ EX_DATAERR, EX_IOERR, EX_UNAVAILABLE, EX_USAGE };
fn main() {
let argv = args().collect::<Vec<String>>();
@@ -54,43 +54,65 @@ fn main() {
exit(EX_USAGE);
});
let index = argv[index_arg].parse::<usize>().unwrap_or_else(|_| {
eprintln!("{}: {}: Not an integer.", argv[0], argv[1]);
let index = argv[index_arg].parse::<usize>().unwrap_or_else(|e| {
eprintln!("{}: {}: {}.", argv[0], argv[1], e);
exit(EX_DATAERR);
});
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 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())
.args(opts)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.unwrap();
.unwrap_or_else( |e| {
eprintln!("{}: {}: {}.", argv[0], argv[command_arg], e);
exit(EX_UNAVAILABLE);
});
let field = fields.get(index).unwrap_or_else(|| {
eprintln!(
"{}: {}: No such index in input.",
argv[0],
index.to_string()
index.to_string(),
);
exit(EX_DATAERR);
});
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);
}
let output = spawned.wait_with_output().unwrap();
let output = spawned.wait_with_output().unwrap_or_else(|e| {
eprintln!("{}: {}: {}.", argv[0], argv[command_arg], e);
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;
print!("{}", fields.join(&d.to_string()));
stdout().write_all(
fields.join(&d.to_string()).as_bytes()
).unwrap_or_else(|e|{
eprintln!("{}: {}.", argv[0], e);
exit(EX_IOERR);
});
}

107
src/hru.rs Normal file
View File

@@ -0,0 +1,107 @@
/*
* 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 sysexits;
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);
exit(EX_IOERR);
});
}
ExitCode::SUCCESS
}

224
src/mm.c Normal file
View File

@@ -0,0 +1,224 @@
/*
* 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
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:
fprintf(stderr, "Usage: %s (-aenu) (-i [input])..."
" (-o [output])...\n", argv[0]);
retval = EX_USAGE;
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,7 +165,7 @@ fn eval(
Subtract => stack.push_back(y - x),
Multiply => 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()),
Modulo => stack.push_back(y % x),
_ => {},

View File

@@ -18,7 +18,7 @@
#include <stdio.h> /* fprintf(3), stderr, NULL */
#include <stdlib.h> /* EXIT_FAILURE */
#include <string.h> /* strchr(3) */
#include <string.h> /* memset(3), strchr(3) */
#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,
* S_ISFIFO, S_ISGID, S_ISREG, S_ISLNK, S_ISSOCK,
@@ -33,17 +33,24 @@ int main(int argc, char *argv[]){
struct stat buf;
int c;
size_t i;
char *p;
if(argc < 2)
goto usage;
i = 0;
memset(ops, '\0', sizeof ops);
while((c = getopt(argc, argv, args)) != -1)
if(strchr(args, c) == NULL)
if((p = strchr(args, c)) == NULL)
goto usage;
else
ops[i++] = c;
ops[i] = '\0';
ops[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';
}
if(optind == argc)
goto usage;

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