14 Commits

4 changed files with 262 additions and 91 deletions

View File

@@ -1,26 +1,29 @@
Make sure to read our code of conduct in the CONDUCT file. Make sure to read our code of conduct in the CONDUCT file.
When contributing a pull request to the main branch, please sign your commits
with a PGP key and add your name and the year to the bottom of the list of Copyright Information
copyright holders for the file. For example, an existing copyright header might =====================
read:
When editing a file, create a copyright statement correlated to your
identity so that it is easier to keep track of who has touched what file.
Pseudonymous contributions are welcome (and encouraged). Place new copyright
information below existing copyright information. If there is an existing
copyright statement:
* Copyright (c) 20222023 Emma Tebibyte <emma@tebibyte.media> * Copyright (c) 20222023 Emma Tebibyte <emma@tebibyte.media>
You would add your name below it like this: you would add your name below it like this:
* Copyright (c) 20222023 Emma Tebibyte <emma@tebibyte.media> * Copyright (c) 20222023 Emma Tebibyte <emma@tebibyte.media>
* Copyright (c) 20XX Your Name <your e-mail address or website> * Copyright (c) 20XX Your Name <your e-mail address or website>
We accept contributions from people using aliases.
Only list years in which you modified the source file. For example: Only list years in which you modified the source file. For example:
* Copyright (c) 20202021, 2023 Your Name <your-address@example.com> * Copyright (c) 20202021, 2023 Your Name <your-address@example.com>
This header shows that “Your Name” worked on this source file in 2020, 2021, and This header shows that “Your Name” worked on this source file in 2020, 2021, and
2023. Please use the en dash (“–”) to separate the years in the copyright 2023. Please use the en dash (“–”, U+2013) to separate consecutive years in the
notice. copyright notice.
If you are contributing a new file, please prepend the following license header If you are contributing a new file, please prepend the following license header
text to it, replacing the proper text on the copyright line: text to it, replacing the proper text on the copyright line:
@@ -92,6 +95,10 @@ notice:
* USE OR OTHER DEALINGS IN THE SOFTWARE. * USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
Style
=====
Make sure lines never exceed 80 columns in width when using four-character Make sure lines never exceed 80 columns in width when using four-character
indentation steps. This helps contributors with smaller screens, those using 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 side-by-side editor windows or panes, and those who have no text wrapping in
@@ -104,8 +111,13 @@ style guide for the usage texts output format [0].
If committing a new utility, please include tests and documentation (see If committing a new utility, please include tests and documentation (see
tests/ and docs/) for the new tool. tests/ and docs/) for the new tool.
If committing a new source file, format the commit message following these Committing
guidelines: ==========
When contributing to Bonsai, please sign your commit with a PGP key and create
the commit with an identity which can be easily contacted.
Format commit messages following these guidelines:
$ git commit -m 'tool(1): add feature x' $ git commit -m 'tool(1): add feature x'
@@ -131,7 +143,13 @@ $ git commit -m 'tool(1): fix #42 & add feature x'
Commit messages should be written in the present tense. Commit messages should be written in the present tense.
References
==========
[0] <http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/share/misc/style> [0] <http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/share/misc/style>
-- --
This work © 20232024 by Emma Tebibyte is licensed under CC BY-SA 4.0. To view a 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/> copy of this license, visit <http://creativecommons.org/licenses/by-sa/4.0/>

View File

@@ -22,9 +22,9 @@ OS_INCLUDE != test -e include/$(OS).mk && printf 'include/$(OS).mk\n' \
|| printf '/dev/null\n' || printf '/dev/null\n'
# normalized prefix # normalized prefix
PREFIX_N != dirname $(PREFIX)/. PREFIX_N != realpath $(PREFIX)
MANDIR != test $(PREFIX_N) = / && printf '/usr/share/man\n' \ MANDIR != test $(PREFIX_N) = / && printf '/usr/share/man\n' \
|| printf '/share/man\n' || printf '$(PREFIX_N)/man\n'
SYSEXITS != printf '\043include <sysexits.h>\n' | cpp -M - | tr ' ' '\n' \ SYSEXITS != printf '\043include <sysexits.h>\n' | cpp -M - | tr ' ' '\n' \
| sed -n 's/sysexits\.h//p' || printf 'include\n' | sed -n 's/sysexits\.h//p' || printf 'include\n'
@@ -54,9 +54,9 @@ clean:
rm -rf build dist rm -rf build dist
dist: all docs dist: all docs
mkdir -p $(DESTDIR)/$(PREFIX)/bin $(DESTDIR)/$(PREFIX)/$(MANDIR)/man1 mkdir -p $(DESTDIR)/$(PREFIX_N)/bin $(DESTDIR)/$(MANDIR)/man1
cp build/bin/* $(DESTDIR)/$(PREFIX)/bin cp build/bin/* $(DESTDIR)/$(PREFIX_N)/bin
cp build/docs/*.1 $(DESTDIR)/$(PREFIX)/$(MANDIR)/man1 cp build/docs/*.1 $(DESTDIR)/$(MANDIR)/man1
.PHONY: install .PHONY: install
install: dist install: dist

49
README
View File

@@ -1,24 +1,28 @@
“Seek not to walk the path of the masters; seek what they sought.” “Seek not to walk the path of the masters; seek what they sought.”
Matsuo Basho Matsuo Basho
The Bonsai harakit utilities are a replacement for standard POSIX utilities Bonsais Harakit is an alternative to the standard POSIX utilities that aims to
which aim to fill its niche while expanding on their capabilities. These new be simpler, easier, and more powerful. These tools are the result of careful
tools are the result of the careful examination of the current state of POSIX examination of the current state common Unix utilities, POSIX-compliant and
and Unix utilies. The Unix Philosophy of “do one thing and do it well” are their otherwise, following frustrations with design decisions and implementation
core but they avoid clinging to the past. details. They represent a vision of accomplishing everyday use cases with tools
that follow the Unix philosophy of “do one thing and do it well” without
clinging to the past.
The era of the original Unix tools has been long and fruitful, but they have The intent of Harakit is not to conform to or extend POSIX, like the GNU or BSD
their flaws. This project originated from frustrations with the way certain utilities do, but to invent new utilities to perform the same tasks in more
tools work and how other projects that extend POSIX dont make anything better. intuitive ways. GNU and BSD extensions are convenient but often unhealthy,
forgetting the purposes of the tools they extend, or building into existing
This project will not follow in the footsteps of GNU; extensions of POSIX will utilities features that would be more useful as their own tools to be used
not be found here. GNU extensions are a gateway to the misuse of the shell. The anywhere. Other utility sets aim to provide a number of fully-featured
harakit utilities will intentionally discourage use of the shell for purposes programs to be used individually, Harakit utilities are meant to be easily
beyond its scope. composable and work together in pipelines.
See docs/ for more on the specific utilities currently implemented. See docs/ for more on the specific utilities currently implemented.
Building Building
========
Harakit utilities require a POSIX-compliant environment to compile, including a Harakit utilities require a POSIX-compliant environment to compile, including a
C compiler and preprocessor (cc(1) and cpp(1) by default), an edition 2023 Rust C compiler and preprocessor (cc(1) and cpp(1) by default), an edition 2023 Rust
@@ -43,7 +47,22 @@ To remove all build and distributable files:
$ make clean $ make clean
Contributing
============
See the CONTRIBUTING file for contribution guidelines.
Community
=========
xmpp://bonsai@covenant.murderu.us
irc://feeling.murderu.us/#bonsai
Read More Read More
=========
An Introduction to the Unix Shell An Introduction to the Unix Shell
<https://porkmail.org/era/unix/shell> <https://porkmail.org/era/unix/shell>
@@ -57,6 +76,10 @@ Master Foo Discourses on the Unix-Nature
Shell Programming! Shell Programming!
<https://tldp.org/LDP/abs/html/why-shell.html> <https://tldp.org/LDP/abs/html/why-shell.html>
UNIX Style, or cat -v Considered Harmful
<http://harmful.cat-v.org/cat-v/>
-- --
Copyright © 20232024 Emma Tebibyte <emma@tebibyte.media> Copyright © 20232024 Emma Tebibyte <emma@tebibyte.media>
Copyright © 2024 DTB <trinity@trinity.moe> Copyright © 2024 DTB <trinity@trinity.moe>

254
STYLE
View File

@@ -1,11 +1,51 @@
“Everyone knows that debugging is twice as hard as writing a program in the
first place. So if youre as clever as you can be when you write it, how
will you ever debug it?”
Brian Kernighan, The Elements of Programming Style
The following guidelines are conducive to clear and readable code that is The following guidelines are conducive to clear and readable code that is
consistent with the style of the rest of the Bonsai Computer System. consistent with the style of the rest of the Bonsai Computer System.
0. Braces are mandatory for all control flow.
1. Nested indentation should be kept to a minimum. Use
===
2. Empty lines should be placed between different kinds of statements: 0. A single line for control flow statements short enough to be easily
understood at a glance:
if !(argc < 0) { usage(program_name); }
This applies to C switch statements and cases and Rust match statements, as
well:
switch (value) { /* aligning stuff to make it easier to read is fine */
case possibility: variable = foo; break;
default: variable = NULL; break;
}
1. Switch cases in C and match arms in Rust should start another level of
indentation:
switch (value) {
case possibility:
statement;
break;
default:
statement;
break;
}
match result {
Ok(n) => variable = n,
Err(e) => error = e,
}
2. Braces in control flow where their inclusion is left optional in C:
if (condition) { statement; }
3. Empty lines between different kinds of statements:
int t; int t;
@@ -25,56 +65,57 @@ consistent with the style of the rest of the Bonsai Computer System.
return io; return io;
3. Each block of code should be indented once more than the keyword which 4. Compiler options that yield the most useful warnings, such as -Wpedantic in
initiated the block: a lot of C compilers. Fix the warnings, too [0].
switch (c) { 5. One more level of indentation and one argument per line when a function
case 'e': mode |= EQUAL; break; call or statement header is too long to fit on one line:
case 'g': mode |= GREATER; break;
case 'l': mode |= LESS; break;
default: return usage(s);
}
4. In C, spaces should be placed in control flow statements after the keyword
and before the opening brace:
for (i = 2; i < argc; ++i) {
5. If a function, a C control flow statement, or a Rust macro has arguments that
cause the statement to be broken into multiple lines, this should be done by
placing the arguments on a new line inside the parentheses:
let usage = format!( let usage = format!(
"Usage: {} [-d delimiter] index command [args...]", "Usage: {} [-d delimiter] index command [args...]",
argv[0], argv[0],
); );
6. If Rust function arguments or fields are on their own lines, they should 6. One more level of indentation than the keyword that initiated a multi-line
always have a trailing comma: block.
if (condition) {
statement;
statement;
}
7. The return value of all non-void functions, or explicitly ignore them (like
casting to void in C) [0]:
if ((a = malloc(sizeof char)) == NULL) { /* handle this error */
(void)fprintf(stderr, "oh noes!"); /* explicitly ignore this one */
return EX_OSERR; /* ...because the program is exiting anyway */
}
8. The smallest possible scope for data [0].
9. Comments noting all the symbols and macros used from a C header file, next
to its include macro:
#include <unistd.h> /* close(2), getopt(3), lseek(2), read(2), write(2),
(space-aligned) * optarg, optind, STDIN_FILENO, STDOUT_FILENO */
10. Spaces in control flow statements, after the keyword and before the
opening brace:
for (i = 2; i < argc; ++i) {
11. In Rust, a trailing comma on all arguments or fields that are on their own
lines:
return Err(EvaluationError { return Err(EvaluationError {
message: format!("{}: Invalid token", i), message: format!("{}: Invalid token", i),
code: EX_DATAERR, code: EX_DATAERR,
}) })
7. If text is on the same line as a brace, spaces should be placed after an 12. In Rust, place extern statements after use statements that include standard
opening curly brace and before a closing one: library crates. Group like statements:
use sysexits::{ EX_DATAERR, EX_IOERR, EX_UNAVAILABLE, EX_USAGE };
8. If a control flow statement is short enough to be easily understood in a
glance, it may be placed on a single line:
if !(argc < 0) { usage(program_name); }
9. In C, note everything you use from a library in a comment subsequent to its
#include statement:
#include <unistd.h> /* close(2), getopt(3), lseek(2), read(2), write(2),
* optarg, optind, STDIN_FILENO, STDOUT_FILENO */
10. In Rust, place extern statements after use statements that include standard
library crates. Group alike statements:
use std::fs::Path; use std::fs::Path;
@@ -84,40 +125,129 @@ library crates. Group alike statements:
use strerror::StrError; use strerror::StrError;
use sysexits::{ EX_OSERR, EX_USAGE }; use sysexits::{ EX_OSERR, EX_USAGE };
11. Do not use do while loops in C. 13. If text is on the same line as a brace, spaces after an opening brace and
before a closing one:
12. Adhere to the following rules from the paper The Power of 10: Rules for use sysexits::{ EX_DATAERR, EX_IOERR, EX_UNAVAILABLE, EX_USAGE };
Developing Safety-Critical Code [0]:
1. Avoid complex flow constructs, such as goto and recursion.
2. All loops must have fixed bounds. This prevents runaway code.
3. Avoid heap memory allocation.
4. Restrict functions to the length of a single printed page.
6. Restrict the scope of data to the smallest possible. 14. Alphabetic sorting, where applicable:
7. Check the return value of all non-void functions, or cast to void to
indicate the return value is useless (such as in the case of using
fprintf(3p) to print to the standard error).
8. Use the preprocessor sparingly.
9. Limit pointer use to a single dereference, and do not use function
pointers.
10. Compile with all possible warnings active; all warnings should then be
addressed before release of the software (for C compilers, compile with
-Wpedantic).
13. Remember this quote from The Elements of Programming Style by Brian use std::io::{ BufWriter, Read, Write, stderr, stdin, stdout }
Kernighan:
Everyone knows that debugging is twice as hard as writing a program in the 15. In Rust, use the to_owned() method on string types (str, OsStr, CStr, etc.)
first place. So if you're as clever as you can be when you write it, how and the to_string() method on other types.
will you ever debug it?
Avoid
=====
16. Unbounded loops [0].
17. Function pointers [0].
18. Heap memory allocation [0].
19. Using too much nested logic (within reason).
20. Too many levels of dereferences [0]:
/* do not do this */
for (size_t i = 0; i < sizeof a / sizeof *a; ++i) {
if (a[i].id == MATCH) { a[i].val = 0; }
}
/* do this */
for (struct MadeUp *s = &a[0]; *s != NULL; s = &s[1]) {
if (s->id == MATCH) { s->val = 0; }
}
21. Using C preprocessor macros; the fewer, the better [0].
22. The exit(3p) and std::process::exit() functions; returning from the main
function skips a system call.
Do Not Use
==========
23. More than the length of one printed page for a function [0].
24. Recursion, as its complex and can unexpectedly overflow the stack [0].
25. Any functionality not in the POSIX C specification and language features not
in C99.
26. Do-while loops, as theyre unique to C and confusing for casual programmers.
27. Labels and goto statements; use sensible flow control [0].
28. Pointer arithmetic, as it tends to be confusing and unnecessary; use
index-reference patterns like &p[1] instead of p + 1. &p[n] is the address at
p + sizeof p * n, not p + n, like pointer arithmetic suggests.
29. C struct bitfields in unions, to access certain bits of bigger data types,
as its poorly defined in the C standards; use bit arithmetic.
30. C trigraphs.
31. Inclusions in C header files, to prevent multiple file inclusions.
32. C preprocessor variables to prevent multiple inclusions of the same file,
such as:
#ifdef _FILE
#define _FILE
/* file body */
#endif /* ifdef _FILE */
Instead, take the time to ensure other files arent including any files twice.
33. The gets(3p) function from <stdio.h>, as its impossible to prevent buffer
overflows when it's used; use fgets(3p) from <stdio.h>.
34. The scanf(3p) function from <stdio.h> [1].
35. Any functionality not described in the latest POSIX make(1) specification.
36. Macros which panic on failure in Rust (such as the print!() and println!()
macros). Use a function and handle any errors. However, do use the eprintln!()
macro for error messages. Handling an error for writing an error message is
redundant.
Usage Text
==========
This section is adapted from the NetBSD style guide [2].
When programs are invoked incorrectly and in the synopsis of manual pages, uasge
text should be provided to the user. The following is the format used by this
project for this purpose:
All optional arguments are to be placed in square brackets (U+005B, U+005D).
Mutually exclusive arguments can be separated by a vertical line (U+007C).
Groups of arguments should be specified in alphabetical order in most cases. The
order of arguments and an example of these rules follows:
0. Options with no option arguments.
1. Options with option arguments. Arguments should be specified inside the same
square brackets as the options.
3. Non-option arguments.
"usage: f [-aDde] [-b b_arg] [-m m_arg] req1 req2 [opt1 [opt2]]\n"
"usage: f [-a | -b] [-c [-de] [-n number]]\n"
References References
========== ==========
[0] <https://web.eecs.umich.edu/~imarkov/10rules.pdf> [0] <https://web.eecs.umich.edu/~imarkov/10rules.pdf>
[1] <http://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html>
[2] <http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/share/misc/style>
-- --
Copyright © 2024 Emma Tebibyte <emma@tebibyte.media> Copyright © 2024 Emma Tebibyte <emma@tebibyte.media>
Copyright © 2024 DTB <trinity@trinity.moe>
Copyright © Wikipedia contributors Copyright © Wikipedia contributors
This work is licensed under CC BY-SA 4.0. To view a copy of this license, visit This work is licensed under CC BY-SA 4.0. To view a copy of this license, visit