Hello,
My name is Gavin Howard. I have developed a new bc(1) and dc(1)
implementation. [0]
I propose replacing the current implementations with mine.
Advantages:
* Performance. [1]
* Extensions for ease of use.
* With build options to remove most extensions, if desired.
* Compatible with GNU bc.
* Already used by default in FreeBSD.
* Fuzzed thoroughly.
* No exec needed for bc(1) (both programs are contained in the same
multi-call binary).
Expectations met:
* Already uses pledge(2) and unveil(2).
* No dependencies beyond C99, POSIX `make`, and POSIX `sh`.
* This includes no dependency on editline(3), even though my bc(1)
and dc(1) have a history implementation.
* Thorough test suite.
* Comprehensive man pages.
* Locale support.
Disadvantages:
* There are incompatibilities with the current bc(1) and dc(1), which
are listed below. All users would need to be made aware of these
incompatibilities, so they can update scripts, and scripts in `src/`
will also need to be updated.
Incompatibilities (failing tests from `regress/usr.bin`):
1. Current bc(1) and dc(1) return 0 for length(a) where a is 0. Mine
return 1. This causes my dc(1) to fail `dc/t1.in` and `dc/t28.in`.
2. Current dc(1) implements arrays as part of registers. Mine keeps
arrays and registers separate. This causes my dc(1) to fail
`dc/t1.in` and `dc/t8.in`.
3. Current dc(1) does not print a `nul` byte if given the `P` or `a`
commands with 0 on the top of the stack. My dc(1) does (because it
considers 0 to have one digit, see #1). This causes my dc(1) to fail
`dc/t3.in` and `dc/t13.in`.
4. Current dc(1) starts with empty registers, and allows the user to pop
all items off the register stack. My dc(1) starts with a single item
in the register and does not allow the user to remove it.
5. Current dc(1) will push an item onto a register stack for the `s`
command. My dc(1) does not since one already exists. This, combined
with #4, causes my dc(1) to fail `dc/t5.in`
6. Current bc(1) and dc(1) have a larger maximum `obase` than mine. This
causes my dc(1) to fail `dc/t9.in`.
7. Current dc(1) does not reset on errors. My dc(1) does, so it fails
`dc/t12.in`.
8. Current dc(1) allows register names with any character. My dc(1)
requires non-control characters and has a different way of doing
extended registers. This causes my dc(1) to fail `dc/t15.in`,
`dc/t16.in`, `dc/t19.in`, `dc/t21.in`, and `dc/t23.in`.
9. Current bc(1) is a frontend to dc(1). Mine are combined into the same
binary and generate and run bytecode. This means that my bc(1) fails
all of the bc(1) regression tests (which generate dc(1) code) and
does not have the `-c` option.
Notes:
My dc(1) also fails `dc/t10.in` because it doesn't have the `!` command,
but https://github.com/openbsd/src/commit/dc405aa075 makes it appear as
though the current dc(1) does not have the `!` command either.
In https://youtu.be/gvmGfpMgny4?t=1277 , Bob Beck said that unveil(2)
must not be used on command-line arguments, so I use unveil(2) after all
command-line files are executed.
Current version is 4.0.2. I am planning to release version 4.1.0 soon,
but held off in case you are interested and had feedback that might
help.
I am willing to help maintain them if they are put into OpenBSD, but I
am also willing to pass them off to whoever you wish, should you wish to
do so.
I do have a mirror on GitHub.
If you are not interested, feel free to ignore this email.
Regardless, thank you for your time.
Gavin Howard
[0]: https://git.yzena.com/gavin/bc
[1]: https://git.yzena.com/gavin/bc/src/branch/master/manuals/benchmarks.md