intcmp(1): new tool; npc(1): new tool; scrut(1): new tool; str(1): new tool; strcmp(1): new tool; tests: added POSIX compatibility test and C compiler compatibility test; Makefile: converted to GNUmakefile; README: added README; docs: added docs
This commit is contained in:
parent
b1f6caaf41
commit
ef1416cd42
73
GNUmakefile
Normal file
73
GNUmakefile
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
# Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media>
|
||||||
|
# Copyright (c) 2023 DTB <trinity@trinity.moe>
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
# If we want to use POSIX make we can’t use ifeq
|
||||||
|
# .POSIX:
|
||||||
|
# .PRAGMA: posix_202x
|
||||||
|
.PHONY: clean
|
||||||
|
.PHONY: install
|
||||||
|
.PHONY: test
|
||||||
|
|
||||||
|
PREFIX=/usr/local
|
||||||
|
CC=cc
|
||||||
|
CFLAGS=-O3 -Lbuild
|
||||||
|
|
||||||
|
ifeq ($(CC), gcc)
|
||||||
|
CFLAGS=-O3 -s -Wl,-z,noseparate-code,-z,nosectionheader -flto -Lbuild
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CC), clang)
|
||||||
|
CFLAGS=-O3 -Wall -Lbuild
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CC), tcc)
|
||||||
|
CFLAGS=-O3 -s -Wl -flto -Lbuild
|
||||||
|
endif
|
||||||
|
|
||||||
|
build: build_dir false intcmp scrut str strcmp true
|
||||||
|
|
||||||
|
build_dir:
|
||||||
|
mkdir -p build
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf build/
|
||||||
|
|
||||||
|
install: build
|
||||||
|
mkdir -p $(PREFIX)/bin $(PREFIX)/lib $(PREFIX)/man/man1 $(PREFIX)/man/man3
|
||||||
|
cp -f build/*.o $(PREFIX)/lib/
|
||||||
|
cp -f build/*.so $(PREFIX)/lib/
|
||||||
|
cp -f build/* $(PREFIX)/bin/
|
||||||
|
cp -f docs/*.1 $(PREFIX)/man/man1/
|
||||||
|
cp -f docs/*.3 $(PREFIX)/man/man3/
|
||||||
|
|
||||||
|
test: build
|
||||||
|
tests/cc-compat.sh
|
||||||
|
tests/posix-compat.sh
|
||||||
|
|
||||||
|
false: src/false.c build_dir
|
||||||
|
$(CC) $(CFLAGS) -o build/false src/false.c
|
||||||
|
|
||||||
|
intcmp: src/intcmp.c build_dir
|
||||||
|
$(CC) $(CFLAGS) -o build/intcmp src/intcmp.c
|
||||||
|
|
||||||
|
scrut: src/scrut.c libfileis build_dir
|
||||||
|
$(CC) $(CFLAGS) -lfileis -o build/scrut src/scrut.c
|
||||||
|
|
||||||
|
str: src/str.c build_dir
|
||||||
|
$(CC) $(CFLAGS) -o build/str src/str.c
|
||||||
|
|
||||||
|
strcmp: src/strcmp.c build_dir
|
||||||
|
$(CC) $(CFLAGS) -o build/strcmp src/strcmp.c
|
||||||
|
|
||||||
|
true: src/true.c build_dir
|
||||||
|
$(CC) $(CFLAGS) -o build/true src/true.c
|
||||||
|
|
||||||
|
libfileis: src/libfileis.c src/libfileis.h build_dir
|
||||||
|
$(CC) $(CFLAGS) -c -fPIC -o build/libfileis.o src/libfileis.c
|
||||||
|
$(CC) -shared -o build/libfileis.so build/libfileis.o
|
||||||
|
|
41
Makefile
41
Makefile
@ -1,41 +0,0 @@
|
|||||||
# Copyright (c) 2023 Emma Tebibyte
|
|
||||||
# SPDX-License-Identifier: FSFAP
|
|
||||||
#
|
|
||||||
# Copying and distribution of this file, with or without modification, are
|
|
||||||
# permitted in any medium without royalty provided the copyright notice and this
|
|
||||||
# notice are preserved. This file is offered as-is, without any warranty.
|
|
||||||
|
|
||||||
.POSIX:
|
|
||||||
|
|
||||||
PREFIX=/usr/local
|
|
||||||
CFLAGS=-O3 -s -Wl,-z,noseparate-code,-z,nosectionheader -flto -Lbuild
|
|
||||||
|
|
||||||
build: build_dir cat false tail true
|
|
||||||
|
|
||||||
clean: build_dir
|
|
||||||
rm -rf build/
|
|
||||||
|
|
||||||
cat: src/cat.c build_dir lib
|
|
||||||
cc $(CFLAGS) -lyac -o build/cat src/cat.c
|
|
||||||
|
|
||||||
false: src/false.c build_dir
|
|
||||||
cc $(CFLAGS) -o build/false src/false.c
|
|
||||||
|
|
||||||
tail: src/tail.c build_dir lib
|
|
||||||
cc $(CFLAGS) -lyac -o build/tail src/tail.c
|
|
||||||
|
|
||||||
true: src/true.c build_dir
|
|
||||||
cc $(CFLAGS) -o build/true src/true.c
|
|
||||||
|
|
||||||
lib: src/yac.c src/yac.h
|
|
||||||
cc $(CFLAGS) -c -fPIC -o build/yac.o src/yac.c
|
|
||||||
cc -shared -o build/libyac.so build/yac.o
|
|
||||||
|
|
||||||
build_dir:
|
|
||||||
mkdir -p build
|
|
||||||
|
|
||||||
install: build
|
|
||||||
rm build/*.o
|
|
||||||
mkdir -p $(PREFIX)/lib $(PREFIX)/bin
|
|
||||||
cp -f build/*.so $(PREFIX)/lib/
|
|
||||||
cp -f build/* $(PREFIX)/bin/
|
|
32
README
Normal file
32
README
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
“Seek not to walk the path of the masters; seek what they sought.”
|
||||||
|
– Matsuo Basho
|
||||||
|
|
||||||
|
The Bonsai core utilities are the result of the careful examination of the
|
||||||
|
current state of POSIX and Unix utilies. The Unix Philosophy, “do one thing and
|
||||||
|
do it well” is its core but these tools do not cling to the names of the past.
|
||||||
|
|
||||||
|
The era of the original Unix tools has been long and fruitful, but they have
|
||||||
|
their flaws. The new, non-POSIX era of this project started with frustration
|
||||||
|
with the way certain tools work and how other projects that extend POSIX don’t
|
||||||
|
make anything better.
|
||||||
|
|
||||||
|
This project will not follow in the footsteps of GNU; extensions of POSIX will
|
||||||
|
not be found here. GNU extensions are a gateway to the misuse of the shell. The
|
||||||
|
Bonsai core utilities will intentionally discourage use of the shell for
|
||||||
|
purposes beyond its scope.
|
||||||
|
|
||||||
|
See docs/ for more on the specific utilities currently implemented.
|
||||||
|
|
||||||
|
Read More
|
||||||
|
|
||||||
|
An Introduction to the Unix Shell
|
||||||
|
<https://porkmail.org/era/unix/shell>
|
||||||
|
|
||||||
|
Master Foo and the Ten Thousand Lines
|
||||||
|
<http://www.catb.org/~esr/writings/unix-koans/ten-thousand.html>
|
||||||
|
|
||||||
|
Master Foo Discourses on the Unix-Nature
|
||||||
|
<http://www.catb.org/~esr/writings/unix-koans/unix-nature.html>
|
||||||
|
|
||||||
|
Shell Programming!
|
||||||
|
<https://tldp.org/LDP/abs/html/why-shell.html>
|
35
docs/false.1
Normal file
35
docs/false.1
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
.\" Copyright (c) 2022 DTB <trinity@trinity.moe>
|
||||||
|
.\" Copyright (c) 2023 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 FALSE 1
|
||||||
|
|
||||||
|
.SH NAME
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
.SH RATIONALE
|
||||||
|
|
||||||
|
False exists for the construction of control flow and loops based on a failure.
|
||||||
|
|
||||||
|
False functions as described in POSIX.1-2017.
|
||||||
|
|
||||||
|
.SH AUTHOR
|
||||||
|
|
||||||
|
Written by Emma Tebibyte <emma@tebibyte.media>.
|
||||||
|
|
||||||
|
.SH COPYRIGHT
|
||||||
|
|
||||||
|
This work is marked with CC0 1.0. To see a copy of this license, visit
|
||||||
|
<http://creativecommons.org/publicdomain/zero/1.0>.
|
||||||
|
|
||||||
|
.SH SEE ALSO
|
||||||
|
|
||||||
|
true(1)
|
78
docs/intcmp.1
Normal file
78
docs/intcmp.1
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
.\" Copyright (c) 2023 DTB <trinity@trinity.moe>
|
||||||
|
.\" Copyright (c) 2023 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 intcmp 1
|
||||||
|
|
||||||
|
.SH NAME
|
||||||
|
|
||||||
|
intcmp \(en compare integers
|
||||||
|
|
||||||
|
.SH SYNOPSIS
|
||||||
|
|
||||||
|
intcmp
|
||||||
|
.RB ( -eghl )
|
||||||
|
.RB [ integer ]
|
||||||
|
.RB [ integer... ]
|
||||||
|
|
||||||
|
.SH DESCRIPTION
|
||||||
|
|
||||||
|
Intcmp compares integers.
|
||||||
|
|
||||||
|
.SH USAGE
|
||||||
|
|
||||||
|
The -e option permits given integers to be equal to each other. If combined
|
||||||
|
with -g or -l, only adjacent integers in the argument sequence can be equal.
|
||||||
|
.PP
|
||||||
|
The -g option permits a given integer to be greater than the following integer.
|
||||||
|
.PP
|
||||||
|
The -l option permits a given integer to be less than the following integer.
|
||||||
|
.PP
|
||||||
|
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,
|
||||||
|
.R intcmp -l 1 2 3
|
||||||
|
is equivalent to evaluating "1 < 2 < 3".
|
||||||
|
|
||||||
|
.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.
|
||||||
|
|
||||||
|
.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
|
||||||
|
program usage and may be abused to function as an integer validator.
|
||||||
|
Use str(1) instead.
|
||||||
|
|
||||||
|
.SH RATIONALE
|
||||||
|
|
||||||
|
The traditional tool for integer comparisons in POSIX and other Unix shells has
|
||||||
|
been test(1). This tool also handles string comparisons and file scrutiny.
|
||||||
|
These parts of its functionality have been broken out into multiple utilities.
|
||||||
|
|
||||||
|
Strcmp’s functionality may be performed on a POSIX-compliant system with
|
||||||
|
test(1p).
|
||||||
|
|
||||||
|
.SH AUTHOR
|
||||||
|
|
||||||
|
Written by DTB <trinity@trinity.moe>.
|
||||||
|
|
||||||
|
.SH COPYRIGHT
|
||||||
|
|
||||||
|
Copyright © 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later
|
||||||
|
<https://gnu.org/licenses/gpl.html>.
|
||||||
|
|
||||||
|
.SH SEE ALSO
|
||||||
|
|
||||||
|
strcmp(1), scrut(1), str(1), test(1)
|
68
docs/npc.1
Normal file
68
docs/npc.1
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
.\" Copyright (c) 2023 DTB <trinity@trinity.moe>
|
||||||
|
.\" Copyright (c) 2023 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 npc 1
|
||||||
|
|
||||||
|
.SH NAME
|
||||||
|
|
||||||
|
npc \(en show non-printing characters
|
||||||
|
|
||||||
|
.SH SYNOPSIS
|
||||||
|
|
||||||
|
npc
|
||||||
|
.RB ( -eht )
|
||||||
|
|
||||||
|
.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-"
|
||||||
|
followed by the graphical representation for the same character without the
|
||||||
|
high bit set.
|
||||||
|
.PP
|
||||||
|
The
|
||||||
|
.B -e
|
||||||
|
option prints a currency sign ('$') before each line ending.
|
||||||
|
.PP
|
||||||
|
The
|
||||||
|
.B -t
|
||||||
|
option prints tab characters as "^I" rather than a literal horizontal tab.
|
||||||
|
|
||||||
|
.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.
|
||||||
|
|
||||||
|
.SH BUGS
|
||||||
|
|
||||||
|
Npc operates in single-byte chunks regardless of intended encoding.
|
||||||
|
|
||||||
|
.SH RATIONALE
|
||||||
|
|
||||||
|
POSIX currently lacks a way to display non-printing characters in the terminal
|
||||||
|
using a standard tool. A popular extension to cat(1p), the -v option, is the
|
||||||
|
bandage solution GNU and other software suites use.
|
||||||
|
|
||||||
|
This functionality should be a separate tool because its usefulness extends
|
||||||
|
beyond that of cat(1p).
|
||||||
|
|
||||||
|
.SH AUTHOR
|
||||||
|
|
||||||
|
Written by DTB <trinity@trinity.moe>.
|
||||||
|
|
||||||
|
.SH COPYRIGHT
|
||||||
|
|
||||||
|
Copyright © 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later
|
||||||
|
<https://gnu.org/licenses/agpl.html>.
|
||||||
|
|
||||||
|
.SH SEE ALSO
|
||||||
|
|
||||||
|
cat(1), cat-v(1)
|
||||||
|
|
||||||
|
.I UNIX Style, or cat -v Considered Harmful
|
||||||
|
by Rob Pike
|
58
docs/str.1
Normal file
58
docs/str.1
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
.\" Copyright (c) 2023 DTB <trinity@trinity.moe>
|
||||||
|
.\" Copyright (c) 2023 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 STR 1
|
||||||
|
|
||||||
|
.SH NAME
|
||||||
|
|
||||||
|
str \(en test the character types of string arguments
|
||||||
|
|
||||||
|
.SH SYNOPSIS
|
||||||
|
|
||||||
|
str
|
||||||
|
.RB [ type ]
|
||||||
|
.RB [ string... ]
|
||||||
|
|
||||||
|
.SH DESCRIPTION
|
||||||
|
|
||||||
|
Str tests each character in an arbitrary quantity of string arguments against
|
||||||
|
the function of the same name within ctype(3).
|
||||||
|
|
||||||
|
.SH DIAGNOSTICS
|
||||||
|
|
||||||
|
Str exits successfully if all tests pass and unsuccessfully if a test failed.
|
||||||
|
.PP
|
||||||
|
Str will exit unsuccessfully if a string is empty, as none of its contents
|
||||||
|
passed the test.
|
||||||
|
.PP
|
||||||
|
Str will print a message to standard error and exit unsuccessfully if used
|
||||||
|
improperly.
|
||||||
|
|
||||||
|
.SH DEPRECATED FEATURES
|
||||||
|
|
||||||
|
Str used to have an "isvalue" type as an extension to ctype(3). This was
|
||||||
|
removed in favor of using strcmp(1) to compare strings against the empty string
|
||||||
|
('').
|
||||||
|
|
||||||
|
.SH BUGS
|
||||||
|
|
||||||
|
There's no way of knowing which argument failed the test without re-testing
|
||||||
|
arguments individually.
|
||||||
|
.PP
|
||||||
|
If a character in a string isn't valid ASCII str will exit unsuccessfully.
|
||||||
|
|
||||||
|
.SH AUTHOR
|
||||||
|
|
||||||
|
Written by DTB <trinity@trinity.moe>.
|
||||||
|
|
||||||
|
.SH COPYRIGHT
|
||||||
|
|
||||||
|
Copyright © 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later
|
||||||
|
<https://gnu.org/licenses/gpl.html>.
|
||||||
|
|
||||||
|
.SH SEE ALSO
|
||||||
|
|
||||||
|
ctype(3), strcmp(1), ascii(7)
|
63
docs/strcmp.1
Normal file
63
docs/strcmp.1
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
.\" Copyright (c) 2023 DTB <trinity@trinity.moe>
|
||||||
|
.\" Copyright (c) 2023 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 STRCMP 1
|
||||||
|
|
||||||
|
.SH NAME
|
||||||
|
|
||||||
|
strcmp \(en compare strings
|
||||||
|
|
||||||
|
.SH SYNOPSIS
|
||||||
|
|
||||||
|
strcmp
|
||||||
|
.RM [ string ]
|
||||||
|
.RB [ strings... ]
|
||||||
|
|
||||||
|
.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.
|
||||||
|
.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).
|
||||||
|
|
||||||
|
.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.
|
||||||
|
|
||||||
|
.SH RATIONALE
|
||||||
|
|
||||||
|
The traditional tool for string comparisons in POSIX and other Unix shells has
|
||||||
|
been test(1). This tool also handles integer comparisons and file scrutiny.
|
||||||
|
These parts of its functionality have been broken out into multiple utilities.
|
||||||
|
|
||||||
|
Strcmp’s functionality may be performed on a POSIX-compliant system with
|
||||||
|
test(1p).
|
||||||
|
|
||||||
|
.SH AUTHOR
|
||||||
|
|
||||||
|
Written by DTB <trinity@trinity.moe>.
|
||||||
|
|
||||||
|
.SH COPYRIGHT
|
||||||
|
|
||||||
|
Copyright © 2023 DTB. License AGPLv3+: GNU AGPL version 3 or later
|
||||||
|
<https://gnu.org/licenses/gpl.html>.
|
||||||
|
|
||||||
|
.SH SEE ALSO
|
||||||
|
|
||||||
|
strcmp(3), intcmp(1), scrut(1), test(1)
|
35
docs/true.1
Normal file
35
docs/true.1
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
.\" Copyright (c) 2022 DTB <trinity@trinity.moe>
|
||||||
|
.\" Copyright (c) 2023 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 TRUE 1
|
||||||
|
|
||||||
|
.SH NAME
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
.SH RATIONALE
|
||||||
|
|
||||||
|
True exists for the construction of control flow and loops based on a success.
|
||||||
|
|
||||||
|
True functions as described in POSIX.1-2017.
|
||||||
|
|
||||||
|
.SH AUTHOR
|
||||||
|
|
||||||
|
Written by Emma Tebibyte <emma@tebibyte.media>.
|
||||||
|
|
||||||
|
.SH COPYRIGHT
|
||||||
|
|
||||||
|
This work is marked with CC0 1.0. To see a copy of this license, visit
|
||||||
|
<http://creativecommons.org/publicdomain/zero/1.0>.
|
||||||
|
|
||||||
|
.SH SEE ALSO
|
||||||
|
|
||||||
|
false(1)
|
104
src/cat.c
104
src/cat.c
@ -1,104 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media>
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
||||||
*
|
|
||||||
* This file is part of YAC coreutils.
|
|
||||||
*
|
|
||||||
* YAC coreutils 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.
|
|
||||||
*
|
|
||||||
* YAC coreutils 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>
|
|
||||||
#include <sysexits.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "yac.h"
|
|
||||||
|
|
||||||
void cat(FILE *file, bool u) {
|
|
||||||
int byte = 0; /* variable for storing bytes as they are read */
|
|
||||||
int p = 0; /* index counter for bytes in buffered reading */
|
|
||||||
char buf[4096]; /* buffer for buffered reading */
|
|
||||||
|
|
||||||
if (u) {
|
|
||||||
while ((byte = fgetc(file)) != EOF) { putchar(byte); }
|
|
||||||
} else {
|
|
||||||
while ((byte = fgetc(file)) != EOF) {
|
|
||||||
if (p > sizeof(buf) - 1) {
|
|
||||||
fputs(buf, stdout);
|
|
||||||
p = 0;
|
|
||||||
} else {
|
|
||||||
buf[p] = byte;
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fwrite(buf, 1, p, stdout);
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
bool u = false;
|
|
||||||
int opt;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
extern int optind;
|
|
||||||
while ((opt = getopt(argc, argv, "u")) != -1) {
|
|
||||||
switch (opt) {
|
|
||||||
/*
|
|
||||||
* From cat(1p):
|
|
||||||
*
|
|
||||||
* -u Write bytes from the input file to the standard output
|
|
||||||
* without delay as each is read.
|
|
||||||
*/
|
|
||||||
case 'u':
|
|
||||||
u = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "Usage: %s (-u) file...\n", argv[0]);
|
|
||||||
return EX_USAGE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* From cat(1p):
|
|
||||||
*
|
|
||||||
* file A pathname of an input file. If no file operands are
|
|
||||||
* specified, the standard input shall be used. If a file is
|
|
||||||
* '-', the cat utility shall read from the standard input at
|
|
||||||
* that point in the sequence. The cat utility shall not close
|
|
||||||
* and reopen standard input when it is referenced in this way,
|
|
||||||
* but shall accept multiple occurrences of '-' as a file
|
|
||||||
* operand.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (optind == argc) {
|
|
||||||
cat(stdin, u);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE *file;
|
|
||||||
|
|
||||||
for (i = optind; i < argc; i++) {
|
|
||||||
file = rpath(argv[0], argv[i]);
|
|
||||||
if (file != NULL) {
|
|
||||||
cat(file, u);
|
|
||||||
if (file != stdin) { fclose(file); }
|
|
||||||
} else { continue; }
|
|
||||||
}
|
|
||||||
|
|
||||||
return EX_OK;
|
|
||||||
}
|
|
18
src/false.c
18
src/false.c
@ -1,21 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media>
|
* Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media>
|
||||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
* SPDX-License-Identifier: CC0
|
||||||
*
|
*
|
||||||
* This file is part of YAC coreutils.
|
* This work is marked with CC0 1.0. To view a copy of this license, visit
|
||||||
*
|
* <http://creativecommons.org/publicdomain/zero/1.0>.
|
||||||
* YAC coreutils 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.
|
|
||||||
*
|
|
||||||
* YAC coreutils 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/.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int main() { return 1; }
|
int main() { return 1; }
|
||||||
|
84
src/intcmp.c
Normal file
84
src/intcmp.c
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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 <stdio.h> /* fprintf(3), stderr */
|
||||||
|
#include <stdlib.h> /* strtol(3), size_t */
|
||||||
|
#ifndef EX_USAGE
|
||||||
|
# include <sysexits.h> /* EX_USAGE */
|
||||||
|
#endif
|
||||||
|
#include <unistd.h> /* getopt(3), optind */
|
||||||
|
|
||||||
|
/* 0b00? */ /* Equal | -e | 0b001 | 1 */
|
||||||
|
#define EQUAL 0x01 /* Greater | -g | 0b010 | 2 */
|
||||||
|
/* 0b0?0 */ /* Greater or Equal | -ge | 0b011 | 3 */
|
||||||
|
#define GREATER 0x02 /* Less | -l | 0b100 | 4 */
|
||||||
|
/* 0b?00 */ /* Less or Equal | -le | 0b101 | 5 */
|
||||||
|
#define LESS 0x04 /* Inequal (Greater or Less) | -gl | 0b110 | 6 */
|
||||||
|
|
||||||
|
static char *program_name = "intcmp";
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]){
|
||||||
|
int c;
|
||||||
|
size_t i;
|
||||||
|
unsigned char mode;
|
||||||
|
int r; /* reference integer */
|
||||||
|
|
||||||
|
mode = 0;
|
||||||
|
|
||||||
|
if(argc < 3)
|
||||||
|
goto usage;
|
||||||
|
|
||||||
|
while((c = getopt(argc, argv, "egl")) != -1)
|
||||||
|
switch(c){
|
||||||
|
case 'e': mode |= EQUAL; break;
|
||||||
|
case 'g': mode |= GREATER; break;
|
||||||
|
case 'l': mode |= LESS; break;
|
||||||
|
default: goto usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(optind + 2 /* ref cmp */ > argc){
|
||||||
|
usage: fprintf(stderr,
|
||||||
|
"Usage: %s (-eghl) [integer] [integer...]\n",
|
||||||
|
argv[0] == NULL ? program_name : argv[0]);
|
||||||
|
return EX_USAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = optind;
|
||||||
|
|
||||||
|
do{ r = c;
|
||||||
|
c = strtol(argv[i], &argv[i], 10);
|
||||||
|
if(*argv[i] != '\0' || errno != 0){
|
||||||
|
fprintf(stderr, "%s: argument #%d: Invalid integer\n",
|
||||||
|
argv[0], (int)i);
|
||||||
|
return EX_USAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(i == optind)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* rule enforcement; if a mode isn't permitted and the numbers
|
||||||
|
* correspond to it, return 1 */
|
||||||
|
if( (!(mode & EQUAL) && r == c)
|
||||||
|
|| (!(mode & GREATER) && r > c)
|
||||||
|
|| (!(mode & LESS) && r < c))
|
||||||
|
return 1;
|
||||||
|
}while(++i < argc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
63
src/libfileis.c
Normal file
63
src/libfileis.c
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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 "libfileis.h"
|
||||||
|
|
||||||
|
#include <unistd.h> /* access(3), F_OK, R_OK, W_OK, X_OK */
|
||||||
|
|
||||||
|
int f_executable(char *path){ return access(path, X_OK) == 0; } /* test -x */
|
||||||
|
int f_exists(char *path){ return access(path, F_OK) == 0; } /* test -e */
|
||||||
|
int f_readable(char *path){ return access(path, R_OK) == 0; } /* test -r */
|
||||||
|
int f_writeable(char *path){ return access(path, W_OK) == 0; } /* test -w */
|
||||||
|
|
||||||
|
#include <sys/stat.h> /* lstat(3), struct stat, S_ISBLK, S_ISCHR, S_ISDIR,
|
||||||
|
* S_ISFIFO, S_ISGID, S_ISREG, S_ISLNK, S_ISSOCK,
|
||||||
|
* S_ISUID, S_ISVTX */
|
||||||
|
|
||||||
|
static struct stat buf;
|
||||||
|
|
||||||
|
int f_blockspecial(char *path){ /* test -b */
|
||||||
|
return lstat(path, &buf) != -1 && S_ISBLK(buf.st_mode);
|
||||||
|
}
|
||||||
|
int f_charspecial(char *path){ /* test -c */
|
||||||
|
return lstat(path, &buf) != -1 && S_ISCHR(buf.st_mode);
|
||||||
|
}
|
||||||
|
int f_directory(char *path){ /* test -d */
|
||||||
|
return lstat(path, &buf) != -1 && S_ISDIR(buf.st_mode);
|
||||||
|
}
|
||||||
|
int f_fifospecial(char *path){ /* test -p */
|
||||||
|
return lstat(path, &buf) != -1 && S_ISFIFO(buf.st_mode);
|
||||||
|
}
|
||||||
|
int f_gid(char *path){ /* test -g */
|
||||||
|
return lstat(path, &buf) != -1 && (buf.st_mode & S_ISGID);
|
||||||
|
}
|
||||||
|
int f_regular(char *path){ /* test -f */
|
||||||
|
return lstat(path, &buf) != -1 && S_ISREG(buf.st_mode);
|
||||||
|
}
|
||||||
|
int f_socket(char *path){ /* test -S */
|
||||||
|
return lstat(path, &buf) != -1 && S_ISSOCK(buf.st_mode);
|
||||||
|
}
|
||||||
|
int f_sticky(char *path){ /* test -k */
|
||||||
|
return lstat(path, &buf) != -1 && (buf.st_mode & S_ISVTX);
|
||||||
|
}
|
||||||
|
int f_symlink(char *path){ /* test -h; test -L */
|
||||||
|
return lstat(path, &buf) != -1 && S_ISLNK(buf.st_mode);
|
||||||
|
}
|
||||||
|
int f_uid(char *path){ /* test -u */
|
||||||
|
return lstat(path, &buf) != -1 && (buf.st_mode & S_ISUID);
|
||||||
|
}
|
62
src/libfileis.h
Normal file
62
src/libfileis.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* libfileis functions return true if the condition is true and false if the
|
||||||
|
* condition is false. Returned values are 0 or 1 only. */
|
||||||
|
|
||||||
|
/* True if file exists and is a block special file. */
|
||||||
|
int f_blockspecial(char *path);
|
||||||
|
|
||||||
|
/* True if file exists and is a character special file. */
|
||||||
|
int f_charspecial(char *path);
|
||||||
|
|
||||||
|
/* True if file exists and is a directory. */
|
||||||
|
int f_directory(char *path);
|
||||||
|
|
||||||
|
/* True if file exists and is executable. */
|
||||||
|
int f_executable(char *path);
|
||||||
|
|
||||||
|
/* True if file exists (regardless of type). */
|
||||||
|
int f_exists(char *path);
|
||||||
|
|
||||||
|
/* True if file exists and is a named pipe (FIFO). */
|
||||||
|
int f_fifospecial(char *path);
|
||||||
|
|
||||||
|
/* True if file exists and its set group ID flag is set. */
|
||||||
|
int f_gid(char *path);
|
||||||
|
|
||||||
|
/* True if file exists and is readable. */
|
||||||
|
int f_readable(char *path);
|
||||||
|
|
||||||
|
/* True if file exists and is a regular file. */
|
||||||
|
int f_regular(char *path);
|
||||||
|
|
||||||
|
/* True if file exists and is a socket. */
|
||||||
|
int f_socket(char *path);
|
||||||
|
|
||||||
|
/* True if file exists and its sticky bit is set. */
|
||||||
|
int f_sticky(char *path);
|
||||||
|
|
||||||
|
/* True if file exists and is a symbolic link. */
|
||||||
|
int f_symlink(char *path);
|
||||||
|
|
||||||
|
/* True if file exists and its set user ID flag is set. */
|
||||||
|
int f_uid(char *path);
|
||||||
|
|
||||||
|
/* True if file exists and is writeable. */
|
||||||
|
int f_writeable(char *path);
|
64
src/npc.c
Normal file
64
src/npc.c
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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 <stdio.h> /* fprintf(3), fputs(3), getc(3), putc(3), stdin, stdout,
|
||||||
|
* EOF */
|
||||||
|
#include <unistd.h> /* getopt(3) */
|
||||||
|
#if !defined EX_USAGE || !defined EX_OK
|
||||||
|
# include <sysexits.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]){
|
||||||
|
int c;
|
||||||
|
char showend;
|
||||||
|
char showtab;
|
||||||
|
|
||||||
|
showend = 0;
|
||||||
|
showtab = 0;
|
||||||
|
|
||||||
|
if(argc > 0)
|
||||||
|
while((c = getopt(argc, argv, "et")) != -1)
|
||||||
|
switch(c){
|
||||||
|
case 'e': showend = 1; break;
|
||||||
|
case 't': showtab = 1; break;
|
||||||
|
default: goto usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(argc > optind){
|
||||||
|
usage: fprintf(stderr, "Usage: %s (-eht)\n", argv[0]);
|
||||||
|
return EX_USAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
while((c = getc(stdin)) != EOF){
|
||||||
|
if((c & 0x80) != 0)
|
||||||
|
fputs("M-", stdout);
|
||||||
|
switch(c ^ 0x80 /* 0b 1000 0000 */){
|
||||||
|
case 0x7f: fputs("^?", stdout);
|
||||||
|
break;
|
||||||
|
case '\n': if(showend)
|
||||||
|
putc('$', stdout);
|
||||||
|
default:
|
||||||
|
if(c >= ' ' || c == '\n' || (!showtab && c == '\t'))
|
||||||
|
putc(c, stdout);
|
||||||
|
else
|
||||||
|
fprintf(stdout, "^%c", c + '@');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EX_OK;
|
||||||
|
}
|
98
src/scrut.c
Normal file
98
src/scrut.c
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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 <stdio.h> /* fprintf(3), stderr, NULL */
|
||||||
|
#include <string.h> /* 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 <sys/stat.h> /* lstat(3), stat struct, S_ISBLK, S_ISCHR, S_ISDIR,
|
||||||
|
* S_ISFIFO, S_ISGID, S_ISREG, S_ISLNK, S_ISSOCK,
|
||||||
|
* S_ISUID, S_ISVTX */
|
||||||
|
|
||||||
|
static char args[] = "bcdefghkprsuwxLS";
|
||||||
|
static char ops[(sizeof args) / (sizeof *args)];
|
||||||
|
static char *program_name = "scrut";
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]){
|
||||||
|
struct stat buf;
|
||||||
|
int c;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if(argc < 2)
|
||||||
|
goto usage;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while((c = getopt(argc, argv, args)) != -1)
|
||||||
|
if(strchr(args, c) == NULL)
|
||||||
|
goto usage;
|
||||||
|
else
|
||||||
|
ops[i++] = c;
|
||||||
|
ops[i] = '\0';
|
||||||
|
|
||||||
|
if(optind == argc)
|
||||||
|
goto usage;
|
||||||
|
|
||||||
|
argv += optind;
|
||||||
|
do{ if(access(*argv, F_OK) != 0 || lstat(*argv, &buf) == -1)
|
||||||
|
return 1; /* doesn't exist or isn't stattable */
|
||||||
|
|
||||||
|
for(i = 0; ops[i] != '\0'; ++i)
|
||||||
|
if(ops[i] == 'e')
|
||||||
|
continue;
|
||||||
|
else if(ops[i] == 'h'){
|
||||||
|
usage: fprintf(stderr, "Usage: %s (-%s) [file...]\n",
|
||||||
|
argv[0] == NULL
|
||||||
|
? program_name
|
||||||
|
: argv[0],
|
||||||
|
args);
|
||||||
|
|
||||||
|
return EX_USAGE;
|
||||||
|
}else if(
|
||||||
|
(ops[i] == 'b'
|
||||||
|
&& !S_ISBLK(buf.st_mode))
|
||||||
|
|| (ops[i] == 'c'
|
||||||
|
&& !S_ISCHR(buf.st_mode))
|
||||||
|
|| (ops[i] == 'd'
|
||||||
|
&& !S_ISDIR(buf.st_mode))
|
||||||
|
|| (ops[i] == 'f'
|
||||||
|
&& !S_ISREG(buf.st_mode))
|
||||||
|
|| (ops[i] == 'g'
|
||||||
|
&& !(buf.st_mode & S_ISGID))
|
||||||
|
|| (ops[i] == 'k'
|
||||||
|
&& !(buf.st_mode & S_ISVTX))
|
||||||
|
|| (ops[i] == 'p'
|
||||||
|
&& !S_ISFIFO(buf.st_mode))
|
||||||
|
|| (ops[i] == 'r'
|
||||||
|
&& access(*argv, R_OK) != 0)
|
||||||
|
|| (ops[i] == 'u'
|
||||||
|
&& !(buf.st_mode & S_ISUID))
|
||||||
|
|| (ops[i] == 'w'
|
||||||
|
&& access(*argv, W_OK) != 0)
|
||||||
|
|| (ops[i] == 'x'
|
||||||
|
&& access(*argv, X_OK) != 0)
|
||||||
|
|| (ops[i] == 'L'
|
||||||
|
&& !S_ISLNK(buf.st_mode))
|
||||||
|
|| (ops[i] == 'S'
|
||||||
|
&& !S_ISSOCK(buf.st_mode)))
|
||||||
|
return 1;
|
||||||
|
}while(*++argv != NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
75
src/str.c
Normal file
75
src/str.c
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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 <ctype.h>
|
||||||
|
#include <stddef.h> /* NULL */
|
||||||
|
#include <stdio.h> /* fprintf(3) */
|
||||||
|
#include <string.h> /* strcmp(3) */
|
||||||
|
#if !defined EX_USAGE
|
||||||
|
# include <sysexits.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static char *program_name = "str";
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
char *name;
|
||||||
|
int (*f)(int);
|
||||||
|
}ctypes[] = {
|
||||||
|
{ "isalnum", isalnum },
|
||||||
|
{ "isalpha", isalpha },
|
||||||
|
{ "isblank", isblank },
|
||||||
|
{ "iscntrl", iscntrl },
|
||||||
|
{ "isdigit", isdigit },
|
||||||
|
{ "isxdigit", isxdigit },
|
||||||
|
{ "isgraph", isgraph },
|
||||||
|
{ "islower", islower },
|
||||||
|
{ "isprint", isprint },
|
||||||
|
{ "ispunct", ispunct },
|
||||||
|
{ "isspace", isspace },
|
||||||
|
{ "isupper", isupper }
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]){
|
||||||
|
int ctype;
|
||||||
|
int i;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if(argc >= 3){
|
||||||
|
for(ctype = 0; ctype < (sizeof ctypes) / (sizeof *ctypes);
|
||||||
|
++ctype)
|
||||||
|
if(strcmp(argv[1], ctypes[ctype].name) == 0)
|
||||||
|
goto pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Usage: %s [type] [string...]\n",
|
||||||
|
argv[0] == NULL ? program_name : argv[0]);
|
||||||
|
|
||||||
|
return EX_USAGE;
|
||||||
|
|
||||||
|
pass: for(argv += 2, r = 1; *argv != NULL; ++argv)
|
||||||
|
for(i = 0; argv[0][i] != '\0'; ++i)
|
||||||
|
/* First checks if argv[0][i] is valid ASCII; ctypes(3)
|
||||||
|
* don't handle non-ASCII.
|
||||||
|
* This is bad. */
|
||||||
|
if(argv[0][i] < 0x80 && !ctypes[ctype].f(argv[0][i]))
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
r = 0;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
25
src/strcmp.c
Normal file
25
src/strcmp.c
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include <stdio.h> /* fprintf(3), stderr */
|
||||||
|
#ifndef EX_USAGE
|
||||||
|
# include <sysexits.h> /* EX_USAGE */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static char *program_name = "strcmp";
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]){
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(argc < 3){
|
||||||
|
fprintf(stderr, "Usage: %s [string] [string...]\n",
|
||||||
|
argv[0] == NULL ? program_name : argv[0]);
|
||||||
|
return EX_USAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(; *argv[1] != '\0'; ++argv[1])
|
||||||
|
for(i = 2; i < argc; ++i)
|
||||||
|
if(*argv[i-1] > *argv[i])
|
||||||
|
return 1;
|
||||||
|
else if(*argv[i-1] < *argv[i]++)
|
||||||
|
return -1; /* actually 255 */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
209
src/tail.c
209
src/tail.c
@ -1,209 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media>
|
|
||||||
* Copyright (c) 2023 Marceline Cramer <mars@tebibyte.media>
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
||||||
*
|
|
||||||
* This file is part of YAC coreutils.
|
|
||||||
*
|
|
||||||
* YAC coreutils 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.
|
|
||||||
*
|
|
||||||
* YAC coreutils 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>
|
|
||||||
#include <sysexits.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "yac.h"
|
|
||||||
|
|
||||||
typedef struct string_t {
|
|
||||||
char *mem;
|
|
||||||
int len;
|
|
||||||
int capacity;
|
|
||||||
} string_t;
|
|
||||||
|
|
||||||
string_t *string_new() {
|
|
||||||
string_t *string = calloc(1, sizeof(string_t));
|
|
||||||
string->capacity = 1024;
|
|
||||||
string->len = 0;
|
|
||||||
string->mem = calloc(string->capacity, sizeof(char));
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
|
|
||||||
void string_putc(string_t *string, char c) {
|
|
||||||
string->mem[string->len] = c;
|
|
||||||
string->len++;
|
|
||||||
if (string->len >= string->capacity) {
|
|
||||||
string->capacity *= 2;
|
|
||||||
string->mem = realloc(string->mem, string->capacity * sizeof(char));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void tailc(FILE *f, long num) {}
|
|
||||||
|
|
||||||
void tailn(FILE *f, long num) {
|
|
||||||
string_t *lines[num];
|
|
||||||
int cursor = 0;
|
|
||||||
int looped = 0;
|
|
||||||
|
|
||||||
lines[cursor] = string_new();
|
|
||||||
|
|
||||||
int c = fgetc(f);
|
|
||||||
for (;;) {
|
|
||||||
if (c == EOF) {
|
|
||||||
string_putc(lines[cursor], '\0');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
string_putc(lines[cursor], c);
|
|
||||||
|
|
||||||
if (c == '\n') {
|
|
||||||
string_putc(lines[cursor], '\0');
|
|
||||||
|
|
||||||
if ((c = fgetc(f)) == EOF) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (++cursor >= num) {
|
|
||||||
looped = 1;
|
|
||||||
cursor = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
lines[cursor] = string_new();
|
|
||||||
} else {
|
|
||||||
c = fgetc(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int read = looped ? cursor + 1 : 0;
|
|
||||||
do {
|
|
||||||
if (read >= num) {
|
|
||||||
read = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
fputs(lines[read]->mem, stdout);
|
|
||||||
} while (read++ != cursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tailf(FILE *file) {
|
|
||||||
int byte;
|
|
||||||
|
|
||||||
while(true) {
|
|
||||||
if ((byte = fgetc(file)) != EOF) { putchar(byte); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
bool c = false;
|
|
||||||
bool f = false;
|
|
||||||
bool n = false;
|
|
||||||
int i;
|
|
||||||
int opt;
|
|
||||||
long num;
|
|
||||||
void (*fn)(FILE *, long) = tailn;
|
|
||||||
|
|
||||||
extern int optind;
|
|
||||||
while ((opt = getopt(argc, argv, "c:fn:")) != -1) {
|
|
||||||
switch (opt) {
|
|
||||||
/*
|
|
||||||
* From tail(1p):
|
|
||||||
*
|
|
||||||
* -c number The application shall ensure that the number option-argument
|
|
||||||
* is a decimal integer, optionally including a sign. The sign
|
|
||||||
* shall affect the location in the file, measured in bytes, to
|
|
||||||
* begin the copying:
|
|
||||||
*
|
|
||||||
* ┌─────┬────────────────────────────────────────┐
|
|
||||||
* │Sign │ Copying Starts │
|
|
||||||
* ├─────┼────────────────────────────────────────┤
|
|
||||||
* │ + │ Relative to the beginning of the file. │
|
|
||||||
* │ - │ Relative to the end of the file. │
|
|
||||||
* │none │ Relative to the end of the file. │
|
|
||||||
* └─────┴────────────────────────────────────────┘
|
|
||||||
* The application shall ensure that if the sign of the number
|
|
||||||
* option-argument is '+', the number option-argument is a non-
|
|
||||||
* zero decimal integer.
|
|
||||||
*
|
|
||||||
* The origin for counting shall be 1; that is, -c +1 represents
|
|
||||||
* the first byte of the file, -c -1 the last.
|
|
||||||
*
|
|
||||||
* -f If the input file is a regular file or if the file operand
|
|
||||||
* specifies a FIFO, do not terminate after the last line of the
|
|
||||||
* input file has been copied, but read and copy further bytes
|
|
||||||
* from the input file when they become available. If no file
|
|
||||||
* operand is specified and standard input is a pipe or FIFO,
|
|
||||||
* the -f option shall be ignored. If the input file is not a
|
|
||||||
* FIFO, pipe, or regular file, it is unspecified whether or not
|
|
||||||
* the -f option shall be ignored.
|
|
||||||
*
|
|
||||||
* -n number This option shall be equivalent to -c number, except the
|
|
||||||
* starting location in the file shall be measured in lines
|
|
||||||
* instead of bytes. The origin for counting shall be 1; that
|
|
||||||
* is, -n +1 represents the first line of the file, -n -1 the
|
|
||||||
* last.
|
|
||||||
*
|
|
||||||
* If neither -c nor -n is specified, -n 10 shall be assumed.
|
|
||||||
*/
|
|
||||||
case 'c':
|
|
||||||
c = true;
|
|
||||||
fn = tailc;
|
|
||||||
num = strtol(optarg, NULL, 10);
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
f = true;
|
|
||||||
case 'n':
|
|
||||||
n = true;
|
|
||||||
num = strtol(optarg, NULL, 10);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(
|
|
||||||
stderr,
|
|
||||||
"Usage: %s (-f) [-c characters] [-n lines] file...\n",
|
|
||||||
argv[0]
|
|
||||||
);
|
|
||||||
return EX_USAGE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!n && !c) {
|
|
||||||
num = 10;
|
|
||||||
} else if (n && c) {
|
|
||||||
fprintf(
|
|
||||||
stderr,
|
|
||||||
"Usage: %s (-f) [-c characters] [-n lines] file...\n",
|
|
||||||
argv[0]
|
|
||||||
);
|
|
||||||
return EX_USAGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE *file;
|
|
||||||
|
|
||||||
if (optind == argc) {
|
|
||||||
fn(stdin, num);
|
|
||||||
|
|
||||||
if (f) { tailf(stdin); }
|
|
||||||
} else {
|
|
||||||
for (i = optind; i < argc; i++) {
|
|
||||||
if ((file = rpath(argv[0], argv[i])) != NULL) {
|
|
||||||
fn(file, num);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f) { tailf(file); }
|
|
||||||
fclose(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return EX_OK;
|
|
||||||
}
|
|
18
src/true.c
18
src/true.c
@ -1,21 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media>
|
* Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media>
|
||||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
* SPDX-License-Identifier: CC0
|
||||||
*
|
*
|
||||||
* This file is part of YAC coreutils.
|
* This work is marked with CC0 1.0. To view a copy of this license, visit
|
||||||
*
|
* <http://creativecommons.org/publicdomain/zero/1.0>.
|
||||||
* YAC coreutils 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.
|
|
||||||
*
|
|
||||||
* YAC coreutils 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/.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int main() {}
|
int main() {}
|
||||||
|
77
src/yac.c
77
src/yac.c
@ -1,77 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media>
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
||||||
*
|
|
||||||
* This file is part of YAC coreutils.
|
|
||||||
*
|
|
||||||
* YAC coreutils 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.
|
|
||||||
*
|
|
||||||
* YAC coreutils 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>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sysexits.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
/* Resolve a file from a path */
|
|
||||||
FILE *rpath(char *argv0, char *path) {
|
|
||||||
struct stat stats;
|
|
||||||
FILE *file;
|
|
||||||
|
|
||||||
if (path[0] == '-') {
|
|
||||||
switch (path[1]) {
|
|
||||||
case '\0':
|
|
||||||
file = stdin;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
file = NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (stat(path, &stats) == 0 && S_ISDIR(stats.st_mode)) {
|
|
||||||
fprintf(stderr, "%s: %s: Is a directory.\n", argv0, path);
|
|
||||||
exit(EX_NOINPUT);
|
|
||||||
} else if ((file = fopen(path, "r")) == NULL) {
|
|
||||||
switch (errno) {
|
|
||||||
case EACCES:
|
|
||||||
fprintf(stderr, "%s: %s: Permission denied.\n", argv0, path);
|
|
||||||
exit(EX_NOINPUT);
|
|
||||||
case EISDIR:
|
|
||||||
fprintf(stderr, "%s: %s: Is a directory.\n", argv0, path);
|
|
||||||
exit(EX_NOINPUT);
|
|
||||||
case ELOOP:
|
|
||||||
fprintf(
|
|
||||||
stderr,
|
|
||||||
"%s: %s: Is a symbolic link loop.\n",
|
|
||||||
argv0,
|
|
||||||
path
|
|
||||||
);
|
|
||||||
exit(EX_UNAVAILABLE);
|
|
||||||
case EMFILE:
|
|
||||||
fprintf(stderr, "%s: Internal error.\n", argv0);
|
|
||||||
exit(EX_SOFTWARE);
|
|
||||||
case ENOENT: case ENOTDIR: case ENXIO:
|
|
||||||
fprintf(
|
|
||||||
stderr,
|
|
||||||
"%s: %s: No such path or directory.\n",
|
|
||||||
argv0,
|
|
||||||
path
|
|
||||||
);
|
|
||||||
exit(EX_NOINPUT);
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "%s: Unknown error.\n", argv0);
|
|
||||||
exit(EX_UNAVAILABLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return file;
|
|
||||||
}
|
|
26
src/yac.h
26
src/yac.h
@ -1,26 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media>
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
||||||
*
|
|
||||||
* This file is part of YAC coreutils.
|
|
||||||
*
|
|
||||||
* YAC coreutils 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.
|
|
||||||
*
|
|
||||||
* YAC coreutils 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/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef YAC_H
|
|
||||||
#define YAC_H
|
|
||||||
|
|
||||||
FILE *rpath(char *argv0, char *path);
|
|
||||||
|
|
||||||
#endif
|
|
35
tests/cc-compat.sh
Executable file
35
tests/cc-compat.sh
Executable file
@ -0,0 +1,35 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Copyright (c) 2023 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 GNUmakefile >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
printf '%s: Run this script in the root of the project.\n' "$0" 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
make clean
|
||||||
|
|
||||||
|
for CC in cc\
|
||||||
|
clang \
|
||||||
|
gcc \
|
||||||
|
tcc \
|
||||||
|
'zig cc'
|
||||||
|
do
|
||||||
|
export CC
|
||||||
|
printf '%s: %s: Testing build.\n' "$0" "$CC"
|
||||||
|
|
||||||
|
make CC="$CC" && printf '%s: Build successful.\n' "$0"
|
||||||
|
|
||||||
|
ls -lA build/
|
||||||
|
|
||||||
|
make clean
|
||||||
|
printf '\n'
|
||||||
|
done
|
24
tests/posix-compat.sh
Executable file
24
tests/posix-compat.sh
Executable file
@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Copyright (c) 2023 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 GNUmakefile >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
printf '%s: Run this script in the root of the project.\n' "$0" 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "Starting POSIX compatibility testing.\n"
|
||||||
|
|
||||||
|
for utility in tests/posix/*; do
|
||||||
|
printf '%s: %s: Testing utility.\n' "$0" "$utility"
|
||||||
|
"$utility"
|
||||||
|
printf '\n'
|
||||||
|
done
|
19
tests/posix/test
Executable file
19
tests/posix/test
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Copyright (c) 2023 DTB <trinity@trinity.moe>
|
||||||
|
# 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
|
||||||
|
|
||||||
|
i=1
|
||||||
|
while test -e "$i".test; do
|
||||||
|
printf '%s: %s: Running test...\n' "$0" "$i".test
|
||||||
|
./"$i".test >"$i".result
|
||||||
|
diff 1.expected 1.result
|
||||||
|
printf '%s: %s: Test passed.\n' "$0" "$i".test
|
||||||
|
i="$(printf '%s + %s\n' 1 "$i" | bc)"
|
||||||
|
done
|
Loading…
Reference in New Issue
Block a user