diff options
Diffstat (limited to 'contrib/bc/scripts')
28 files changed, 2154 insertions, 3170 deletions
diff --git a/contrib/bc/scripts/afl.py b/contrib/bc/scripts/afl.py deleted file mode 100755 index c4312ce84f83..000000000000 --- a/contrib/bc/scripts/afl.py +++ /dev/null @@ -1,245 +0,0 @@ -#! /usr/bin/python3 -B -# -# SPDX-License-Identifier: BSD-2-Clause -# -# Copyright (c) 2018-2021 Gavin D. Howard and contributors. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# - -import os -import sys -import shutil -import subprocess - - -# Print the usage and exit with an error. -def usage(): - print("usage: {} [--asan] dir [results_dir [exe options...]]".format(script)) - print(" The valid values for dir are: 'bc1', 'bc2', 'bc3', and 'dc'.") - sys.exit(1) - - -# Check for a crash. -# @param exebase The calculator that crashed. -# @param out The file to copy the crash file to. -# @param error The error code (negative). -# @param file The crash file. -# @param type The type of run that caused the crash. This is just a string -# that would make sense to the user. -# @param test The contents of the crash file, or which line caused the crash -# for a run through stdin. -def check_crash(exebase, out, error, file, type, test): - if error < 0: - print("\n{} crashed ({}) on {}:\n".format(exebase, -error, type)) - print(" {}".format(test)) - print("\nCopying to \"{}\"".format(out)) - shutil.copy2(file, out) - print("\nexiting...") - sys.exit(error) - - -# Runs a test. This function is used to ensure that if a test times out, it is -# discarded. Otherwise, some tests result in incredibly long runtimes. We need -# to ignore those. -# -# @param cmd The command to run. -# @param exebase The calculator to test. -# @param tout The timeout to use. -# @param indata The data to push through stdin for the test. -# @param out The file to copy the test file to if it causes a crash. -# @param file The test file. -# @param type The type of test. This is just a string that would make sense -# to the user. -# @param test The test. It could be an entire file, or just one line. -# @param environ The environment to run the command under. -def run_test(cmd, exebase, tout, indata, out, file, type, test, environ=None): - try: - p = subprocess.run(cmd, timeout=tout, input=indata, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, env=environ) - check_crash(exebase, out, p.returncode, file, type, test) - except subprocess.TimeoutExpired: - print("\n {} timed out. Continuing...\n".format(exebase)) - - -# Creates and runs a test. This basically just takes a file, runs it through the -# appropriate calculator as a whole file, then runs it through the calculator -# using stdin. -# @param file The file to test. -# @param tout The timeout to use. -# @param environ The environment to run under. -def create_test(file, tout, environ=None): - - print(" {}".format(file)) - - base = os.path.basename(file) - - if base == "README.txt": - return - - with open(file, "rb") as f: - lines = f.readlines() - - print(" Running whole file...") - - run_test(exe + [ file ], exebase, tout, halt.encode(), out, file, "file", file, environ) - - print(" Running file through stdin...") - - with open(file, "rb") as f: - content = f.read() - - run_test(exe, exebase, tout, content, out, file, - "running {} through stdin".format(file), file, environ) - - -# Get the children of a directory. -# @param dir The directory to get the children of. -# @param get_files True if files should be gotten, false if directories should -# be gotten. -def get_children(dir, get_files): - dirs = [] - with os.scandir(dir) as it: - for entry in it: - if not entry.name.startswith('.') and \ - ((entry.is_dir() and not get_files) or \ - (entry.is_file() and get_files)): - dirs.append(entry.name) - dirs.sort() - return dirs - - -# Returns the correct executable name for the directory under test. -# @param d The directory under test. -def exe_name(d): - return "bc" if d == "bc1" or d == "bc2" or d == "bc3" else "dc" - - -# Housekeeping. -script = sys.argv[0] -scriptdir = os.path.dirname(script) - -# Must run this script alone. -if __name__ != "__main__": - usage() - -timeout = 2.5 - -if len(sys.argv) < 2: - usage() - -idx = 1 - -exedir = sys.argv[idx] - -asan = (exedir == "--asan") - -# We could possibly run under ASan. See later for what that means. -if asan: - idx += 1 - if len(sys.argv) < idx + 1: - usage() - exedir = sys.argv[idx] - -print("exedir: {}".format(exedir)) - -# Grab the correct directory of AFL++ results. -if len(sys.argv) >= idx + 2: - resultsdir = sys.argv[idx + 1] -else: - if exedir == "bc1": - resultsdir = scriptdir + "/../tests/fuzzing/bc_outputs1" - elif exedir == "bc2": - resultsdir = scriptdir + "/../tests/fuzzing/bc_outputs2" - elif exedir == "bc3": - resultsdir = scriptdir + "/../tests/fuzzing/bc_outputs3" - elif exedir == "dc": - resultsdir = scriptdir + "/../tests/fuzzing/dc_outputs" - else: - raise ValueError("exedir must be either bc1, bc2, bc3, or dc"); - -print("resultsdir: {}".format(resultsdir)) - -# More command-line processing. -if len(sys.argv) >= idx + 3: - exe = sys.argv[idx + 2] -else: - exe = scriptdir + "/../bin/" + exe_name(exedir) - -exebase = os.path.basename(exe) - - -# Use the correct options. -if exebase == "bc": - halt = "halt\n" - options = "-lq" - seed = ["-e", "seed = 1280937142.20981723890730892738902938071028973408912703984712093", "-f-" ] -else: - halt = "q\n" - options = "-x" - seed = ["-e", "1280937142.20981723890730892738902938071028973408912703984712093j", "-f-" ] - -# More command-line processing. -if len(sys.argv) >= idx + 4: - exe = [ exe, sys.argv[idx + 3:], options ] + seed -else: - exe = [ exe, options ] + seed -for i in range(4, len(sys.argv)): - exe.append(sys.argv[i]) - -out = scriptdir + "/../.test.txt" - -print(os.path.realpath(os.getcwd())) - -dirs = get_children(resultsdir, False) - -# Set the correct ASAN_OPTIONS. -if asan: - env = os.environ.copy() - env['ASAN_OPTIONS'] = 'abort_on_error=1:allocator_may_return_null=1' - -for d in dirs: - - d = resultsdir + "/" + d - - print(d) - - # Check the crash files. - files = get_children(d + "/crashes/", True) - - for file in files: - file = d + "/crashes/" + file - create_test(file, timeout) - - # If we are running under ASan, we want to check all files. Otherwise, skip. - if not asan: - continue - - # Check all of the test cases found by AFL++. - files = get_children(d + "/queue/", True) - - for file in files: - file = d + "/queue/" + file - create_test(file, timeout * 2, env) - -print("Done") diff --git a/contrib/bc/scripts/alloc.sh b/contrib/bc/scripts/alloc.sh deleted file mode 100755 index c5c46febe0b3..000000000000 --- a/contrib/bc/scripts/alloc.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/bin/sh -# -# SPDX-License-Identifier: BSD-2-Clause -# -# Copyright (c) 2018-2021 Gavin D. Howard and contributors. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# - -# This script is only really useful for running on Linux. It tests the code to -# free temps in order to make an allocation work. In order to see it work, I -# suggest adding code after the following line in src/vm.c: -# -# if (BC_ERR(ptr == NULL)) bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR); -# -# The code you should add is the following: -# -# bc_file_printf(&vm.ferr, "If you see this, the code worked.\n"); -# bc_file_flush(&vm.ferr, bc_flush_none); -# -# If you do not see the that message printed, the code did not work. Or, in the -# case of some allocators, like jemalloc, the allocator just isn't great with -# turning a bunch of small allocations into a bigger allocation, - -script="$0" -scriptdir=$(dirname "$script") - -export LANG=C - -virtlimit=1000000 - -ulimit -v $virtlimit - -# This script is designed to allocate lots of memory with a lot of caching of -# numbers (the function f() specifically). Then, it's designed allocate one -# large number and grow it until allocation failure (the function g()). -"$scriptdir/../bin/bc" <<*EOF - -define f(i, n) { - if (n == 0) return i; - return f(i + 1, n - 1) -} - -define g(n) { - t = (10^9)^(2^24) - while (n) { - n *= t - print "success\n" - } -} - -iterations=2000000 - -for (l=0; l < 100; l++) { - iterations - j = f(0, iterations$) - iterations += 100000 - print "here\n" - n=10^235929600 - g(n) - print "success\n" - n=0 -} -*EOF diff --git a/contrib/bc/scripts/benchmark.sh b/contrib/bc/scripts/benchmark.sh deleted file mode 100755 index 35f92452ce78..000000000000 --- a/contrib/bc/scripts/benchmark.sh +++ /dev/null @@ -1,159 +0,0 @@ -#! /bin/sh -# -# SPDX-License-Identifier: BSD-2-Clause -# -# Copyright (c) 2018-2021 Gavin D. Howard and contributors. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# - -# This script depends on the GNU time utility, but I am okay with that because -# this script is only for maintainers. - -# Just print the usage and exit with an error. -usage() { - printf 'usage: %s [-n<runs>] [-p<pause>] dir benchmark...\n' "$0" 1>&2 - printf ' -n runs is how many runs to run the benchmark, default 10.\n' - printf ' -p pause is how many seconds to pause before running the benchmarks.\n' - printf '\n' - printf 'The fields are put in this order:\n' - printf '1. Elapsed Time\n' - printf '2. System Time\n' - printf '3. User Time\n' - printf '4. Max RSS\n' - printf '5. Average RSS\n' - printf '6. Average Total Memory Use\n' - printf '7. Average Unshared Data\n' - printf '8. Average Unshared Stack\n' - printf '9. Average Shared Text\n' - printf '10. Major Page Faults\n' - printf '11. Minor Page Faults\n' - printf '12. Swaps\n' - printf '13. Involuntary Context Switches\n' - printf '14. Voluntary Context Switches\n' - printf '15. Inputs\n' - printf '16. Outputs\n' - printf '17. Signals Delivered\n' - exit 1 -} - -script="$0" -scriptdir=$(dirname "$script") - -runs=10 -pause=0 - -# Process command-line arguments. -while getopts "n:p:" opt; do - - case "$opt" in - n) runs="$OPTARG" ;; - p) pause="$OPTARG" ;; - ?) usage "Invalid option: $opt" ;; - esac - -done - -while [ "$#" -gt 0 ] && [ "$OPTIND" -gt 1 ]; do - - OPTIND=$(bin/bc -e "$OPTIND - 1") - shift - -done - -if [ "$#" -lt 2 ]; then - usage -fi - -cd "$scriptdir/.." - -d="$1" -shift - -benchmarks="" - -# Create the list of benchmarks from the arguments. -while [ "$#" -gt 0 ]; do - - if [ "$benchmarks" = "" ]; then - benchmarks="$1" - else - benchmarks="$benchmarks $1" - fi - - shift -done - -files="" - -# Create the list of files from the benchmarks. -for b in $benchmarks; do - - f=$(printf "benchmarks/%s/%s.txt" "$d" "$b") - - if [ "$files" = "" ]; then - files="$f" - else - files="$files $f" - fi - -done - -if [ "$d" = "bc" ]; then - opts="-lq" - halt="halt" -else - opts="-x" - halt="q" -fi - -# Generate all of the benchmarks. -for b in $benchmarks; do - - if [ ! -f "./benchmarks/$d/$b.txt" ]; then - printf 'Benchmarking generation of benchmarks/%s/%s.txt...\n' "$d" "$b" >&2 - printf '%s\n' "$halt" | /usr/bin/time -v bin/$d $opts "./benchmarks/$d/$b.$d" \ - > "./benchmarks/$d/$b.txt" - fi -done - -# We use this format to make things easier to use with ministat. -format="%e %S %U %M %t %K %D %p %X %F %R %W %c %w %I %O %k" - -printf 'Benchmarking %s...\n' "$files" >&2 - -if [ "$pause" -gt 0 ]; then - sleep "$pause" -fi - -i=0 - -# Run the benchmarks as many times as told to. -while [ "$i" -lt "$runs" ]; do - - printf '%s\n' "$halt" | /usr/bin/time -f "$format" bin/$d $opts $files 2>&1 > /dev/null - - # Might as well use the existing bc. - i=$(printf '%s + 1\n' "$i" | bin/bc) - -done diff --git a/contrib/bc/scripts/bitgen.c b/contrib/bc/scripts/bitgen.c deleted file mode 100644 index 5dd1e6622b00..000000000000 --- a/contrib/bc/scripts/bitgen.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * ***************************************************************************** - * - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2018-2021 Gavin D. Howard and contributors. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * ***************************************************************************** - * - * A generator for bitwise operations test. - * - */ - -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> - -#define NTESTS (100) - -/** - * Abort with an error message. - * @param msg The error message. - */ -void err(const char *msg) { - fprintf(stderr, "%s\n", msg); - abort(); -} - -int main(void) { - - uint64_t a = 0, b = 0; - size_t i; - - // We attempt to open this or /dev/random to get random data. - int fd = open("/dev/urandom", O_RDONLY); - - if (fd < 0) { - - fd = open("/dev/random", O_RDONLY); - - if (fd < 0) err("cannot open a random number generator"); - } - - // Generate NTESTS tests. - for (i = 0; i < NTESTS; ++i) { - - ssize_t nread; - - // Generate random data for the first operand. - nread = read(fd, (char*) &a, sizeof(uint64_t)); - if (nread != sizeof(uint64_t)) err("I/O error"); - - // Generate random data for the second operand. - nread = read(fd, (char*) &b, sizeof(uint64_t)); - if (nread != sizeof(uint64_t)) err("I/O error"); - - // Output the tests to stdout. - printf("band(%lu, %lu)\n", a, b); - printf("bor(%lu, %lu)\n", a, b); - printf("bxor(%lu, %lu)\n", a, b); - printf("blshift(%llu, %lu)\n", a & ((1ULL << 32) - 1), b & 31); - printf("brshift(%llu, %lu)\n", a & ((1ULL << 32) - 1), b & 31); - printf("blshift(%llu, %lu)\n", b & ((1ULL << 32) - 1), a & 31); - printf("brshift(%llu, %lu)\n", b & ((1ULL << 32) - 1), a & 31); - - // Output the results to stderr. - fprintf(stderr, "%lu\n", a & b); - fprintf(stderr, "%lu\n", a | b); - fprintf(stderr, "%lu\n", a ^ b); - fprintf(stderr, "%llu\n", (a & ((1ULL << 32) - 1)) << (b & 31)); - fprintf(stderr, "%llu\n", (a & ((1ULL << 32) - 1)) >> (b & 31)); - fprintf(stderr, "%llu\n", (b & ((1ULL << 32) - 1)) << (a & 31)); - fprintf(stderr, "%llu\n", (b & ((1ULL << 32) - 1)) >> (a & 31)); - } - - return 0; -} diff --git a/contrib/bc/scripts/exec-install.sh b/contrib/bc/scripts/exec-install.sh index 25d56c6fc688..835b7491ac66 100755 --- a/contrib/bc/scripts/exec-install.sh +++ b/contrib/bc/scripts/exec-install.sh @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: BSD-2-Clause # -# Copyright (c) 2018-2021 Gavin D. Howard and contributors. +# Copyright (c) 2018-2025 Gavin D. Howard and contributors. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: @@ -29,7 +29,7 @@ # Print usage and exit with an error. usage() { - printf "usage: %s install_dir exec_suffix\n" "$0" 1>&2 + printf "usage: %s install_dir exec_suffix [bindir]\n" "$0" 1>&2 exit 1 } @@ -49,12 +49,23 @@ shift exec_suffix="$1" shift -bindir="$scriptdir/../bin" +if [ "$#" -gt 0 ]; then + bindir="$1" + shift +else + bindir="$scriptdir/../bin" +fi # Install or symlink, depending on the type of file. If it's a file, install it. # If it's a symlink, create an equivalent in the install directory. for exe in $bindir/*; do + # Skip any directories in case the bin/ directory is also used as the + # prefix. + if [ -d "$exe" ]; then + continue + fi + base=$(basename "$exe") if [ -L "$exe" ]; then diff --git a/contrib/bc/scripts/fuzz_prep.sh b/contrib/bc/scripts/format.sh index 0441f94e340c..e8836c6ba1e0 100755 --- a/contrib/bc/scripts/fuzz_prep.sh +++ b/contrib/bc/scripts/format.sh @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: BSD-2-Clause # -# Copyright (c) 2018-2021 Gavin D. Howard and contributors. +# Copyright (c) 2018-2025 Gavin D. Howard and contributors. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: @@ -27,55 +27,27 @@ # POSSIBILITY OF SUCH DAMAGE. # -# Just print the usage and exit with an error. -usage() { - printf 'usage: %s [-a] [afl_compiler]\n' "$0" 1>&2 - printf '\n' - printf ' If -a is given, then an ASan ready build is created.\n' - printf ' Otherwise, a normal fuzz build is created.\n' - printf ' The ASan-ready build is for running under\n' - printf ' `tests/afl.py --asan`, which checks that there were no\n' - printf ' memory errors in any path found by the fuzzer.\n' - printf ' It might also be useful to run scripts/randmath.py on an\n' - printf ' ASan-ready binary.\n' - exit 1 -} +scriptdir=$(dirname "$0") -script="$0" -scriptdir=$(dirname "$script") +. "$scriptdir/functions.sh" -asan=0 - -# Process command-line arguments. -while getopts "a" opt; do - - case "$opt" in - a) asan=1 ; shift ;; - ?) usage "Invalid option: $opt" ;; - esac - -done +cd "$scriptdir/.." -if [ $# -lt 1 ]; then - CC=afl-clang-lto +if [ "$#" -gt 0 ]; then + files="$@" else - CC="$1" + files=$(find "." -name "*.c" -or -name "*.h") fi -# We want this for extra sensitive crashing -AFL_HARDEN=1 +for f in $files; do -cd "$scriptdir/.." - -set -e + case "$f" in + *scripts/ministat.c) continue ;; + esac -if [ "$asan" -ne 0 ]; then - CFLAGS="-flto -fsanitize=address" -else - CFLAGS="-flto" -fi + clang-format -i --style=file "$f" + sed -i 's|^#else //|#else //|g' "$f" -# We want a debug build because asserts are counted as crashes too. -CC="$CC" CFLAGS="$CFLAGS" ./configure.sh -gO3 -z +done -make -j16 +sed -i 's|^ // clang-format on| // clang-format on|g' src/program.c diff --git a/contrib/bc/scripts/functions.sh b/contrib/bc/scripts/functions.sh index e794d96fc707..13ccbf8f3f31 100755 --- a/contrib/bc/scripts/functions.sh +++ b/contrib/bc/scripts/functions.sh @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: BSD-2-Clause # -# Copyright (c) 2018-2021 Gavin D. Howard and contributors. +# Copyright (c) 2018-2025 Gavin D. Howard and contributors. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: @@ -71,6 +71,88 @@ err_exit() { exit "$2" } +# Function for checking the "d"/"dir" argument of scripts. This function expects +# a usage() function to exist in the caller. +# @param 1 The argument to check. +check_d_arg() { + + if [ "$#" -ne 1 ]; then + printf 'Invalid number of args to check_d_arg\n' + exit 1 + fi + + _check_d_arg_arg="$1" + shift + + if [ "$_check_d_arg_arg" != "bc" ] && [ "$_check_d_arg_arg" != "dc" ]; then + _check_d_arg_msg=$(printf 'Invalid d arg: %s\nMust be either "bc" or "dc".\n\n' \ + "$_check_d_arg_arg") + usage "$_check_d_arg_msg" + fi +} + +# Function for checking the boolean arguments of scripts. This function expects +# a usage() function to exist in the caller. +# @param 1 The argument to check. +check_bool_arg() { + + if [ "$#" -ne 1 ]; then + printf 'Invalid number of args to check_bool_arg\n' + exit 1 + fi + + _check_bool_arg_arg="$1" + shift + + if [ "$_check_bool_arg_arg" != "0" ] && [ "$_check_bool_arg_arg" != "1" ]; then + _check_bool_arg_msg=$(printf 'Invalid bool arg: %s\nMust be either "0" or "1".\n\n' \ + "$_check_bool_arg_arg") + usage "$_check_bool_arg_msg" + fi +} + +# Function for checking the executable arguments of scripts. This function +# expects a usage() function to exist in the caller. +# @param 1 The argument to check. +check_exec_arg() { + + if [ "$#" -ne 1 ]; then + printf 'Invalid number of args to check_exec_arg\n' + exit 1 + fi + + _check_exec_arg_arg="$1" + shift + + if [ ! -x "$_check_exec_arg_arg" ]; then + if ! command -v "$_check_exec_arg_arg" >/dev/null 2>&1; then + _check_exec_arg_msg=$(printf 'Invalid exec arg: %s\nMust be an executable file.\n\n' \ + "$_check_exec_arg_arg") + usage "$_check_exec_arg_msg" + fi + fi +} + +# Function for checking the file arguments of scripts. This function expects a +# usage() function to exist in the caller. +# @param 1 The argument to check. +check_file_arg() { + + if [ "$#" -ne 1 ]; then + printf 'Invalid number of args to check_file_arg\n' + exit 1 + fi + + _check_file_arg_arg="$1" + shift + + if [ ! -f "$_check_file_arg_arg" ]; then + _check_file_arg_msg=$(printf 'Invalid file arg: %s\nMust be a file.\n\n' \ + "$_check_file_arg_arg") + usage "$_check_file_arg_msg" + fi +} + # Check the return code on a test and exit with a fail if it's non-zero. # @param d The calculator under test. # @param err The return code. @@ -223,11 +305,9 @@ checkerrtest() die "$_checkerrtest_d" "produced no error message" "$_checkerrtest_name" "$_checkerrtest_error" fi - # Display the error messages if not directly running exe. - # This allows the script to print valgrind output. - if [ "$_checkerrtest_exebase" != "bc" ] && [ "$_checkerrtest_exebase" != "dc" ]; then - cat "$_checkerrtest_out" - fi + # To display error messages, uncomment this line. This is useful when + # debugging. + #cat "$_checkerrtest_out" } # Replace a substring in a string with another. This function is the *real* @@ -328,3 +408,94 @@ gen_nlspath() { # Return the result. printf '%s' "$_gen_nlspath_nlspath" } + +ALL=0 +NOSKIP=1 +SKIP=2 + +# Filters text out of a file according to the build type. +# @param in File to filter. +# @param out File to write the filtered output to. +# @param type Build type. +filter_text() { + + _filter_text_in="$1" + shift + + _filter_text_out="$1" + shift + + _filter_text_buildtype="$1" + shift + + # Set up some local variables. + _filter_text_status="$ALL" + _filter_text_last_line="" + + # We need to set IFS, so we store it here for restoration later. + _filter_text_ifs="$IFS" + + # Remove the file- that will be generated. + rm -rf "$_filter_text_out" + + # Here is the magic. This loop reads the template line-by-line, and based on + # _filter_text_status, either prints it to the markdown manual or not. + # + # Here is how the template is set up: it is a normal markdown file except + # that there are sections surrounded tags that look like this: + # + # {{ <build_type_list> }} + # ... + # {{ end }} + # + # Those tags mean that whatever build types are found in the + # <build_type_list> get to keep that section. Otherwise, skip. + # + # Obviously, the tag itself and its end are not printed to the markdown + # manual. + while IFS= read -r _filter_text_line; do + + # If we have found an end, reset the status. + if [ "$_filter_text_line" = "{{ end }}" ]; then + + # Some error checking. This helps when editing the templates. + if [ "$_filter_text_status" -eq "$ALL" ]; then + err_exit "{{ end }} tag without corresponding start tag" 2 + fi + + _filter_text_status="$ALL" + + # We have found a tag that allows our build type to use it. + elif [ "${_filter_text_line#\{\{* $_filter_text_buildtype *\}\}}" != "$_filter_text_line" ]; then + + # More error checking. We don't want tags nested. + if [ "$_filter_text_status" -ne "$ALL" ]; then + err_exit "start tag nested in start tag" 3 + fi + + _filter_text_status="$NOSKIP" + + # We have found a tag that is *not* allowed for our build type. + elif [ "${_filter_text_line#\{\{*\}\}}" != "$_filter_text_line" ]; then + + if [ "$_filter_text_status" -ne "$ALL" ]; then + err_exit "start tag nested in start tag" 3 + fi + + _filter_text_status="$SKIP" + + # This is for normal lines. If we are not skipping, print. + else + if [ "$_filter_text_status" -ne "$SKIP" ]; then + if [ "$_filter_text_line" != "$_filter_text_last_line" ]; then + printf '%s\n' "$_filter_text_line" >> "$_filter_text_out" + fi + _filter_text_last_line="$_filter_text_line" + fi + fi + + done < "$_filter_text_in" + + # Reset IFS. + IFS="$_filter_text_ifs" +} diff --git a/contrib/bc/scripts/karatsuba.py b/contrib/bc/scripts/karatsuba.py index b8505186b526..c4e0720b3408 100755 --- a/contrib/bc/scripts/karatsuba.py +++ b/contrib/bc/scripts/karatsuba.py @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: BSD-2-Clause # -# Copyright (c) 2018-2021 Gavin D. Howard and contributors. +# Copyright (c) 2018-2025 Gavin D. Howard and contributors. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: @@ -49,9 +49,6 @@ testdir = os.path.dirname(script) if testdir == "": testdir = os.getcwd() -# We want to be in the root directory. -os.chdir(testdir + "/..") - print("\nWARNING: This script is for distro and package maintainers.") print("It is for finding the optimal Karatsuba number.") print("Though it only needs to be run once per release/platform,") @@ -116,7 +113,7 @@ try: except KeyError: flags["CFLAGS"] = "-flto" -p = run([ "./configure.sh", "-O3" ], flags) +p = run([ "{}/../configure.sh".format(testdir), "-O3" ], flags) if p.returncode != 0: print("configure.sh returned an error ({}); exiting...".format(p.returncode)) sys.exit(p.returncode) @@ -161,7 +158,7 @@ try: # Configure and compile. print("\nCompiling...\n") - p = run([ "./configure.sh", "-O3", "-k{}".format(i) ], config_env) + p = run([ "{}/../configure.sh".format(testdir), "-O3", "-k{}".format(i) ], config_env) if p.returncode != 0: print("configure.sh returned an error ({}); exiting...".format(p.returncode)) diff --git a/contrib/bc/scripts/link.sh b/contrib/bc/scripts/link.sh index f1c403d50dda..4562677d7b38 100755 --- a/contrib/bc/scripts/link.sh +++ b/contrib/bc/scripts/link.sh @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: BSD-2-Clause # -# Copyright (c) 2018-2021 Gavin D. Howard and contributors. +# Copyright (c) 2018-2025 Gavin D. Howard and contributors. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: @@ -32,6 +32,11 @@ usage() { exit 1 } +script="$0" +scriptdir=$(dirname "$script") + +. "$scriptdir/functions.sh" + # Command-line processing. test "$#" -gt 1 || usage diff --git a/contrib/bc/scripts/test_settings.sh b/contrib/bc/scripts/lint.sh index 563dbf0e58f3..611560ced31a 100755 --- a/contrib/bc/scripts/test_settings.sh +++ b/contrib/bc/scripts/lint.sh @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: BSD-2-Clause # -# Copyright (c) 2018-2021 Gavin D. Howard and contributors. +# Copyright (c) 2018-2025 Gavin D. Howard and contributors. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: @@ -27,51 +27,40 @@ # POSSIBILITY OF SUCH DAMAGE. # -# This script's argument is a number, which is the index of the setting set -# that is under test. This script is for maintainers only. -# -# The procedure is this: run the script with: -# -# ./scripts/test_settings.sh 1 -# -# Then run bc and dc to ensure their stuff is correct. Then run this script -# again with: -# -# ./scripts/test_settings.sh 2 -# -# And repeat. You can also test various environment variable sets with them. - -# Print the usage and exit with an error. -usage() { - printf 'usage: %s index\n' "$0" 1>&2 - exit 1 -} - script="$0" scriptdir=$(dirname "$script") -cd "$scriptdir/.." +. "$scriptdir/functions.sh" -test "$#" -eq 1 || usage +cd "$scriptdir/.." -target="$1" -shift +if [ "$#" -gt 0 ]; then + files="$@" +else + files=$(find "." -name "*.c" -or -name "*.h") +fi -line=0 +for f in $files; do -# This loop just loops until it gets to the right line. Quick and dirty. -while read s; do + case "$f" in + *scripts/ministat.c) continue ;; + esac - line=$(printf '%s + 1\n' "$line" | bc) + contents=$(clang-tidy --use-color -p ../build "$f" -- -I./include \ + -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -D_BSD_SOURCE \ + -D_GNU_SOURCE -D_DEFAULT_SOURCE 2>&1) - if [ "$line" -eq "$target" ]; then + err="$?" - # Configure, build, and exit. - ./configure.sh -O3 $s + if [ ! -z "$contents" ] || [ "$err" -ne 0 ]; then - make -j16 > /dev/null + printf '%s\n' "$f" + printf '%s\n' "$contents" + printf '\n' - exit + if [ "$err" -ne 0 ]; then + exit "$err" + fi fi -done < "$scriptdir/test_settings.txt" +done diff --git a/contrib/bc/scripts/locale_install.sh b/contrib/bc/scripts/locale_install.sh index a67e6aa52970..cec69d7201f4 100755 --- a/contrib/bc/scripts/locale_install.sh +++ b/contrib/bc/scripts/locale_install.sh @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: BSD-2-Clause # -# Copyright (c) 2018-2021 Gavin D. Howard and contributors. +# Copyright (c) 2018-2025 Gavin D. Howard and contributors. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: @@ -28,6 +28,7 @@ # # Just print the usage and exit with an error. +# @param 1 A message to print. usage() { if [ $# -eq 1 ]; then printf '%s\n' "$1" @@ -183,13 +184,14 @@ all_locales=0 while getopts "l" opt; do case "$opt" in - l) all_locales=1 ; shift ;; + l) all_locales=1 ;; ?) usage "Invalid option: $opt" ;; esac done +shift $(($OPTIND - 1)) -test "$#" -ge 2 || usage +test "$#" -ge 2 || usage "Must have at least two arguments" nlspath="$1" shift @@ -240,11 +242,15 @@ for file in $locales_dir/*.msg; do continue fi + printf 'Installing %s...' "$locale" + # Generate the proper location for the cat file. loc=$(gen_nlspath "$destdir/$nlspath" "$locale" "$main_exec") gencatfile "$loc" "$file" + printf 'done\n' + done # Now that we have done the non-symlinks, it's time to do the symlinks. Think @@ -275,6 +281,8 @@ for file in $locales_dir/*.msg; do # Make sure to skip non-symlinks; they are already done. if [ -L "$file" ]; then + printf 'Linking %s...' "$locale" + # This song and dance is because we want to generate relative symlinks. # They take less space, but also, they are more resilient to being # moved. @@ -294,6 +302,8 @@ for file in $locales_dir/*.msg; do # Finally, symlink to the install of the generated cat file that # corresponds to the correct msg file. ln -fs "$rel" "$loc" + + printf 'done\n' fi done diff --git a/contrib/bc/scripts/locale_uninstall.sh b/contrib/bc/scripts/locale_uninstall.sh index 3e79e083b803..274b6bcf49f1 100755 --- a/contrib/bc/scripts/locale_uninstall.sh +++ b/contrib/bc/scripts/locale_uninstall.sh @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: BSD-2-Clause # -# Copyright (c) 2018-2021 Gavin D. Howard and contributors. +# Copyright (c) 2018-2025 Gavin D. Howard and contributors. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: diff --git a/contrib/bc/scripts/manpage.sh b/contrib/bc/scripts/manpage.sh deleted file mode 100755 index c1429a6ed51f..000000000000 --- a/contrib/bc/scripts/manpage.sh +++ /dev/null @@ -1,175 +0,0 @@ -#! /bin/sh -# -# SPDX-License-Identifier: BSD-2-Clause -# -# Copyright (c) 2018-2021 Gavin D. Howard and contributors. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# - -# Print the usage and exit with an error. -usage() { - printf "usage: %s manpage\n" "$0" 1>&2 - exit 1 -} - -# Generate a manpage and print it to a file. -# @param md The markdown manual to generate a manpage for. -# @param out The file to print the manpage to. -gen_manpage() { - - _gen_manpage_md="$1" - shift - - _gen_manpage_out="$1" - shift - - cat "$manualsdir/header.txt" > "$_gen_manpage_out" - cat "$manualsdir/header_${manpage}.txt" >> "$_gen_manpage_out" - - pandoc -f commonmark_x -t man "$_gen_manpage_md" >> "$_gen_manpage_out" -} - -# Generate a manual from a template and print it to a file before generating -# its manpage. -# param args The type of markdown manual to generate. This is a string that -# corresponds to build type (see the Build Type section of the -# manuals/build.md manual). -gen_manual() { - - _gen_manual_args="$1" - shift - - # Set up some local variables. $manualsdir and $manpage from from the - # variables outside the function. - _gen_manual_status="$ALL" - _gen_manual_out="$manualsdir/$manpage/$_gen_manual_args.1" - _gen_manual_md="$manualsdir/$manpage/$_gen_manual_args.1.md" - _gen_manual_temp="$manualsdir/temp.1.md" - - # We need to set IFS, so we store it here for restoration later. - _gen_manual_ifs="$IFS" - - # Remove the files that will be generated. - rm -rf "$_gen_manual_out" "$_gen_manual_md" - - # Here is the magic. This loop reads the template line-by-line, and based on - # _gen_manual_status, either prints it to the markdown manual or not. - # - # Here is how the template is set up: it is a normal markdown file except - # that there are sections surrounded tags that look like this: - # - # {{ <build_type_list> }} - # ... - # {{ end }} - # - # Those tags mean that whatever build types are found in the - # <build_type_list> get to keep that section. Otherwise, skip. - # - # Obviously, the tag itself and its end are not printed to the markdown - # manual. - while IFS= read -r line; do - - # If we have found an end, reset the status. - if [ "$line" = "{{ end }}" ]; then - - # Some error checking. This helps when editing the templates. - if [ "$_gen_manual_status" -eq "$ALL" ]; then - err_exit "{{ end }} tag without corresponding start tag" 2 - fi - - _gen_manual_status="$ALL" - - # We have found a tag that allows our build type to use it. - elif [ "${line#\{\{* $_gen_manual_args *\}\}}" != "$line" ]; then - - # More error checking. We don't want tags nested. - if [ "$_gen_manual_status" -ne "$ALL" ]; then - err_exit "start tag nested in start tag" 3 - fi - - _gen_manual_status="$NOSKIP" - - # We have found a tag that is *not* allowed for our build type. - elif [ "${line#\{\{*\}\}}" != "$line" ]; then - - if [ "$_gen_manual_status" -ne "$ALL" ]; then - err_exit "start tag nested in start tag" 3 - fi - - _gen_manual_status="$SKIP" - - # This is for normal lines. If we are not skipping, print. - else - if [ "$_gen_manual_status" -ne "$SKIP" ]; then - printf '%s\n' "$line" >> "$_gen_manual_temp" - fi - fi - - done < "$manualsdir/${manpage}.1.md.in" - - # Remove multiple blank lines. - uniq "$_gen_manual_temp" "$_gen_manual_md" - - # Remove the temp file. - rm -rf "$_gen_manual_temp" - - # Reset IFS. - IFS="$_gen_manual_ifs" - - # Generate the manpage. - gen_manpage "$_gen_manual_md" "$_gen_manual_out" -} - -set -e - -script="$0" -scriptdir=$(dirname "$script") -manualsdir="$scriptdir/../manuals" - -. "$scriptdir/functions.sh" - -# Constants for use later. If the set of build types is changed, $ARGS must be -# updated. -ARGS="A E H N EH EN HN EHN" -ALL=0 -NOSKIP=1 -SKIP=2 - -# Process command-line arguments. -test "$#" -eq 1 || usage - -manpage="$1" -shift - -if [ "$manpage" != "bcl" ]; then - - # Generate a manual and manpage for each build type. - for a in $ARGS; do - gen_manual "$a" - done - -else - # For bcl, just generate the manpage. - gen_manpage "$manualsdir/${manpage}.3.md" "$manualsdir/${manpage}.3" -fi diff --git a/contrib/bc/scripts/ministat.c b/contrib/bc/scripts/ministat.c deleted file mode 100644 index 6bef341c5890..000000000000 --- a/contrib/bc/scripts/ministat.c +++ /dev/null @@ -1,670 +0,0 @@ -/*- - * SPDX-License-Identifier: Beerware - * - * ---------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp - * ---------------------------------------------------------------------------- - * - */ - -#include <sys/cdefs.h> - -#include <sys/ioctl.h> -#include <sys/queue.h> - -#include <assert.h> -#include <ctype.h> -#include <err.h> -#include <errno.h> -#include <math.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#define NSTUDENT 100 -#define NCONF 6 -static double const studentpct[] = { 80, 90, 95, 98, 99, 99.5 }; -static double const student[NSTUDENT + 1][NCONF] = { -/* inf */ { 1.282, 1.645, 1.960, 2.326, 2.576, 3.090 }, -/* 1. */ { 3.078, 6.314, 12.706, 31.821, 63.657, 318.313 }, -/* 2. */ { 1.886, 2.920, 4.303, 6.965, 9.925, 22.327 }, -/* 3. */ { 1.638, 2.353, 3.182, 4.541, 5.841, 10.215 }, -/* 4. */ { 1.533, 2.132, 2.776, 3.747, 4.604, 7.173 }, -/* 5. */ { 1.476, 2.015, 2.571, 3.365, 4.032, 5.893 }, -/* 6. */ { 1.440, 1.943, 2.447, 3.143, 3.707, 5.208 }, -/* 7. */ { 1.415, 1.895, 2.365, 2.998, 3.499, 4.782 }, -/* 8. */ { 1.397, 1.860, 2.306, 2.896, 3.355, 4.499 }, -/* 9. */ { 1.383, 1.833, 2.262, 2.821, 3.250, 4.296 }, -/* 10. */ { 1.372, 1.812, 2.228, 2.764, 3.169, 4.143 }, -/* 11. */ { 1.363, 1.796, 2.201, 2.718, 3.106, 4.024 }, -/* 12. */ { 1.356, 1.782, 2.179, 2.681, 3.055, 3.929 }, -/* 13. */ { 1.350, 1.771, 2.160, 2.650, 3.012, 3.852 }, -/* 14. */ { 1.345, 1.761, 2.145, 2.624, 2.977, 3.787 }, -/* 15. */ { 1.341, 1.753, 2.131, 2.602, 2.947, 3.733 }, -/* 16. */ { 1.337, 1.746, 2.120, 2.583, 2.921, 3.686 }, -/* 17. */ { 1.333, 1.740, 2.110, 2.567, 2.898, 3.646 }, -/* 18. */ { 1.330, 1.734, 2.101, 2.552, 2.878, 3.610 }, -/* 19. */ { 1.328, 1.729, 2.093, 2.539, 2.861, 3.579 }, -/* 20. */ { 1.325, 1.725, 2.086, 2.528, 2.845, 3.552 }, -/* 21. */ { 1.323, 1.721, 2.080, 2.518, 2.831, 3.527 }, -/* 22. */ { 1.321, 1.717, 2.074, 2.508, 2.819, 3.505 }, -/* 23. */ { 1.319, 1.714, 2.069, 2.500, 2.807, 3.485 }, -/* 24. */ { 1.318, 1.711, 2.064, 2.492, 2.797, 3.467 }, -/* 25. */ { 1.316, 1.708, 2.060, 2.485, 2.787, 3.450 }, -/* 26. */ { 1.315, 1.706, 2.056, 2.479, 2.779, 3.435 }, -/* 27. */ { 1.314, 1.703, 2.052, 2.473, 2.771, 3.421 }, -/* 28. */ { 1.313, 1.701, 2.048, 2.467, 2.763, 3.408 }, -/* 29. */ { 1.311, 1.699, 2.045, 2.462, 2.756, 3.396 }, -/* 30. */ { 1.310, 1.697, 2.042, 2.457, 2.750, 3.385 }, -/* 31. */ { 1.309, 1.696, 2.040, 2.453, 2.744, 3.375 }, -/* 32. */ { 1.309, 1.694, 2.037, 2.449, 2.738, 3.365 }, -/* 33. */ { 1.308, 1.692, 2.035, 2.445, 2.733, 3.356 }, -/* 34. */ { 1.307, 1.691, 2.032, 2.441, 2.728, 3.348 }, -/* 35. */ { 1.306, 1.690, 2.030, 2.438, 2.724, 3.340 }, -/* 36. */ { 1.306, 1.688, 2.028, 2.434, 2.719, 3.333 }, -/* 37. */ { 1.305, 1.687, 2.026, 2.431, 2.715, 3.326 }, -/* 38. */ { 1.304, 1.686, 2.024, 2.429, 2.712, 3.319 }, -/* 39. */ { 1.304, 1.685, 2.023, 2.426, 2.708, 3.313 }, -/* 40. */ { 1.303, 1.684, 2.021, 2.423, 2.704, 3.307 }, -/* 41. */ { 1.303, 1.683, 2.020, 2.421, 2.701, 3.301 }, -/* 42. */ { 1.302, 1.682, 2.018, 2.418, 2.698, 3.296 }, -/* 43. */ { 1.302, 1.681, 2.017, 2.416, 2.695, 3.291 }, -/* 44. */ { 1.301, 1.680, 2.015, 2.414, 2.692, 3.286 }, -/* 45. */ { 1.301, 1.679, 2.014, 2.412, 2.690, 3.281 }, -/* 46. */ { 1.300, 1.679, 2.013, 2.410, 2.687, 3.277 }, -/* 47. */ { 1.300, 1.678, 2.012, 2.408, 2.685, 3.273 }, -/* 48. */ { 1.299, 1.677, 2.011, 2.407, 2.682, 3.269 }, -/* 49. */ { 1.299, 1.677, 2.010, 2.405, 2.680, 3.265 }, -/* 50. */ { 1.299, 1.676, 2.009, 2.403, 2.678, 3.261 }, -/* 51. */ { 1.298, 1.675, 2.008, 2.402, 2.676, 3.258 }, -/* 52. */ { 1.298, 1.675, 2.007, 2.400, 2.674, 3.255 }, -/* 53. */ { 1.298, 1.674, 2.006, 2.399, 2.672, 3.251 }, -/* 54. */ { 1.297, 1.674, 2.005, 2.397, 2.670, 3.248 }, -/* 55. */ { 1.297, 1.673, 2.004, 2.396, 2.668, 3.245 }, -/* 56. */ { 1.297, 1.673, 2.003, 2.395, 2.667, 3.242 }, -/* 57. */ { 1.297, 1.672, 2.002, 2.394, 2.665, 3.239 }, -/* 58. */ { 1.296, 1.672, 2.002, 2.392, 2.663, 3.237 }, -/* 59. */ { 1.296, 1.671, 2.001, 2.391, 2.662, 3.234 }, -/* 60. */ { 1.296, 1.671, 2.000, 2.390, 2.660, 3.232 }, -/* 61. */ { 1.296, 1.670, 2.000, 2.389, 2.659, 3.229 }, -/* 62. */ { 1.295, 1.670, 1.999, 2.388, 2.657, 3.227 }, -/* 63. */ { 1.295, 1.669, 1.998, 2.387, 2.656, 3.225 }, -/* 64. */ { 1.295, 1.669, 1.998, 2.386, 2.655, 3.223 }, -/* 65. */ { 1.295, 1.669, 1.997, 2.385, 2.654, 3.220 }, -/* 66. */ { 1.295, 1.668, 1.997, 2.384, 2.652, 3.218 }, -/* 67. */ { 1.294, 1.668, 1.996, 2.383, 2.651, 3.216 }, -/* 68. */ { 1.294, 1.668, 1.995, 2.382, 2.650, 3.214 }, -/* 69. */ { 1.294, 1.667, 1.995, 2.382, 2.649, 3.213 }, -/* 70. */ { 1.294, 1.667, 1.994, 2.381, 2.648, 3.211 }, -/* 71. */ { 1.294, 1.667, 1.994, 2.380, 2.647, 3.209 }, -/* 72. */ { 1.293, 1.666, 1.993, 2.379, 2.646, 3.207 }, -/* 73. */ { 1.293, 1.666, 1.993, 2.379, 2.645, 3.206 }, -/* 74. */ { 1.293, 1.666, 1.993, 2.378, 2.644, 3.204 }, -/* 75. */ { 1.293, 1.665, 1.992, 2.377, 2.643, 3.202 }, -/* 76. */ { 1.293, 1.665, 1.992, 2.376, 2.642, 3.201 }, -/* 77. */ { 1.293, 1.665, 1.991, 2.376, 2.641, 3.199 }, -/* 78. */ { 1.292, 1.665, 1.991, 2.375, 2.640, 3.198 }, -/* 79. */ { 1.292, 1.664, 1.990, 2.374, 2.640, 3.197 }, -/* 80. */ { 1.292, 1.664, 1.990, 2.374, 2.639, 3.195 }, -/* 81. */ { 1.292, 1.664, 1.990, 2.373, 2.638, 3.194 }, -/* 82. */ { 1.292, 1.664, 1.989, 2.373, 2.637, 3.193 }, -/* 83. */ { 1.292, 1.663, 1.989, 2.372, 2.636, 3.191 }, -/* 84. */ { 1.292, 1.663, 1.989, 2.372, 2.636, 3.190 }, -/* 85. */ { 1.292, 1.663, 1.988, 2.371, 2.635, 3.189 }, -/* 86. */ { 1.291, 1.663, 1.988, 2.370, 2.634, 3.188 }, -/* 87. */ { 1.291, 1.663, 1.988, 2.370, 2.634, 3.187 }, -/* 88. */ { 1.291, 1.662, 1.987, 2.369, 2.633, 3.185 }, -/* 89. */ { 1.291, 1.662, 1.987, 2.369, 2.632, 3.184 }, -/* 90. */ { 1.291, 1.662, 1.987, 2.368, 2.632, 3.183 }, -/* 91. */ { 1.291, 1.662, 1.986, 2.368, 2.631, 3.182 }, -/* 92. */ { 1.291, 1.662, 1.986, 2.368, 2.630, 3.181 }, -/* 93. */ { 1.291, 1.661, 1.986, 2.367, 2.630, 3.180 }, -/* 94. */ { 1.291, 1.661, 1.986, 2.367, 2.629, 3.179 }, -/* 95. */ { 1.291, 1.661, 1.985, 2.366, 2.629, 3.178 }, -/* 96. */ { 1.290, 1.661, 1.985, 2.366, 2.628, 3.177 }, -/* 97. */ { 1.290, 1.661, 1.985, 2.365, 2.627, 3.176 }, -/* 98. */ { 1.290, 1.661, 1.984, 2.365, 2.627, 3.175 }, -/* 99. */ { 1.290, 1.660, 1.984, 2.365, 2.626, 3.175 }, -/* 100. */ { 1.290, 1.660, 1.984, 2.364, 2.626, 3.174 } -}; - -#define MAX_DS 8 -static char symbol[MAX_DS] = { ' ', 'x', '+', '*', '%', '#', '@', 'O' }; - -struct dataset { - char *name; - double *points; - size_t lpoints; - double sy, syy; - size_t n; -}; - -static struct dataset * -NewSet(void) -{ - struct dataset *ds; - - ds = calloc(1, sizeof *ds); - assert(ds != NULL); - ds->lpoints = 100000; - ds->points = calloc(sizeof *ds->points, ds->lpoints); - assert(ds->points != NULL); - ds->syy = NAN; - return(ds); -} - -static void -AddPoint(struct dataset *ds, double a) -{ - double *dp; - - if (ds->n >= ds->lpoints) { - dp = ds->points; - ds->lpoints *= 4; - ds->points = calloc(sizeof *ds->points, ds->lpoints); - assert(ds->points != NULL); - memcpy(ds->points, dp, sizeof *dp * ds->n); - free(dp); - } - ds->points[ds->n++] = a; - ds->sy += a; -} - -static double -Min(const struct dataset *ds) -{ - - return (ds->points[0]); -} - -static double -Max(const struct dataset *ds) -{ - - return (ds->points[ds->n -1]); -} - -static double -Avg(const struct dataset *ds) -{ - - return(ds->sy / ds->n); -} - -static double -Median(const struct dataset *ds) -{ - const size_t m = ds->n / 2; - - if ((ds->n % 2) == 0) - return ((ds->points[m] + (ds->points[m - 1])) / 2); - return (ds->points[m]); -} - -static double -Var(struct dataset *ds) -{ - size_t z; - const double a = Avg(ds); - - if (isnan(ds->syy)) { - ds->syy = 0.0; - for (z = 0; z < ds->n; z++) - ds->syy += (ds->points[z] - a) * (ds->points[z] - a); - } - - return (ds->syy / (ds->n - 1.0)); -} - -static double -Stddev(struct dataset *ds) -{ - - return sqrt(Var(ds)); -} - -static void -VitalsHead(void) -{ - - printf(" N Min Max Median Avg Stddev\n"); -} - -static void -Vitals(struct dataset *ds, int flag) -{ - - printf("%c %3zu %13.8g %13.8g %13.8g %13.8g %13.8g", symbol[flag], - ds->n, Min(ds), Max(ds), Median(ds), Avg(ds), Stddev(ds)); - printf("\n"); -} - -static void -Relative(struct dataset *ds, struct dataset *rs, int confidx) -{ - double spool, s, d, e, t; - double re; - size_t z; - - z = ds->n + rs->n - 2; - if (z > NSTUDENT) - t = student[0][confidx]; - else - t = student[z][confidx]; - spool = (ds->n - 1) * Var(ds) + (rs->n - 1) * Var(rs); - spool /= ds->n + rs->n - 2; - spool = sqrt(spool); - s = spool * sqrt(1.0 / ds->n + 1.0 / rs->n); - d = Avg(ds) - Avg(rs); - e = t * s; - - re = (ds->n - 1) * Var(ds) + (rs->n - 1) * Var(rs) * - (Avg(ds) * Avg(ds)) / (Avg(rs) * Avg(rs)); - re *= (ds->n + rs->n) / (ds->n * rs->n * (ds->n + rs->n - 2.0)); - re = t * sqrt(re); - - if (fabs(d) > e) { - printf("Difference at %.1f%% confidence\n", studentpct[confidx]); - printf(" %g +/- %g\n", d, e); - printf(" %g%% +/- %g%%\n", d * 100 / Avg(rs), re * 100 / Avg(rs)); - printf(" (Student's t, pooled s = %g)\n", spool); - } else { - printf("No difference proven at %.1f%% confidence\n", - studentpct[confidx]); - } -} - -struct plot { - double min; - double max; - double span; - int width; - - double x0, dx; - size_t height; - char *data; - char **bar; - int separate_bars; - int num_datasets; -}; - -static struct plot plot; - -static void -SetupPlot(int width, int separate, int num_datasets) -{ - struct plot *pl; - - pl = &plot; - pl->width = width; - pl->height = 0; - pl->data = NULL; - pl->bar = NULL; - pl->separate_bars = separate; - pl->num_datasets = num_datasets; - pl->min = 999e99; - pl->max = -999e99; -} - -static void -AdjPlot(double a) -{ - struct plot *pl; - - pl = &plot; - if (a < pl->min) - pl->min = a; - if (a > pl->max) - pl->max = a; - pl->span = pl->max - pl->min; - pl->dx = pl->span / (pl->width - 1.0); - pl->x0 = pl->min - .5 * pl->dx; -} - -static void -DimPlot(struct dataset *ds) -{ - AdjPlot(Min(ds)); - AdjPlot(Max(ds)); - AdjPlot(Avg(ds) - Stddev(ds)); - AdjPlot(Avg(ds) + Stddev(ds)); -} - -static void -PlotSet(struct dataset *ds, int val) -{ - struct plot *pl; - int i, x; - size_t m, j, z; - size_t n; - int bar; - double av, sd; - - pl = &plot; - if (pl->span == 0) - return; - - if (pl->separate_bars) - bar = val-1; - else - bar = 0; - - if (pl->bar == NULL) { - pl->bar = calloc(sizeof(char *), pl->num_datasets); - assert(pl->bar != NULL); - } - - if (pl->bar[bar] == NULL) { - pl->bar[bar] = malloc(pl->width); - assert(pl->bar[bar] != NULL); - memset(pl->bar[bar], 0, pl->width); - } - - m = 1; - i = -1; - j = 0; - /* Set m to max(j) + 1, to allocate required memory */ - for (n = 0; n < ds->n; n++) { - x = (ds->points[n] - pl->x0) / pl->dx; - if (x == i) { - j++; - if (j > m) - m = j; - } else { - j = 1; - i = x; - } - } - m += 1; - if (m > pl->height) { - pl->data = realloc(pl->data, pl->width * m); - assert(pl->data != NULL); - memset(pl->data + pl->height * pl->width, 0, - (m - pl->height) * pl->width); - } - pl->height = m; - i = -1; - for (n = 0; n < ds->n; n++) { - x = (ds->points[n] - pl->x0) / pl->dx; - if (x == i) { - j++; - } else { - j = 1; - i = x; - } - pl->data[j * pl->width + x] |= val; - } - av = Avg(ds); - sd = Stddev(ds); - if (!isnan(sd)) { - x = ((av - sd) - pl->x0) / pl->dx; - m = ((av + sd) - pl->x0) / pl->dx; - pl->bar[bar][m] = '|'; - pl->bar[bar][x] = '|'; - for (z = x + 1; z < m; z++) - if (pl->bar[bar][z] == 0) - pl->bar[bar][z] = '_'; - } - x = (Median(ds) - pl->x0) / pl->dx; - pl->bar[bar][x] = 'M'; - x = (av - pl->x0) / pl->dx; - pl->bar[bar][x] = 'A'; -} - -static void -DumpPlot(void) -{ - struct plot *pl; - int i, j, k; - size_t z; - - pl = &plot; - if (pl->span == 0) { - printf("[no plot, span is zero width]\n"); - return; - } - - putchar('+'); - for (i = 0; i < pl->width; i++) - putchar('-'); - putchar('+'); - putchar('\n'); - for (z = 1; z < pl->height; z++) { - putchar('|'); - for (j = 0; j < pl->width; j++) { - k = pl->data[(pl->height - z) * pl->width + j]; - if (k >= 0 && k < MAX_DS) - putchar(symbol[k]); - else - printf("[%02x]", k); - } - putchar('|'); - putchar('\n'); - } - for (i = 0; i < pl->num_datasets; i++) { - if (pl->bar[i] == NULL) - continue; - putchar('|'); - for (j = 0; j < pl->width; j++) { - k = pl->bar[i][j]; - if (k == 0) - k = ' '; - putchar(k); - } - putchar('|'); - putchar('\n'); - } - putchar('+'); - for (i = 0; i < pl->width; i++) - putchar('-'); - putchar('+'); - putchar('\n'); -} - -static int -dbl_cmp(const void *a, const void *b) -{ - const double *aa = a; - const double *bb = b; - - if (*aa < *bb) - return (-1); - else if (*aa > *bb) - return (1); - else - return (0); -} - -static struct dataset * -ReadSet(FILE *f, const char *n, int column, const char *delim) -{ - char buf[BUFSIZ], *p, *t; - struct dataset *s; - double d; - int line; - int i; - - s = NewSet(); - s->name = strdup(n); - assert(s->name != NULL); - line = 0; - while (fgets(buf, sizeof buf, f) != NULL) { - line++; - - i = strlen(buf); - while (i > 0 && isspace(buf[i - 1])) - buf[--i] = '\0'; - for (i = 1, t = strtok(buf, delim); - t != NULL && *t != '#'; - i++, t = strtok(NULL, delim)) { - if (i == column) - break; - } - if (t == NULL || *t == '#') - continue; - - d = strtod(t, &p); - if (p != NULL && *p != '\0') - errx(2, "Invalid data on line %d in %s", line, n); - if (*buf != '\0') - AddPoint(s, d); - } - if (s->n < 3) { - fprintf(stderr, - "Dataset %s must contain at least 3 data points\n", n); - exit (2); - } - qsort(s->points, s->n, sizeof *s->points, dbl_cmp); - return (s); -} - -static void -usage(char const *whine) -{ - int i; - - fprintf(stderr, "%s\n", whine); - fprintf(stderr, - "Usage: ministat [-C column] [-c confidence] [-d delimiter(s)] [-Ans] [-w width] [file [file ...]]\n"); - fprintf(stderr, "\tconfidence = {"); - for (i = 0; i < NCONF; i++) { - fprintf(stderr, "%s%g%%", - i ? ", " : "", - studentpct[i]); - } - fprintf(stderr, "}\n"); - fprintf(stderr, "\t-A : print statistics only. suppress the graph.\n"); - fprintf(stderr, "\t-C : column number to extract (starts and defaults to 1)\n"); - fprintf(stderr, "\t-d : delimiter(s) string, default to \" \\t\"\n"); - fprintf(stderr, "\t-n : print summary statistics only, no graph/test\n"); - fprintf(stderr, "\t-s : print avg/median/stddev bars on separate lines\n"); - fprintf(stderr, "\t-w : width of graph/test output (default 74 or terminal width)\n"); - exit (2); -} - -int -main(int argc, char **argv) -{ - const char *setfilenames[MAX_DS - 1]; - struct dataset *ds[MAX_DS - 1]; - FILE *setfiles[MAX_DS - 1]; - int nds; - double a; - const char *delim = " \t"; - char *p; - int c, i, ci; - int column = 1; - int flag_s = 0; - int flag_n = 0; - int termwidth = 74; - int suppress_plot = 0; - - if (isatty(STDOUT_FILENO)) { - struct winsize wsz; - - if ((p = getenv("COLUMNS")) != NULL && *p != '\0') - termwidth = atoi(p); - else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &wsz) != -1 && - wsz.ws_col > 0) - termwidth = wsz.ws_col - 2; - } - - ci = -1; - while ((c = getopt(argc, argv, "AC:c:d:snw:")) != -1) - switch (c) { - case 'A': - suppress_plot = 1; - break; - case 'C': - column = strtol(optarg, &p, 10); - if (p != NULL && *p != '\0') - usage("Invalid column number."); - if (column <= 0) - usage("Column number should be positive."); - break; - case 'c': - a = strtod(optarg, &p); - if (p != NULL && *p != '\0') - usage("Not a floating point number"); - for (i = 0; i < NCONF; i++) - if (a == studentpct[i]) - ci = i; - if (ci == -1) - usage("No support for confidence level"); - break; - case 'd': - if (*optarg == '\0') - usage("Can't use empty delimiter string"); - delim = optarg; - break; - case 'n': - flag_n = 1; - break; - case 's': - flag_s = 1; - break; - case 'w': - termwidth = strtol(optarg, &p, 10); - if (p != NULL && *p != '\0') - usage("Invalid width, not a number."); - if (termwidth < 0) - usage("Unable to move beyond left margin."); - break; - default: - usage("Unknown option"); - break; - } - if (ci == -1) - ci = 2; - argc -= optind; - argv += optind; - - if (argc == 0) { - setfilenames[0] = "<stdin>"; - setfiles[0] = stdin; - nds = 1; - } else { - if (argc > (MAX_DS - 1)) - usage("Too many datasets."); - nds = argc; - for (i = 0; i < nds; i++) { - setfilenames[i] = argv[i]; - if (!strcmp(argv[i], "-")) - setfiles[0] = stdin; - else - setfiles[i] = fopen(argv[i], "r"); - if (setfiles[i] == NULL) - err(2, "Cannot open %s", argv[i]); - } - } - - for (i = 0; i < nds; i++) { - ds[i] = ReadSet(setfiles[i], setfilenames[i], column, delim); - if (setfiles[i] != stdin) - fclose(setfiles[i]); - } - - for (i = 0; i < nds; i++) - printf("%c %s\n", symbol[i+1], ds[i]->name); - - if (!flag_n && !suppress_plot) { - SetupPlot(termwidth, flag_s, nds); - for (i = 0; i < nds; i++) - DimPlot(ds[i]); - for (i = 0; i < nds; i++) - PlotSet(ds[i], i + 1); - DumpPlot(); - } - VitalsHead(); - Vitals(ds[0], 1); - for (i = 1; i < nds; i++) { - Vitals(ds[i], i + 1); - if (!flag_n) - Relative(ds[i], ds[0], ci); - } - exit(0); -} diff --git a/contrib/bc/scripts/os.c b/contrib/bc/scripts/os.c new file mode 100644 index 000000000000..89c5b1b95b3f --- /dev/null +++ b/contrib/bc/scripts/os.c @@ -0,0 +1,59 @@ +/* + * ***************************************************************************** + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2018-2025 Gavin D. Howard and contributors. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * ***************************************************************************** + * + * File for testing compilation on different platforms. + * + */ + +// This is used by configure.sh to test for OpenBSD. +#ifdef BC_TEST_OPENBSD +#ifdef __OpenBSD__ +#error On OpenBSD without _BSD_SOURCE +#endif // __OpenBSD__ +#endif // BC_TEST_OPENBSD + +// This is used by configure.sh to test for FreeBSD. +#ifdef BC_TEST_FREEBSD +#ifdef __FreeBSD__ +#error On FreeBSD with _POSIX_C_SOURCE +#endif // __FreeBSD__ +#endif // BC_TEST_FREEBSD + +// This is used by configure.sh to test for macOS. +#ifdef BC_TEST_APPLE +#ifdef __APPLE__ +#error On macOS without _DARWIN_C_SOURCE +#endif // __APPLE__ +#endif // BC_TEST_APPLE + +extern int test; + +int test; diff --git a/contrib/bc/scripts/package.sh b/contrib/bc/scripts/package.sh deleted file mode 100755 index 4b76b0462313..000000000000 --- a/contrib/bc/scripts/package.sh +++ /dev/null @@ -1,173 +0,0 @@ -#!/bin/sh -# -# SPDX-License-Identifier: BSD-2-Clause -# -# Copyright (c) 2018-2021 Gavin D. Howard and contributors. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# - -# This script requires some non-POSIX utilities, but that's okay because it's -# really for maintainer use only. -# -# The non-POSIX utilities include: -# -# * git -# * stat -# * tar -# * xz -# * sha512sum -# * sha256sum -# * gpg -# * zip - -script="$0" -scriptdir=$(dirname "$script") - -repo="$scriptdir/.." -proj="bc" - -cd "$repo" - -# We want the absolute path for later. -repo=$(pwd) - -# This convoluted mess does pull the version out. If you change the format of -# include/version.h, you may have to change this line. -version=$(cat include/version.h | grep "VERSION " - | awk '{ print $3 }' -) - -tag_msg="Version $version" -projver="${proj}-${version}" - -tempdir="/tmp/${projver}" -rm -rf $tempdir -mkdir -p $tempdir - -make clean_tests > /dev/null 2> /dev/null - -# Delete the tag and recreate it. This is the part of the script that makes it -# so you cannot run it twice on the same version, unless you know what you are -# doing. In fact, you cannot run it again if users have already started to use -# the old version of the tag. -if git rev-parse "$version" > /dev/null 2>&1; then - : - #git push --delete origin "$version" > /dev/null 2> /dev/null - #git tag --delete "$version" > /dev/null 2> /dev/null -fi - -#git push > /dev/null 2> /dev/null -#git tg "$version" -m "$tag_msg" > /dev/null 2> /dev/null -#git push --tags > /dev/null 2> /dev/null - -# This line grabs the names of all of the files in .gitignore that still exist. -ignores=$(git check-ignore * **/*) - -cp -r ./* "$tempdir" - -cd $tempdir - -# Delete all the ignored files. -for i in $ignores; do - rm -rf "./$i" -done - -# This is a list of files that end users (including *software packagers* and -# *distro maintainers*!) do not care about. In particular, they *do* care about -# the testing infrastructure for the regular test suite because distro -# maintainers probably want to ensure the test suite runs. However, they -# probably don't care about fuzzing or other randomized testing. Also, I -# technically can't distribute tests/bc/scripts/timeconst.bc because it's from -# the Linux kernel, which is GPL. -extras=$(cat <<*EOF -.git/ -.gitignore -.gitattributes -benchmarks/ -manuals/bc.1.md.in -manuals/dc.1.md.in -manuals/development.md -manuals/header_bcl.txt -manuals/header_bc.txt -manuals/header_dc.txt -manuals/header.txt -manuals/release.md -scripts/afl.py -scripts/alloc.sh -scripts/benchmark.sh -scripts/fuzz_prep.sh -scripts/manpage.sh -scripts/ministat.c -scripts/package.sh -scripts/radamsa.sh -scripts/radamsa.txt -scripts/randmath.py -scripts/release_settings.txt -scripts/release.sh -scripts/test_settings.sh -scripts/test_settings.txt -tests/bc/scripts/timeconst.bc -*EOF -) - -for i in $extras; do - rm -rf "./$i" -done - -cd .. - -parent="$repo/.." - -# Tar and compress and move into the parent directory of the repo. -tar cf "$projver.tar" "$projver/" -xz -z -v -9 -e "$projver.tar" > /dev/null 2> /dev/null -mv "$projver.tar.xz" "$parent" - -cd "$parent" - -windows_builds=$(cat <<*EOF -TODO -*EOF - -# All this fancy stuff takes the sha512 and sha256 sums and signs it. The -# output after this point is what I usually copy into the release notes. (See -# manuals/release.md for more information.) -printf '$ sha512sum %s.tar.xz\n' "$projver" -sha512sum "$projver.tar.xz" -printf '\n' -printf '$ sha256sum %s.tar.xz\n' "$projver" -sha256sum "$projver.tar.xz" -printf '\n' -printf "$ stat -c '%%s %%n'\n" "$projver.tar.xz" -stat -c '%s %n' "$projver.tar.xz" - -gpg --detach-sig -o "$projver.tar.xz.sig" "$projver.tar.xz" 2> /dev/null - -printf '\n' -printf '$ sha512sum %s.tar.xz.sig\n' "$projver" -sha512sum "$projver.tar.xz.sig" -printf '\n' -printf '$ sha256sum %s.tar.xz.sig\n' "$projver" -sha256sum "$projver.tar.xz.sig" -printf '\n' -printf "$ stat -c '%%s %%n'\n" "$projver.tar.xz.sig" -stat -c '%s %n' "$projver.tar.xz.sig" diff --git a/contrib/bc/scripts/radamsa.sh b/contrib/bc/scripts/radamsa.sh deleted file mode 100755 index c92923ddadc4..000000000000 --- a/contrib/bc/scripts/radamsa.sh +++ /dev/null @@ -1,133 +0,0 @@ -#! /bin/sh -# -# SPDX-License-Identifier: BSD-2-Clause -# -# Copyright (c) 2018-2021 Gavin D. Howard and contributors. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# - -# This script uses some non-POSIX behavior, but since it's meant for bc -# maintainers only, I can accept that. - -# Get an entry from the file. If an argument exists, it is an index. Get that -# line. Otherwise, get a random line. -getentry() { - - # Figure out if we get a specific or random line. - if [ $# -gt 0 ]; then - entnum="$1" - else - entnum=0 - fi - - # Get data from stdin and figure out how many lines there are. - e=$(cat -) - num=$(printf '%s\n' "$e" | wc -l) - - # Figure out what line we are going to get. Uses bc's own PRNG. - if [ "$entnum" -eq 0 ]; then - rand=$(printf 'irand(%s) + 1\n' "$num" | "$bcdir/bc") - else - rand="$entnum" - fi - - # Get the line. - ent=$(printf '%s\n' "$e" | tail -n +$rand | head -n 1) - - printf '%s\n' "$ent" -} - -script="$0" -dir=$(dirname "$script") - -. "$dir/functions.sh" - -# Command-line processing. -if [ "$#" -lt 1 ]; then - printf 'usage: %s dir\n' "$0" - exit 1 -fi - -d="$1" -shift - -bcdir="$dir/../bin" - -# Figure out the correct input directory. -if [ "$d" = "bc" ]; then - inputs="$dir/../tests/fuzzing/bc_inputs1" - opts="-lq" -elif [ "$d" = "dc" ]; then - inputs="$dir/../test/fuzzing/dc_inputs" - opts="-x" -else - err_exit "wrong type of executable" 1 -fi - -export ASAN_OPTIONS="abort_on_error=1:allocator_may_return_null=1" - -entries=$(cat "$dir/radamsa.txt") - -IFS=$'\n' - -go=1 - -# Infinite loop. -while [ "$go" -ne 0 ]; do - - # If we are running bc, fuzz command-line arguments in BC_ENV_ARGS. - if [ "$d" = "bc" ]; then - - entry=$(cat -- "$dir/radamsa.txt" | getentry) - items=$(printf '%s\n' "$entry" | radamsa -n 10) - - printf '%s\n' "$items" - - for i in `seq 1 10`; do - - item=$(printf '%s\n' "$items" | getentry "$i") - - export BC_ENV_ARGS="$item" - echo 'halt' | "$bcdir/$d" - err=$? - - checkcrash "$d" "$err" "radamsa env args: \"$item\"" - done - - fi - - f=$(ls "$inputs" | getentry) - l=$(cat "$inputs/$f" | wc -l) - ll=$(printf '%s^2\n' "$l" | bc) - - # Fuzz on the AFL++ inputs. - for i in $(seq 1 2); do - data=$(cat "$inputs/$f" | radamsa -n 1) - printf '%s\n' "$data" > "$dir/../.log_${d}_test.txt" - printf '%s\n' "$data" | timeout -s SIGTERM 5 "$bcdir/$d" "$opts" > /dev/null - err=$? - checkcrash "$d" "$err" "radamsa stdin" - done - -done diff --git a/contrib/bc/scripts/radamsa.txt b/contrib/bc/scripts/radamsa.txt deleted file mode 100644 index 4bf28907bead..000000000000 --- a/contrib/bc/scripts/radamsa.txt +++ /dev/null @@ -1,17 +0,0 @@ --lq '/home/gavin/.bcrc' --lq "/home/gavin/.bcrc" --lqg '/home/gavin/bc stuff.bc' --lqg "/home/gavin/bc stuff.bc" --lqg '/home/gavin/"bc" stuff.bc' --lqg "/home/gavin/'bc' stuff.bc" --lqg '/home/gavin/bc stuff.bc --lqg "/home/gavin/bc stuff.bc --lqg '/home/gavin/"bc" stuff.bc --lqg "/home/gavin/'bc' stuff.bc ---mathlib --expand ---file="/home/gavin/.bcrc" ---file=/home/gavin/.bcrc ---file="/home/gavin/bc stuff.bc" ---file ---expression "4+4" --e "irand(128)" -f /home/gavin/.bcrc diff --git a/contrib/bc/scripts/randmath.py b/contrib/bc/scripts/randmath.py deleted file mode 100755 index 896f0e46c97f..000000000000 --- a/contrib/bc/scripts/randmath.py +++ /dev/null @@ -1,421 +0,0 @@ -#! /usr/bin/python3 -B -# -# SPDX-License-Identifier: BSD-2-Clause -# -# Copyright (c) 2018-2021 Gavin D. Howard and contributors. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# - -import os, errno -import random -import sys -import subprocess - -# I want line length to *not* affect differences between the two, so I set it -# as high as possible. -env = { - "BC_LINE_LENGTH": "65535", - "DC_LINE_LENGTH": "65535" -} - - -# Generate a random integer between 0 and 2^limit. -# @param limit The power of two for the upper limit. -def gen(limit=4): - return random.randint(0, 2 ** (8 * limit)) - - -# Returns a random boolean for whether a number should be negative or not. -def negative(): - return random.randint(0, 1) == 1 - - -# Returns a random boolean for whether a number should be 0 or not. I decided to -# have it be 0 every 2^4 times since sometimes it is used to make a number less -# than 1. -def zero(): - return random.randint(0, 2 ** (4) - 1) == 0 - - -# Generate a real portion of a number. -def gen_real(): - - # Figure out if we should have a real portion. If so generate it. - if negative(): - n = str(gen(25)) - length = gen(7 / 8) - if len(n) < length: - n = ("0" * (length - len(n))) + n - else: - n = "0" - - return n - - -# Generates a number (as a string) based on the parameters. -# @param op The operation under test. -# @param neg Whether the number can be negative. -# @param real Whether the number can be a non-integer. -# @param z Whether the number can be zero. -# @param limit The power of 2 upper limit for the number. -def num(op, neg, real, z, limit=4): - - # Handle zero first. - if z: - z = zero() - else: - z = False - - if z: - # Generate a real portion maybe - if real: - n = gen_real() - if n != "0": - return "0." + n - return "0" - - # Figure out if we should be negative. - if neg: - neg = negative() - - # Generate the integer portion. - g = gen(limit) - - # Figure out if we should have a real number. negative() is used to give a - # 50/50 chance of getting a negative number. - if real: - n = gen_real() - else: - n = "0" - - # Generate the string. - g = str(g) - if n != "0": - g = g + "." + n - - # Make sure to use the right negative sign. - if neg and g != "0": - if op != modexp: - g = "-" + g - else: - g = "_" + g - - return g - - -# Add a failed test to the list. -# @param test The test that failed. -# @param op The operation for the test. -def add(test, op): - tests.append(test) - gen_ops.append(op) - - -# Compare the output between the two. -# @param exe The executable under test. -# @param options The command-line options. -# @param p The object returned from subprocess.run() for the calculator -# under test. -# @param test The test. -# @param halt The halt string for the calculator under test. -# @param expected The expected result. -# @param op The operation under test. -# @param do_add If true, add a failing test to the list, otherwise, don't. -def compare(exe, options, p, test, halt, expected, op, do_add=True): - - # Check for error from the calculator under test. - if p.returncode != 0: - - print(" {} returned an error ({})".format(exe, p.returncode)) - - if do_add: - print(" adding to checklist...") - add(test, op) - - return - - actual = p.stdout.decode() - - # Check for a difference in output. - if actual != expected: - - if op >= exponent: - - # This is here because GNU bc, like mine can be flaky on the - # functions in the math library. This is basically testing if adding - # 10 to the scale works to make them match. If so, the difference is - # only because of that. - indata = "scale += 10; {}; {}".format(test, halt) - args = [ exe, options ] - p2 = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) - expected = p2.stdout[:-10].decode() - - if actual == expected: - print(" failed because of bug in other {}".format(exe)) - print(" continuing...") - return - - # Do the correct output for the situation. - if do_add: - print(" failed; adding to checklist...") - add(test, op) - else: - print(" failed {}".format(test)) - print(" expected:") - print(" {}".format(expected)) - print(" actual:") - print(" {}".format(actual)) - - -# Generates a test for op. I made sure that there was no clashing between -# calculators. Each calculator is responsible for certain ops. -# @param op The operation to test. -def gen_test(op): - - # First, figure out how big the scale should be. - scale = num(op, False, False, True, 5 / 8) - - # Do the right thing for each op. Generate the test based on the format - # string and the constraints of each op. For example, some ops can't accept - # 0 in some arguments, and some must have integers in some arguments. - if op < div: - s = fmts[op].format(scale, num(op, True, True, True), num(op, True, True, True)) - elif op == div or op == mod: - s = fmts[op].format(scale, num(op, True, True, True), num(op, True, True, False)) - elif op == power: - s = fmts[op].format(scale, num(op, True, True, True, 7 / 8), num(op, True, False, True, 6 / 8)) - elif op == modexp: - s = fmts[op].format(scale, num(op, True, False, True), num(op, True, False, True), - num(op, True, False, False)) - elif op == sqrt: - s = "1" - while s == "1": - s = num(op, False, True, True, 1) - s = fmts[op].format(scale, s) - else: - - if op == exponent: - first = num(op, True, True, True, 6 / 8) - elif op == bessel: - first = num(op, False, True, True, 6 / 8) - else: - first = num(op, True, True, True) - - if op != bessel: - s = fmts[op].format(scale, first) - else: - s = fmts[op].format(scale, first, 6 / 8) - - return s - - -# Runs a test with number t. -# @param t The number of the test. -def run_test(t): - - # Randomly select the operation. - op = random.randrange(bessel + 1) - - # Select the right calculator. - if op != modexp: - exe = "bc" - halt = "halt" - options = "-lq" - else: - exe = "dc" - halt = "q" - options = "" - - # Generate the test. - test = gen_test(op) - - # These don't work very well for some reason. - if "c(0)" in test or "scale = 4; j(4" in test: - return - - # Make sure the calculator will halt. - bcexe = exedir + "/" + exe - indata = test + "\n" + halt - - print("Test {}: {}".format(t, test)) - - # Only bc has options. - if exe == "bc": - args = [ exe, options ] - else: - args = [ exe ] - - # Run the GNU bc. - p = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) - - output1 = p.stdout.decode() - - # Error checking for GNU. - if p.returncode != 0 or output1 == "": - print(" other {} returned an error ({}); continuing...".format(exe, p.returncode)) - return - - if output1 == "\n": - print(" other {} has a bug; continuing...".format(exe)) - return - - # Don't know why GNU has this problem... - if output1 == "-0\n": - output1 = "0\n" - elif output1 == "-0": - output1 = "0" - - args = [ bcexe, options ] - - # Run this bc/dc and compare. - p = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) - compare(exe, options, p, test, halt, output1, op) - - -# This script must be run by itself. -if __name__ != "__main__": - sys.exit(1) - -script = sys.argv[0] -testdir = os.path.dirname(script) - -exedir = testdir + "/../bin" - -# The following are tables used to generate numbers. - -# The operations to test. -ops = [ '+', '-', '*', '/', '%', '^', '|' ] - -# The functions that can be tested. -funcs = [ "sqrt", "e", "l", "a", "s", "c", "j" ] - -# The files (corresponding to the operations with the functions appended) to add -# tests to if they fail. -files = [ "add", "subtract", "multiply", "divide", "modulus", "power", "modexp", - "sqrt", "exponent", "log", "arctangent", "sine", "cosine", "bessel" ] - -# The format strings corresponding to each operation and then each function. -fmts = [ "scale = {}; {} + {}", "scale = {}; {} - {}", "scale = {}; {} * {}", - "scale = {}; {} / {}", "scale = {}; {} % {}", "scale = {}; {} ^ {}", - "{}k {} {} {}|pR", "scale = {}; sqrt({})", "scale = {}; e({})", - "scale = {}; l({})", "scale = {}; a({})", "scale = {}; s({})", - "scale = {}; c({})", "scale = {}; j({}, {})" ] - -# Constants to make some code easier later. -div = 3 -mod = 4 -power = 5 -modexp = 6 -sqrt = 7 -exponent = 8 -bessel = 13 - -gen_ops = [] -tests = [] - -# Infinite loop until the user sends SIGINT. -try: - i = 0 - while True: - run_test(i) - i = i + 1 -except KeyboardInterrupt: - pass - -# This is where we start processing the checklist of possible failures. Why only -# possible failures? Because some operations, specifically the functions in the -# math library, are not guaranteed to be exactly correct. Because of that, we -# need to present every failed test to the user for a final check before we -# add them as test cases. - -# No items, just exit. -if len(tests) == 0: - print("\nNo items in checklist.") - print("Exiting") - sys.exit(0) - -print("\nGoing through the checklist...\n") - -# Just do some error checking. If this fails here, it's a bug in this script. -if len(tests) != len(gen_ops): - print("Corrupted checklist!") - print("Exiting...") - sys.exit(1) - -# Go through each item in the checklist. -for i in range(0, len(tests)): - - # Yes, there's some code duplication. Sue me. - - print("\n{}".format(tests[i])) - - op = int(gen_ops[i]) - - if op != modexp: - exe = "bc" - halt = "halt" - options = "-lq" - else: - exe = "dc" - halt = "q" - options = "" - - # We want to run the test again to show the user the difference. - indata = tests[i] + "\n" + halt - - args = [ exe, options ] - - p = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) - - expected = p.stdout.decode() - - bcexe = exedir + "/" + exe - args = [ bcexe, options ] - - p = subprocess.run(args, input=indata.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) - - compare(exe, options, p, tests[i], halt, expected, op, False) - - # Ask the user to make a decision on the failed test. - answer = input("\nAdd test ({}/{}) to test suite? [y/N]: ".format(i + 1, len(tests))) - - # Quick and dirty answer parsing. - if 'Y' in answer or 'y' in answer: - - print("Yes") - - name = testdir + "/" + exe + "/" + files[op] - - # Write the test to the test file and the expected result to the - # results file. - with open(name + ".txt", "a") as f: - f.write(tests[i] + "\n") - - with open(name + "_results.txt", "a") as f: - f.write(expected) - - else: - print("No") - -print("Done!") diff --git a/contrib/bc/scripts/release.pkg.yao b/contrib/bc/scripts/release.pkg.yao new file mode 100644 index 000000000000..525709c28164 --- /dev/null +++ b/contrib/bc/scripts/release.pkg.yao @@ -0,0 +1,1410 @@ +/** + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2018-2025 Gavin D. Howard and contributors. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +PROG: str = path.realpath(sys.program); +REAL: str = path.realpath(PROG +~ ".."); + +SCRIPTDIR: str = path.dirname(PROG); + +WINDOWS: bool = (host.os == "Windows"); + +DEFOPT: str = if WINDOWS { "/D"; } else { "-D"; }; +C11OPT: str = if WINDOWS { "/std:c11"; } else { "-std=c11"; }; +C99OPT: str = if WINDOWS { "/std:c99"; } else { "-std=c99"; }; + +/** + * Turns a string array into a string by joining all strings together with + * spaces. + * @param arr The array to join. + * @return The joined array. + */ +fn strv2str(arr: []str) -> str +{ + ret: !str = ""; + + for item: arr + { + if ret == "" + { + ret! = item; + } + else + { + ret! = ret +~ " " +~ item; + } + } + + return ret; +} + +opts: Gaml = @(gaml){ + help: [ + "Runs the testing part of the release process.\n" + "\n" + "Usage: ", $PROG, " [-h|--help] [<options> \n" + ] + options: { + no64: { + help: "Turn off building and testing 64-bit builds." + long: @no-64 + type: @NONE + } + no128: { + help: "Turn off building and testing builds with 128-bit integers." + long: @no-128 + type: @NONE + } + C: { + help: "Turn off building under Clang." + short: @C + long: @no-clang + type: @NONE + } + C11: { + help: "Turn off building under C11." + long: @no-c11 + type: @NONE + } + G: { + help: "Turn off building under GCC." + short: @G + long: @no-gcc + type: @NONE + } + GEN: { + help: "Turn off running the gen script." + short: @G + long: @no-gen-script + type: @NONE + } + MAKE: { + help: "Turn off running the build with `configure.sh` and `make`." + long: @no-make + type: @NONE + } + RIG: { + help: "Turn off running the build with Rig." + long: @no-rig + type: @NONE + } + T: { + help: "Turn off running tests." + short: @T + long: @no-tests + type: @NONE + } + computed-goto: { + help: "Whether to test with computed goto or not." + long: @computed-goto + type: @NONE + } + e: { + help: "Whether to test with editline or not." + short: @e + long: @editline + type: @NONE + } + g: { + help: "Whether generate tests that are generated or not." + short: @g + long: @generate + type: @NONE + } + history: { + help: "Whether to test with history or not." + long: @history + type: @NONE + } + k: { + help: "Whether to run the Karatsuba tests or not." + short: @k + long: @karatsuba + type: @NONE + } + p: { + help: "Whether to run problematic tests or not." + short: @p + long: @problematic-tests + type: @NONE + } + r: { + help: "Whether to test with readline or not." + short: @r + long: @readline + type: @NONE + } + s: { + help: "Whether to run tests under sanitizers or not." + short: @s + long: @sanitizers + type: @NONE + } + settings: { + help: "Whether to test settings or not." + long: @settings + type: @NONE + } + v: { + help: "Whether to run under Valgrind or not." + short: @v + long: @valgrind + type: @NONE + } + } +}; + +// These are the booleans for the command-line flags. +no64: !bool = false; +no128: !bool = false; +clang: !bool = true; +c11: !bool = true; +gcc: !bool = true; +gen_host: !bool = true; +run_make: !bool = !WINDOWS; +run_rig: !bool = true; +tests: !bool = true; +computed_goto: !bool = false; +editline: !bool = false; +generated: !bool = false; +history: !bool = false; +karatsuba: !bool = false; +problematic: !bool = false; +readline: !bool = false; +sanitizers: !bool = false; +settings: !bool = false; +valgrind: !bool = false; + +defcc: str = if clang { "clang"; } else if gcc { "gcc"; } else { "c99"; }; +defbits: usize = if no64 { usize(32); } else { usize(64); }; + +cgoto_flags: []str = if !computed_goto { @[ "-DBC_NO_COMPUTED_GOTO" ]; }; + +// Set some strict warning flags. Clang's -Weverything can be way too strict, so +// we actually have to turn off some things. +CLANG_FLAGS: []str = @[ "-Weverything", "-Wno-padded", + "-Wno-unsafe-buffer-usage", + "-Wno-poison-system-directories", + "-Wno-switch-default", "-Wno-unknown-warning-option", + "-Wno-pre-c11-compat" ] +~ cgoto_flags; +GCC_FLAGS: []str = @[ "-Wno-clobbered" ] +~ cgoto_flags; + +CLANG_FLAGS_STR: str = strv2str(CLANG_FLAGS); + +GCC_FLAGS_STR: str = strv2str(GCC_FLAGS); + +// Common CFLAGS. +CFLAGS: []str = @[ "-Wall", "-Wextra", "-Werror", "-pedantic" ]; + +CFLAGS_STR: str = strv2str(CFLAGS); + +// Common debug and release flags. +DEBUG_CFLAGS: []str = CFLAGS +~ @[ "-fno-omit-frame-pointer" ]; +DEBUG_CFLAGS_STR: str = CFLAGS_STR +~ " -fno-omit-frame-pointer"; +RELEASE_CFLAGS: []str = CFLAGS +~ @[ "-DNDEBUG" ]; +RELEASE_CFLAGS_STR: str = CFLAGS_STR +~ " -DNDEBUG"; + +/** + * Print a header with a message. This is just to make it easy to track + * progress. + * @param msg The message to print in the header. + */ +fn header(msg: str) -> void +{ + io.eprint("\n*******************\n"); + io.eprint(msg); + io.eprint("\n*******************\n\n"); +} + +/** + * An easy way to call `make`. + * @param args The arguments to pass to `make`, if any. + */ +fn do_make(args: []str) -> void +{ + $ make -j64 %(args); +} + +/** + * An easy way to call Rig. + * @param args The arguments to pass to Rig, if any. + */ +fn do_rig(args: []str) -> void +{ + $ rig -j64 %(args); +} + +/** + * Runs `configure.sh`. + * @param cflags The C compiler flags. + * @param cc The C compiler. + * @param flags The flags to pass to `configure.sh` itself. + * @param gen The setting for `GEN_HOST`. + * @param long_bit The number of bits in longs. + */ +fn configure( + cflags: str, + cc: str, + flags: str, + gen: bool, + long_bit: usize +) -> void +{ + if !run_make + { + sys.panic("Cannot run `configure.sh` or make"); + } + + extra_flags: str = + if !generated + { + if !problematic { "-GP"; } else { "-G"; } + } + else if !problematic + { + "-P"; + }; + + extra_cflags: str = + if cc == "clang" + { + // We need to quiet this warning from Clang because the configure.sh + // docs have this warning, so people should know. Also, I want this + // script to work. + CLANG_FLAGS_STR +~ (if !gen_host { " -Wno-overlength-strings"; }); + } + else if cc == "gcc" + { + // We need to quiet this warning from GCC because the configure.sh docs + // have this warning, so people should know. Also, I want this script to + // work. + GCC_FLAGS_STR +~ (if !gen_host { "-Wno-overlength-strings"; }); + }; + + all_flags: str = flags +~ " " +~ extra_flags; + all_cflags: str = cflags +~ " " +~ extra_cflags; + + hdr := "Running configure.sh " +~ all_flags +~ + "..." +~ + "\n CC=\"" +~ cc +~ "\"\n" +~ + "\n CFLAGS=\"" +~ all_cflags +~ "\"\n" +~ + "\n LONG_BIT=" +~ str(long_bit) +~ + "\n GEN_HOST=" +~ str(gen); + + // Print the header and do the job. + header(hdr); + + env.set env.str("CFLAGS", str(cflags +~ extra_cflags)), + env.str("CC", cc), env.str("GEN_HOST", str(gen)), + env.str("LONG_BIT", str(long_bit)) + { + $ @(path.join(REAL, "configure.sh")) $flags $extra_flags > /dev/null + !> /dev/null; + } +} + +/** + * Build with `make`. This function also captures and outputs any warnings if + * they exist because as far as I am concerned, warnings are not acceptable for + * release. + * @param cflags The C compiler flags. + * @param cc The C compiler. + * @param flags The flags to pass to `configure.sh` itself. + * @param gen The setting for `GEN_HOST`. + * @param long_bit The number of bits in longs. + */ +fn build_make( + cflags: str, + cc: str, + flags: str, + gen: bool, + long_bit: usize +) -> void +{ + if !run_make + { + sys.panic("Cannot run `configure.sh` or make"); + } + + configure(cflags, cc, flags, gen, long_bit); + + hdr := "Building with `make`...\n CC=" +~ cc +~ + "\n CFLAGS=\"" +~ cflags +~ + "\n LONG_BIT=" +~ str(long_bit) +~ + "\n GEN_HOST=" +~ str(gen); + + header(hdr); + + res := $ make; + + if res.stderr.len != 0 + { + io.eprint(cc +~ "generated warning(s):\n\n"); + io.eprint(str(res.stderr)); + sys.exit(1); + } + + if res.exitcode != 0 + { + sys.exit(res.exitcode); + } +} + +/** + * Build with Rig. This function also captures and outputs any warnings if they + * exist because as far as I am concerned, warnings are not acceptable for + * release. + * @param cflags The C compiler flags. + * @param cc The C compiler. + * @param flags The flags to pass to `configure.sh` itself. + * @param long_bit The number of bits in longs. + */ +fn build_rig( + cflags: []str, + cc: str, + flags: []str, + long_bit: usize +) -> void +{ + if !run_rig + { + sys.panic("Cannot run Rig"); + } + + cflags_str: str = strv2str(cflags); + + hdr := "Building with Rig...\n CC=" +~ cc +~ + "\n CFLAGS=\"" +~ cflags_str +~ + "\n LONG_BIT=" +~ str(long_bit); + + header(hdr); + + res := $ rig; + + if res.stderr.len != 0 + { + io.eprint(cc +~ "generated warning(s):\n\n"); + io.eprint(str(res.stderr)); + sys.exit(1); + } + + if res.exitcode != 0 + { + sys.exit(res.exitcode); + } +} + +/** + * Run tests with `make`. + * @param args Any arguments to pass to `make`, if any. + */ +fn run_test_make(args: []str) -> void +{ + if !run_make + { + sys.panic("Cannot run `configure.sh` or make"); + } + + header("Running `make` tests"); + + if args.len > 0 + { + do_make(args); + } + else + { + do_make(@[ "test" ]); + + if history + { + do_make(@[ "test_history" ]); + } + } +} + +/** + * Run tests with Rig. + * @param args Any arguments to pass to Rig, if any. + */ +fn run_test_rig(args: []str) -> void +{ + if !run_rig + { + sys.panic("Cannot run Rig"); + } + + header("Running Rig tests"); + + if args.len > 0 + { + do_rig(args); + } + else + { + do_rig(@[ "test" ]); + + if history + { + do_rig(@[ "test_history" ]); + } + } +} + +/** + * Builds and runs tests using `make` with both calculators, then bc only, then + * dc only. If `tests` is false, then it just does the builds. + * @param cflags The C compiler flags. + * @param cc The C compiler. + * @param flags The flags to pass to `configure.sh` itself. + * @param gen The setting for `GEN_HOST`. + * @param long_bit The number of bits in longs. + */ +fn run_config_tests_make( + cflags: str, + cc: str, + flags: str, + gen: bool, + long_bit: usize, +) -> void +{ + if !run_make + { + sys.panic("Cannot run `configure.sh` or make"); + } + + header_start: str = + if tests + { + "Running tests with configure flags and `make`"; + } + else + { + "Building with configure flags and `make`"; + }; + + header("\"" +~ header_start +~ "\" ...\n" +~ + " CC=" +~ cc +~ "\n" +~ + " CFLAGS=\"" +~ cflags +~ "\"\n" +~ + " LONG_BIT=" +~ str(long_bit) +~ "\n" +~ + " GEN_HOST=" +~ str(gen)); + + build_make(cflags, cc, flags, gen, long_bit); + + if tests + { + run_test_make(@[]); + } + + do_make(@[ "clean" ]); + + build_make(cflags, cc, flags +~ " -b", gen, long_bit); + + if tests + { + run_test_make(@[]); + } + + do_make(@[ "clean" ]); + + build_make(cflags, cc, flags +~ " -d", gen, long_bit); + + if tests + { + run_test_make(@[]); + } + + do_make(@[ "clean" ]); +} + +/** + * Builds and runs tests using Rig with both calculators, then bc only, then dc + * only. If `tests` is false, then it just does the builds. + * @param cflags The C compiler flags. + * @param cc The C compiler. + * @param flags The flags to pass to Rig itself. + * @param long_bit The number of bits in longs. + */ +fn run_config_tests_rig( + cflags: []str, + cc: str, + flags: []str, + long_bit: usize, +) -> void +{ + if !run_rig + { + sys.panic("Cannot run Rig"); + } + + header_start: str = + if tests + { + "Running tests with Rig"; + } + else + { + "Building with Rig"; + }; + + header("\"" +~ header_start +~ "\" ...\n" +~ + " CC=" +~ cc +~ "\n" +~ + " CFLAGS=\"" +~ strv2str(cflags) +~ "\"\n" +~ + " flags=\"" +~ strv2str(flags) +~ "\"\n" +~ + " LONG_BIT=" +~ str(long_bit)); + + build_rig(cflags, cc, flags, long_bit); + + if tests + { + run_test_rig(@[]); + } + + do_rig(@[ "clean" ]); + + build_rig(cflags, cc, flags +~ @[ "-Dbuild_mode=bc" ], long_bit); + + if tests + { + run_test_rig(@[]); + } + + do_rig(@[ "clean" ]); + + build_rig(cflags, cc, flags +~ @[ "-Dbuild_mode=dc" ], long_bit); + + if tests + { + run_test_rig(@[]); + } + + do_rig(@[ "clean" ]); +} + +/** + * Builds and runs tests using `run_config_tests_make()` with both calculators, + * then bc only, then dc only. If `tests` is false, then it just does the + * builds. + * @param cflags The C compiler flags. + * @param cc The C compiler. + * @param flags The flags to pass to `configure.sh` itself. + */ +fn run_config_series_make( + cflags: str, + cc: str, + flags: str, +) -> void +{ + if !run_make + { + sys.panic("Cannot run `configure.sh` or make"); + } + + if !no64 + { + if !no128 + { + run_config_tests_make(cflags, cc, flags, true, usize(64)); + } + + if gen_host + { + run_config_tests_make(cflags, cc, flags, false, usize(64)); + } + + run_config_tests_make(cflags +~ " " +~ DEFOPT +~ "BC_RAND_BUILTIN=0", + cc, flags, true, usize(64)); + + // Test Editline if history is not turned off. + if editline && !(flags contains "H") + { + run_config_tests_make(cflags +~ " " +~ DEFOPT +~ + "BC_RAND_BUILTIN=0", + cc, flags +~ " -e", true, usize(64)); + } + + // Test Readline if history is not turned off. + if readline && !(flags contains "H") + { + run_config_tests_make(cflags +~ " " +~ DEFOPT +~ + "BC_RAND_BUILTIN=0", + cc, flags +~ " -r", true, usize(64)); + } + } + + run_config_tests_make(cflags, cc, flags, true, usize(32)); + + if gen_host + { + run_config_tests_make(cflags, cc, flags, false, usize(32)); + } +} + +/** + * Builds and runs tests using `run_config_tests_rig()` with both calculators, + * then bc only, then dc only. If `tests` is false, then it just does the + * builds. + * @param cflags The C compiler flags. + * @param cc The C compiler. + * @param flags The flags to pass to Rig itself. + */ +fn run_config_series_rig( + cflags: []str, + cc: str, + flags: []str, +) -> void +{ + if !run_rig + { + sys.panic("Cannot run Rig"); + } + + if !no64 + { + if !no128 + { + run_config_tests_rig(cflags, cc, flags, usize(64)); + } + + run_config_tests_rig(cflags +~ @[ DEFOPT +~ "BC_RAND_BUILTIN=0" ], cc, + flags, usize(64)); + + // Test Editline if history is not turned off. + if editline && !(flags contains "-Dhistory=none") + { + run_config_tests_rig(cflags +~ @[ DEFOPT +~ "BC_RAND_BUILTIN=0" ], + cc, flags +~ @[ "-Dhistory=editline" ], + usize(64)); + } + + // Test Readline if history is not turned off. + if readline && !(flags contains "-Dhistory=none") + { + run_config_tests_rig(cflags +~ @[ DEFOPT +~ "BC_RAND_BUILTIN=0" ], + cc, flags +~ @[ "-Dhistory=readline" ], + usize(64)); + } + } + + run_config_tests_rig(cflags, cc, flags, usize(32)); +} + +/** + * Builds and runs tests with each setting combo running + * `run_config_series_make()`. If `tests` is false, it just does the builds. + * @param cflags The C compiler flags. + * @param cc The C compiler. + * @param flags The flags to pass to `configure.sh` itself. + */ +fn run_settings_series_make( + cflags: str, + cc: str, + flags: str, +) -> void +{ + if !run_make + { + sys.panic("Cannot run `configure.sh` or make"); + } + + if settings + { + settings_path: str = path.join(SCRIPTDIR, "release_settings_make.txt"); + settings_txt: str = io.read_file(settings_path); + lines: []str = settings_txt.split("\n"); + + for line: lines + { + run_config_series_make(cflags, cc, flags +~ " " +~ line); + } + } + else + { + run_config_series_make(cflags, cc, flags); + } +} + +/** + * Builds and runs tests with each setting combo running + * `run_config_series_rig()`. If `tests` is false, it just does the builds. + * @param cflags The C compiler flags. + * @param cc The C compiler. + * @param flags The flags to pass to Rig itself. + */ +fn run_settings_series_rig( + cflags: []str, + cc: str, + flags: []str, +) -> void +{ + if !run_rig + { + sys.panic("Cannot run Rig"); + } + + if settings + { + settings_path: str = path.join(SCRIPTDIR, "release_settings_rig.txt"); + settings_txt: str = io.read_file(settings_path); + lines: []str = settings_txt.split("\n"); + + for line: lines + { + opts_list: []str = + for opt: line.split(" ") + { + DEFOPT +~ opt; + }; + + run_config_series_rig(cflags, cc, flags +~ opts_list); + } + } + else + { + run_config_series_rig(cflags, cc, flags); + } +} + +/** + * Builds and runs tests with each build type running + * `run_settings_series_make()`. If `tests` is false, it just does the builds. + * @param cflags The C compiler flags. + * @param cc The C compiler. + * @param flags The flags to pass to `configure.sh` itself. + */ +fn run_test_series_make( + cflags: str, + cc: str, + flags: str, +) -> void +{ + if !run_make + { + sys.panic("Cannot run `configure.sh` or make"); + } + + series_flags: []str = @[ "E", "H", "N", "EH", "EN", "HN", "EHN" ]; + + run_settings_series_make(cflags, cc, flags); + + for sflag: series_flags + { + run_settings_series_make(cflags, cc, flags +~ " -" +~ sflag); + } +} + +/** + * Builds and runs tests with each build type running + * `run_settings_series_rig()`. If `tests` is false, it just does the builds. + * @param cflags The C compiler flags. + * @param cc The C compiler. + * @param flags The flags to pass to Rig itself. + */ +fn run_test_series_rig( + cflags: []str, + cc: str, + flags: []str, +) -> void +{ + if !run_rig + { + sys.panic("Cannot run Rig"); + } + + series_path: str = path.join(SCRIPTDIR, "release_flags_rig.txt"); + series_txt: str = io.read_file(series_path); + series_flags: []str = series_txt.split("\n"); + + run_settings_series_rig(cflags, cc, flags); + + for line: series_flags + { + opts_list: []str = + for opt: line.split(" ") + { + DEFOPT +~ opt; + }; + + run_settings_series_rig(cflags, cc, flags +~ opts_list); + } +} + +/** + * Builds and runs tests for `bcl` with `make`. If `tests` is false, it just + * does the builds. + * @param cflags The C compiler flags. + * @param cc The C compiler. + * @param flags The flags to pass to `configure.sh` itself. + */ +fn run_lib_tests_make( + cflags: str, + cc: str, + flags: str, +) -> void +{ + if !run_make + { + sys.panic("Cannot run `configure.sh` or make"); + } + + build_make(cflags +~ " -a", cc, flags, true, usize(64)); + + if tests + { + run_test_make(@[ "test" ]); + } + + build_make(cflags +~ " -a", cc, flags, true, usize(32)); + + if tests + { + run_test_make(@[ "test" ]); + } +} + +/** + * Builds and runs tests for `bcl` with Rig. If `tests` is false, it just does + * the builds. + * @param cflags The C compiler flags. + * @param cc The C compiler. + * @param flags The flags to pass to Rig itself. + */ +fn run_lib_tests_rig( + cflags: []str, + cc: str, + flags: []str, +) -> void +{ + if !run_rig + { + sys.panic("Cannot run Rig"); + } + + build_rig(cflags, cc, flags +~ @[ "-Dbuild_mode=library" ], usize(64)); + + if tests + { + run_test_rig(@[ "test" ]); + } + + build_rig(cflags, cc, flags +~ @[ "-Dbuild_mode=library" ], usize(32)); + + if tests + { + run_test_rig(@[ "test" ]); + } +} + +/** + * Builds and runs tests under C99, then C11, if requested, using + * `run_test_series_make()`. If run_tests is false, it just does the builds. + * @param cflags The C compiler flags. + * @param cc The C compiler. + * @param flags The flags to pass to Rig itself. + */ +fn run_tests_make( + cflags: str, + cc: str, + flags: str, +) -> void +{ + if !run_make + { + sys.panic("Cannot run `configure.sh` or make"); + } + + run_test_series_make(cflags +~ " " +~ C99OPT, cc, flags); + + if c11 + { + run_test_series_make(cflags +~ " " +~ C11OPT, cc, flags); + } +} + +/** + * Builds and runs tests under C99, then C11, if requested, using + * `run_test_series_rig()`. If run_tests is false, it just does the builds. + * @param cflags The C compiler flags. + * @param cc The C compiler. + * @param flags The flags to pass to Rig itself. + */ +fn run_tests_rig( + cflags: []str, + cc: str, + flags: []str, +) -> void +{ + if !run_rig + { + sys.panic("Cannot run Rig"); + } + + run_test_series_rig(cflags +~ @[ C99OPT ], cc, flags); + + if c11 + { + run_test_series_rig(cflags +~ @[ C11OPT ], cc, flags); + } +} + +/** + * Runs the Karatsuba tests with `make`. + */ +fn karatsuba_make() -> void +{ + if !run_make + { + sys.panic("Cannot run `configure.sh` or make"); + } + + header("Running Karatsuba tests"); + + do_make(@[ "karatsuba_test" ]); +} + +/** + * Runs the Karatsuba tests with Rig. + */ +fn karatsuba_rig() -> void +{ + if !run_rig + { + sys.panic("Cannot run Rig"); + } + + header("Running Karatsuba tests"); + + build_rig(RELEASE_CFLAGS, defcc, @[ "-O3" ], usize(64)); + + do_rig(@[ "karatsuba_test" ]); +} + +/** + * Builds with `make` and runs under valgrind. It runs both, bc only, then dc + * only, then the library. + */ +fn vg_make() -> void +{ + if !run_make + { + sys.panic("Cannot run `configure.sh` or make"); + } + + header("Running Valgrind under `make`"); + + build_make(DEBUG_CFLAGS_STR +~ " -std=c99", "gcc", "-O3 -gv", true, + defbits); + run_test_make(@[ "test" ]); + + do_make(@[ "clean_config" ]); + + build_make(DEBUG_CFLAGS_STR +~ " -std=c99", "gcc", "-O3 -gvb", true, + defbits); + run_test_make(@[ "test" ]); + + do_make(@[ "clean_config" ]); + + build_make(DEBUG_CFLAGS_STR +~ " -std=c99", "gcc", "-O3 -gvd", true, + defbits); + run_test_make(@[ "test" ]); + + do_make(@[ "clean_config" ]); + + build_make(DEBUG_CFLAGS_STR +~ " -std=c99", "gcc", "-O3 -gva", true, + defbits); + run_test_make(@[ "test" ]); + + do_make(@[ "clean_config" ]); +} + +fn vg_rig() -> void +{ + if !run_rig + { + sys.panic("Cannot run Rig"); + } + + header("Running Valgrind under Rig"); + + build_rig(DEBUG_CFLAGS +~ @[ "-std=c99" ], "gcc", @[ "-O3", "-gv" ], + defbits); + run_test_rig(@[ "test" ]); + + do_rig(@[ "clean_config" ]); + + build_rig(DEBUG_CFLAGS +~ @[ "-std=c99" ], "gcc", @[ "-O3", "-gvb" ], + defbits); + run_test_rig(@[ "test" ]); + + do_rig(@[ "clean_config" ]); + + build_rig(DEBUG_CFLAGS +~ @[ "-std=c99" ], "gcc", @[ "-O3", "-gvd" ], + defbits); + run_test_rig(@[ "test" ]); + + do_rig(@[ "clean_config" ]); + + build_rig(DEBUG_CFLAGS +~ @[ "-std=c99" ], "gcc", @[ "-O3", "-gva" ], + defbits); + run_test_rig(@[ "test" ]); + + do_rig(@[ "clean_config" ]); +} + +/** + * Builds the debug series with `make` and runs the tests if `tests` allows. + * @param cc The C compiler. + */ +fn debug_make( + cc: str, +) -> void +{ + if !run_make + { + sys.panic("Cannot run `configure.sh` or make"); + } + + if cc == "clang" && sanitizers + { + run_tests_make(DEBUG_CFLAGS_STR +~ " -fsanitize=undefined", cc, "-mg"); + } + else + { + run_tests_make(DEBUG_CFLAGS_STR, cc, "-g"); + } +} + +/** + * Builds the release series with `make` and runs the tests if `tests` allows. + * @param cc The C compiler. + */ +fn release_make( + cc: str, +) -> void +{ + if !run_make + { + sys.panic("Cannot run `configure.sh` or make"); + } + + run_tests_make(RELEASE_CFLAGS_STR, cc, "-O3"); + run_lib_tests_make(RELEASE_CFLAGS_STR, cc, "-O3"); +} + +/** + * Builds the release debug series with `make` and runs the tests if `tests` + * allows. + * @param cc The C compiler. + */ +fn reldebug_make( + cc: str, +) -> void +{ + if !run_make + { + sys.panic("Cannot run `configure.sh` or make"); + } + + if cc == "clang" && sanitizers + { + run_tests_make(DEBUG_CFLAGS_STR +~ " -fsanitize=address", cc, "-mgO3"); + run_tests_make(DEBUG_CFLAGS_STR +~ " -fsanitize=memory", cc, "-mgO3"); + } + else + { + run_tests_make(DEBUG_CFLAGS_STR, cc, "-gO3"); + } + + if cc == "clang" && sanitizers + { + run_lib_tests_make(DEBUG_CFLAGS_STR +~ " -fsanitize=address", cc, + "-mgO3"); + run_lib_tests_make(DEBUG_CFLAGS_STR +~ " -fsanitize=memory", cc, + "-mgO3"); + } + else + { + run_lib_tests_make(DEBUG_CFLAGS_STR, cc, "-gO3"); + } +} + +/** + * Builds the min size release with `make` and runs the tests if `tests` allows. + * @param cc The C compiler. + */ +fn minsize_make( + cc: str, +) -> void +{ + if !run_make + { + sys.panic("Cannot run `configure.sh` or make"); + } + + run_tests_make(RELEASE_CFLAGS_STR, cc, "-Os"); + run_lib_tests_make(RELEASE_CFLAGS_STR, cc, "-Os"); +} + +/** + * Builds all sets with `make`: debug, release, release debug, and min size, and + * runs the tests if `tests` allows. + * @param cc The C compiler. + */ +fn build_set_make( + cc: str, +) -> void +{ + if !run_make + { + sys.panic("Cannot run `configure.sh` or make"); + } + + debug_make(cc); + release_make(cc); + reldebug_make(cc); + minsize_make(cc); + + if karatsuba + { + karatsuba_make(); + } + + if valgrind + { + vg_make(); + } +} + +/** + * Builds the debug series with Rig and runs the tests if `tests` allows. + * @param cc The C compiler. + */ +fn debug_rig( + cc: str, +) -> void +{ + if !run_rig + { + sys.panic("Cannot run Rig"); + } + + if cc == "clang" && sanitizers + { + run_tests_rig(DEBUG_CFLAGS +~ @[ " -fsanitize=undefined" ], cc, + @[ "-Dmemcheck=1", "-Ddebug=1" ]); + } + else + { + run_tests_rig(DEBUG_CFLAGS, cc, @[ "-Ddebug=1" ]); + } +} + +/** + * Builds the release series with Rig and runs the tests if `tests` allows. + * @param cc The C compiler. + */ +fn release_rig( + cc: str, +) -> void +{ + if !run_rig + { + sys.panic("Cannot run Rig"); + } + + run_tests_rig(RELEASE_CFLAGS, cc, @[ "-Doptimization=3" ]); + run_lib_tests_rig(RELEASE_CFLAGS, cc, @[ "-Doptimization=3" ]); +} + +/** + * Builds the release debug series with Rig and runs the tests if `tests` + * allows. + * @param cc The C compiler. + */ +fn reldebug_rig( + cc: str, +) -> void +{ + if !run_rig + { + sys.panic("Cannot run Rig"); + } + + if cc == "clang" && sanitizers + { + run_tests_rig(DEBUG_CFLAGS +~ @[ " -fsanitize=address" ], cc, + @[ "-Dmemcheck=1", "-Ddebug=1", "-Doptimization=3" ]); + run_tests_rig(DEBUG_CFLAGS +~ @[ " -fsanitize=memory" ], cc, + @[ "-Dmemcheck=1", "-Ddebug=1", "-Doptimization=3" ]); + } + else + { + run_tests_rig(DEBUG_CFLAGS, cc, @[ "-gO3" ]); + } + + if cc == "clang" && sanitizers + { + run_lib_tests_rig(DEBUG_CFLAGS +~ @[ " -fsanitize=address" ], cc, + @[ "-Dmemcheck=1", "-Ddebug=1", "-Doptimization=3" ]); + run_lib_tests_rig(DEBUG_CFLAGS +~ @[ " -fsanitize=memory" ], cc, + @[ "-Dmemcheck=1", "-Ddebug=1", "-Doptimization=3" ]); + } + else + { + run_lib_tests_rig(DEBUG_CFLAGS, cc, + @[ "-Ddebug=1", "-Doptimization=3" ]); + } +} + +/** + * Builds the min size release with Rig and runs the tests if `tests` allows. + * @param cc The C compiler. + */ +fn minsize_rig( + cc: str, +) -> void +{ + if !run_rig + { + sys.panic("Cannot run Rig"); + } + + run_tests_rig(RELEASE_CFLAGS, cc, @[ "-Doptimization=s" ]); + run_lib_tests_rig(RELEASE_CFLAGS, cc, @[ "-Doptimization=s" ]); +} + +/** + * Builds all sets with Rig: debug, release, release debug, and min size, and + * runs the tests if `tests` allows. + * @param cc The C compiler. + */ +fn build_set_rig( + cc: str, +) -> void +{ + if !run_rig + { + sys.panic("Cannot run Rig"); + } + + debug_rig(cc); + release_rig(cc); + reldebug_rig(cc); + minsize_rig(cc); + + if karatsuba + { + karatsuba_rig(); + } + + if valgrind + { + vg_rig(); + } +} + +/** + * Builds all sets with `make` under all compilers. + */ +fn build_sets_make() -> void +{ + header("Running math library under --standard with Rig"); + + build_make(DEBUG_CFLAGS_STR +~ " -std=c99", defcc, "-g", true, + defbits); + + $ bin/bc -ls << @("quit\n"); + + do_rig(@[ "clean_tests" ]); + + if clang + { + build_set_make("clang"); + } + + if gcc + { + build_set_make("gcc"); + } +} + +/** + * Builds all sets with Rig under all compilers. + */ +fn build_sets_rig() -> void +{ + header("Running math library under --standard with Rig"); + + build_rig(DEBUG_CFLAGS +~ @[ "-std=c99" ], defcc, @[ "-Ddebug=1" ], + defbits); + + $ build/bc -ls << @("quit\n"); + + do_rig(@[ "clean_tests" ]); + + if clang + { + build_set_rig("clang"); + } + + if gcc + { + build_set_rig("gcc"); + } +} + +fn build_sets() -> void +{ + if !run_make + { + build_sets_rig(); + } + else if !run_rig + { + build_sets_make(); + } + else + { + parallel.map @[ "rig", "make" ]: + (builder: str) -> void + { + if builder == "rig" + { + build_sets_rig(); + } + else if builder == "make" + { + build_sets_make(); + } + else + { + sys.panic("Bad builder: " +~ builder +~ "\n"); + } + } + } + + io.eprint("\nTests successful.\n"); +} diff --git a/contrib/bc/scripts/release.sh b/contrib/bc/scripts/release.sh deleted file mode 100755 index 638161f83732..000000000000 --- a/contrib/bc/scripts/release.sh +++ /dev/null @@ -1,779 +0,0 @@ -#! /bin/sh -# -# SPDX-License-Identifier: BSD-2-Clause -# -# Copyright (c) 2018-2021 Gavin D. Howard and contributors. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# - -# For OpenBSD, run using the following: -# -# scripts/release.sh 1 0 1 0 0 0 0 1 0 0 0 0 -# -# For FreeBSD, run using the following: -# -# scripts/release.sh 1 0 1 0 0 0 0 1 0 1 0 0 -# -# There is one problem with running this script on FreeBSD: it takes overcommit -# to the extreme. This means that some tests that try to create allocation -# failures instead make bc and dc crash. So running this script on FreeBSD does -# not work right now. -# -# For Linux, run two separate ones (in different checkouts), like so: -# -# scripts/release.sh 1 1 1 0 1 0 0 1 0 1 0 1 -# scripts/release.sh 1 1 0 1 0 1 0 1 0 1 0 0 -# -# Yes, I usually do sanitizers with Clang and Valgrind with GCC. -# -# To run sanitizers or Valgrind with generated tests, use the following: -# -# scripts/release.sh 1 1 1 0 1 0 0 1 0 1 0 1 -# scripts/release.sh 1 1 0 1 0 1 0 1 0 1 0 0 -# -# If this script fails on any platform when starting the Karatsuba test, check -# that Python is installed, especially if the error says something like: -# "karatsuba.py: not found". - -# Print the usage and exit with an error. Each parameter should be an integer. -# Non-zero activates, and zero deactivates. -usage() { - printf 'usage: %s [run_tests] [generate_tests] [test_with_clang] [test_with_gcc] \n' "$script" - printf ' [run_sanitizers] [run_valgrind] [test_settings] [run_64_bit] \n' - printf ' [run_gen_script] [test_c11] [test_128_bit] [test_computed_goto]\n' - exit 1 -} - -# Print a header with a message. This is just to make it easy to track progress. -# @param msg The message to print in the header. -header() { - - _header_msg="$1" - shift - - printf '\n' - printf '*******************\n' - printf "$_header_msg" - printf '\n' - printf '*******************\n' - printf '\n' -} - -# Easy way to call make. -do_make() { - # No reason to do 64 except to see if I actually can overload my system. :) - # Well, also that it might actually improve throughput as other jobs can run - # while some are waiting. - make -j64 "$@" -} - -# Run configure.sh. -# @param CFLAGS The CFLAGS. -# @param CC The C compiler. -# @param configure_flags The flags for configure.sh itself. -# @param GEN_HOST The setting for GEN_HOST. -# @param LONG_BIT The setting for LONG_BIT. -configure() { - - _configure_CFLAGS="$1" - shift - - _configure_CC="$1" - shift - - _configure_configure_flags="$1" - shift - - _configure_GEN_HOST="$1" - shift - - _configure_LONG_BIT="$1" - shift - - # Make sure to not generate tests if necessary. - if [ "$gen_tests" -eq 0 ]; then - _configure_configure_flags="-G $_configure_configure_flags" - fi - - # Choose the right extra flags. - if [ "$_configure_CC" = "clang" ]; then - _configure_CFLAGS="$clang_flags $_configure_CFLAGS" - elif [ "$_configure_CC" = "gcc" ]; then - _configure_CFLAGS="$gcc_flags $_configure_CFLAGS" - fi - - # Print the header and do the job. - _configure_header=$(printf 'Running ./configure.sh %s ...' "$_configure_configure_flags") - _configure_header=$(printf "$_configure_header\n CC=\"%s\"\n" "$_configure_CC") - _configure_header=$(printf "$_configure_header\n CFLAGS=\"%s\"\n" "$_configure_CFLAGS") - _configure_header=$(printf "$_configure_header\n LONG_BIT=%s" "$_configure_LONG_BIT") - _configure_header=$(printf "$_configure_header\n GEN_HOST=%s" "$_configure_GEN_HOST") - - header "$_configure_header" - CFLAGS="$_configure_CFLAGS" CC="$_configure_CC" GEN_HOST="$_configure_GEN_HOST" \ - LONG_BIT="$_configure_LONG_BIT" ./configure.sh $_configure_configure_flags > /dev/null -} - -# Build with make. This function also captures and outputs any warnings if they -# exists because as far as I am concerned, warnings are not acceptable for -# release. -# @param CFLAGS The CFLAGS. -# @param CC The C compiler. -# @param configure_flags The flags for configure.sh itself. -# @param GEN_HOST The setting for GEN_HOST. -# @param LONG_BIT The setting for LONG_BIT. -build() { - - _build_CFLAGS="$1" - shift - - _build_CC="$1" - shift - - _build_configure_flags="$1" - shift - - _build_GEN_HOST="$1" - shift - - _build_LONG_BIT="$1" - shift - - configure "$_build_CFLAGS" "$_build_CC" "$_build_configure_flags" "$_build_GEN_HOST" "$_build_LONG_BIT" - - _build_header=$(printf 'Building...\n CC=%s' "$_build_CC") - _build_header=$(printf "$_build_header\n CFLAGS=\"%s\"" "$_build_CFLAGS") - _build_header=$(printf "$_build_header\n LONG_BIT=%s" "$_build_LONG_BIT") - _build_header=$(printf "$_build_header\n GEN_HOST=%s" "$_build_GEN_HOST") - - header "$_build_header" - - # Capture and print warnings. - do_make > /dev/null 2> "$scriptdir/../.test.txt" - - if [ -s "$scriptdir/../.test.txt" ]; then - printf '%s generated warning(s):\n' "$_build_CC" - printf '\n' - cat "$scriptdir/../.test.txt" - exit 1 - fi -} - -# Run tests with make. -runtest() { - - header "Running tests" - - if [ "$#" -gt 0 ]; then - do_make "$@" - else - do_make test - fi -} - -# Builds and runs tests with both calculators, then bc only, then dc only. If -# run_tests is false, then it just does the builds. -# @param CFLAGS The CFLAGS. -# @param CC The C compiler. -# @param configure_flags The flags for configure.sh itself. -# @param GEN_HOST The setting for GEN_HOST. -# @param LONG_BIT The setting for LONG_BIT. -# @param run_tests Whether to run tests or not. -runconfigtests() { - - _runconfigtests_CFLAGS="$1" - shift - - _runconfigtests_CC="$1" - shift - - _runconfigtests_configure_flags="$1" - shift - - _runconfigtests_GEN_HOST="$1" - shift - - _runconfigtests_LONG_BIT="$1" - shift - - _runconfigtests_run_tests="$1" - shift - - if [ "$_runconfigtests_run_tests" -ne 0 ]; then - _runconfigtests_header=$(printf 'Running tests with configure flags') - else - _runconfigtests_header=$(printf 'Building with configure flags') - fi - - _runconfigtests_header=$(printf "$_runconfigtests_header \"%s\" ...\n" "$_runconfigtests_configure_flags") - _runconfigtests_header=$(printf "$_runconfigtests_header\n CC=%s\n" "$_runconfigseries_CC") - _runconfigtests_header=$(printf "$_runconfigtests_header\n CFLAGS=\"%s\"" "$_runconfigseries_CFLAGS") - _runconfigtests_header=$(printf "$_runconfigtests_header\n LONG_BIT=%s" "$_runconfigtests_LONG_BIT") - _runconfigtests_header=$(printf "$_runconfigtests_header\n GEN_HOST=%s" "$_runconfigtests_GEN_HOST") - - header "$_runconfigtests_header" - - build "$_runconfigtests_CFLAGS" "$_runconfigtests_CC" \ - "$_runconfigtests_configure_flags" "$_runconfigtests_GEN_HOST" \ - "$_runconfigtests_LONG_BIT" - - if [ "$_runconfigtests_run_tests" -ne 0 ]; then - runtest - fi - - do_make clean - - build "$_runconfigtests_CFLAGS" "$_runconfigtests_CC" \ - "$_runconfigtests_configure_flags -b" "$_runconfigtests_GEN_HOST" \ - "$_runconfigtests_LONG_BIT" - - if [ "$_runconfigtests_run_tests" -ne 0 ]; then - runtest - fi - - do_make clean - - build "$_runconfigtests_CFLAGS" "$_runconfigtests_CC" \ - "$_runconfigtests_configure_flags -d" "$_runconfigtests_GEN_HOST" \ - "$_runconfigtests_LONG_BIT" - - if [ "$_runconfigtests_run_tests" -ne 0 ]; then - runtest - fi - - do_make clean -} - -# Builds and runs tests with runconfigtests(), but also does 64-bit, 32-bit, and -# 128-bit rand, if requested. It also does it with the gen script (strgen.sh) if -# requested. If run_tests is false, it just does the builds. -# @param CFLAGS The CFLAGS. -# @param CC The C compiler. -# @param configure_flags The flags for configure.sh itself. -# @param run_tests Whether to run tests or not. -runconfigseries() { - - _runconfigseries_CFLAGS="$1" - shift - - _runconfigseries_CC="$1" - shift - - _runconfigseries_configure_flags="$1" - shift - - _runconfigseries_run_tests="$1" - shift - - if [ "$run_64_bit" -ne 0 ]; then - - if [ "$test_128_bit" -ne 0 ]; then - runconfigtests "$_runconfigseries_CFLAGS" "$_runconfigseries_CC" \ - "$_runconfigseries_configure_flags" 1 64 "$_runconfigseries_run_tests" - fi - - if [ "$run_gen_script" -ne 0 ]; then - runconfigtests "$_runconfigseries_CFLAGS" "$_runconfigseries_CC" \ - "$_runconfigseries_configure_flags" 0 64 "$_runconfigseries_run_tests" - fi - - runconfigtests "$_runconfigseries_CFLAGS -DBC_RAND_BUILTIN=0" "$_runconfigseries_CC" \ - "$_runconfigseries_configure_flags" 1 64 "$_runconfigseries_run_tests" - - fi - - runconfigtests "$_runconfigseries_CFLAGS" "$_runconfigseries_CC" \ - "$_runconfigseries_configure_flags" 1 32 "$_runconfigseries_run_tests" - - if [ "$run_gen_script" -ne 0 ]; then - runconfigtests "$_runconfigseries_CFLAGS" "$_runconfigseries_CC" \ - "$_runconfigseries_configure_flags" 0 32 "$_runconfigseries_run_tests" - fi -} - -# Builds and runs tests with each setting combo running runconfigseries(). If -# run_tests is false, it just does the builds. -# @param CFLAGS The CFLAGS. -# @param CC The C compiler. -# @param configure_flags The flags for configure.sh itself. -# @param run_tests Whether to run tests or not. -runsettingsseries() { - - _runsettingsseries_CFLAGS="$1" - shift - - _runsettingsseries_CC="$1" - shift - - _runsettingsseries_configure_flags="$1" - shift - - _runsettingsseries_run_tests="$1" - shift - - if [ "$test_settings" -ne 0 ]; then - - while read _runsettingsseries_s; do - runconfigseries "$_runsettingsseries_CFLAGS" "$_runsettingsseries_CC" \ - "$_runsettingsseries_configure_flags $_runsettingsseries_s" \ - "$_runsettingsseries_run_tests" - done < "$scriptdir/release_settings.txt" - - else - runconfigseries "$_runsettingsseries_CFLAGS" "$_runsettingsseries_CC" \ - "$_runsettingsseries_configure_flags" "$_runsettingsseries_run_tests" - fi -} - -# Builds and runs tests with each build type running runsettingsseries(). If -# run_tests is false, it just does the builds. -# @param CFLAGS The CFLAGS. -# @param CC The C compiler. -# @param configure_flags The flags for configure.sh itself. -# @param run_tests Whether to run tests or not. -runtestseries() { - - _runtestseries_CFLAGS="$1" - shift - - _runtestseries_CC="$1" - shift - - _runtestseries_configure_flags="$1" - shift - - _runtestseries_run_tests="$1" - shift - - _runtestseries_flags="E H N EH EN HN EHN" - - runsettingsseries "$_runtestseries_CFLAGS" "$_runtestseries_CC" \ - "$_runtestseries_configure_flags" "$_runtestseries_run_tests" - - for _runtestseries_f in $_runtestseries_flags; do - runsettingsseries "$_runtestseries_CFLAGS" "$_runtestseries_CC" \ - "$_runtestseries_configure_flags -$_runtestseries_f" "$_runtestseries_run_tests" - done -} - -# Builds and runs the tests for bcl. If run_tests is false, it just does the -# builds. -# @param CFLAGS The CFLAGS. -# @param CC The C compiler. -# @param configure_flags The flags for configure.sh itself. -# @param run_tests Whether to run tests or not. -runlibtests() { - - _runlibtests_CFLAGS="$1" - shift - - _runlibtests_CC="$1" - shift - - _runlibtests_configure_flags="$1" - shift - - _runlibtests_run_tests="$1" - shift - - _runlibtests_configure_flags="$_runlibtests_configure_flags -a" - - build "$_runlibtests_CFLAGS" "$_runlibtests_CC" "$_runlibtests_configure_flags" 1 64 - - if [ "$_runlibtests_run_tests" -ne 0 ]; then - runtest - fi - - build "$_runlibtests_CFLAGS" "$_runlibtests_CC" "$_runlibtests_configure_flags" 1 32 - - if [ "$_runlibtests_run_tests" -ne 0 ]; then - runtest - fi -} - -# Builds and runs tests under C99, then C11, if requested, using -# runtestseries(). If run_tests is false, it just does the builds. -# @param CFLAGS The CFLAGS. -# @param CC The C compiler. -# @param configure_flags The flags for configure.sh itself. -# @param run_tests Whether to run tests or not. -runtests() { - - _runtests_CFLAGS="$1" - shift - - _runtests_CC="$1" - shift - - _runtests_configure_flags="$1" - shift - - _runtests_run_tests="$1" - shift - - runtestseries "-std=c99 $_runtests_CFLAGS" "$_runtests_CC" "$_runtests_configure_flags" "$_runtests_run_tests" - - if [ "$test_c11" -ne 0 ]; then - runtestseries "-std=c11 $_runtests_CFLAGS" "$_runtests_CC" "$_runtests_configure_flags" "$_runtests_run_tests" - fi -} - -# Runs the karatsuba tests. -karatsuba() { - - header "Running Karatsuba tests" - do_make karatsuba_test -} - -# Builds and runs under valgrind. It runs both, bc only, then dc only. -vg() { - - header "Running valgrind" - - if [ "$run_64_bit" -ne 0 ]; then - _vg_bits=64 - else - _vg_bits=32 - fi - - build "$debug -std=c99" "gcc" "-O3 -gv" "1" "$_vg_bits" - runtest test - - do_make clean_config - - build "$debug -std=c99" "gcc" "-O3 -gvb" "1" "$_vg_bits" - runtest test - - do_make clean_config - - build "$debug -std=c99" "gcc" "-O3 -gvd" "1" "$_vg_bits" - runtest test - - do_make clean_config - - build "$debug -std=c99" "gcc" "-O3 -gva" "1" "$_vg_bits" - runtest test - - do_make clean_config -} - -# Builds the debug series and runs the tests if run_tests allows. If sanitizers -# are enabled, it also does UBSan. -# @param CC The C compiler. -# @param run_tests Whether to run tests or not. -debug() { - - _debug_CC="$1" - shift - - _debug_run_tests="$1" - shift - - - if [ "$_debug_CC" = "clang" -a "$run_sanitizers" -ne 0 ]; then - runtests "$debug -fsanitize=undefined" "$_debug_CC" "-gm" "$_debug_run_tests" - else - runtests "$debug" "$_debug_CC" "-g" "$_debug_run_tests" - fi - - - if [ "$_debug_CC" = "clang" -a "$run_sanitizers" -ne 0 ]; then - runlibtests "$debug -fsanitize=undefined" "$_debug_CC" "-gm" "$_debug_run_tests" - else - runlibtests "$debug" "$_debug_CC" "-g" "$_debug_run_tests" - fi -} - -# Builds the release series and runs the test if run_tests allows. -# @param CC The C compiler. -# @param run_tests Whether to run tests or not. -release() { - - _release_CC="$1" - shift - - _release_run_tests="$1" - shift - - runtests "$release" "$_release_CC" "-O3" "$_release_run_tests" - - runlibtests "$release" "$_release_CC" "-O3" "$_release_run_tests" -} - -# Builds the release debug series and runs the test if run_tests allows. If -# sanitizers are enabled, it also does ASan and MSan. -# @param CC The C compiler. -# @param run_tests Whether to run tests or not. -reldebug() { - - _reldebug_CC="$1" - shift - - _reldebug_run_tests="$1" - shift - - - if [ "$_reldebug_CC" = "clang" -a "$run_sanitizers" -ne 0 ]; then - runtests "$debug -fsanitize=address" "$_reldebug_CC" "-mgO3" "$_reldebug_run_tests" - runtests "$debug -fsanitize=memory" "$_reldebug_CC" "-mgO3" "$_reldebug_run_tests" - else - runtests "$debug" "$_reldebug_CC" "-gO3" "$_reldebug_run_tests" - fi - - - if [ "$_reldebug_CC" = "clang" -a "$run_sanitizers" -ne 0 ]; then - runlibtests "$debug -fsanitize=address" "$_reldebug_CC" "-mgO3" "$_reldebug_run_tests" - runlibtests "$debug -fsanitize=memory" "$_reldebug_CC" "-mgO3" "$_reldebug_run_tests" - else - runlibtests "$debug" "$_reldebug_CC" "-gO3" "$_reldebug_run_tests" - fi -} - -# Builds the min size release series and runs the test if run_tests allows. -# @param CC The C compiler. -# @param run_tests Whether to run tests or not. -minsize() { - - _minsize_CC="$1" - shift - - _minsize_run_tests="$1" - shift - - runtests "$release" "$_minsize_CC" "-Os" "$_minsize_run_tests" - - runlibtests "$release" "$_minsize_CC" "-Os" "$_minsize_run_tests" -} - -# Builds all sets: debug, release, release debug, and min size, and runs the -# tests if run_tests allows. -# @param CC The C compiler. -# @param run_tests Whether to run tests or not. -build_set() { - - _build_set_CC="$1" - shift - - _build_set_run_tests="$1" - shift - - debug "$_build_set_CC" "$_build_set_run_tests" - release "$_build_set_CC" "$_build_set_run_tests" - reldebug "$_build_set_CC" "$_build_set_run_tests" - minsize "$_build_set_CC" "$_build_set_run_tests" -} - -# Set some strict warning flags. Clang's -Weverything can be way too strict, so -# we actually have to turn off some things. -clang_flags="-Weverything -Wno-padded -Wno-switch-enum -Wno-format-nonliteral" -clang_flags="$clang_flags -Wno-cast-align -Wno-missing-noreturn -Wno-disabled-macro-expansion" -clang_flags="$clang_flags -Wno-unreachable-code -Wno-unreachable-code-return" -clang_flags="$clang_flags -Wno-implicit-fallthrough -Wno-unused-macros -Wno-gnu-label-as-value" -gcc_flags="-Wno-maybe-uninitialized -Wno-clobbered" - -# Common CFLAGS. -cflags="-Wall -Wextra -Werror -pedantic -Wno-conditional-uninitialized" - -# Common debug and release flags. -debug="$cflags -fno-omit-frame-pointer" -release="$cflags -DNDEBUG" - -set -e - -script="$0" -scriptdir=$(dirname "$script") - -# Whether to run tests. -if [ "$#" -gt 0 ]; then - run_tests="$1" - shift -else - run_tests=1 -fi - -# Whether to generate tests. On platforms like OpenBSD, there is no GNU bc to -# generate tests, so this must be off. -if [ "$#" -gt 0 ]; then - gen_tests="$1" - shift -else - gen_tests=1 -fi - -# Whether to test with clang. -if [ "$#" -gt 0 ]; then - test_with_clang="$1" - shift -else - test_with_clang=1 -fi - -# Whether to test with gcc. -if [ "$#" -gt 0 ]; then - test_with_gcc="$1" - shift -else - test_with_gcc=1 -fi - -# Whether to test with sanitizers. -if [ "$#" -gt 0 ]; then - run_sanitizers="$1" - shift -else - run_sanitizers=1 -fi - -# Whether to test with valgrind. -if [ "$#" -gt 0 ]; then - run_valgrind="$1" - shift -else - run_valgrind=1 -fi - -# Whether to test all settings combos. -if [ "$#" -gt 0 ]; then - test_settings="$1" - shift -else - test_settings=1 -fi - -# Whether to test 64-bit in addition to 32-bit. -if [ "$#" -gt 0 ]; then - run_64_bit="$1" - shift -else - run_64_bit=1 -fi - -# Whether to test with strgen.sh in addition to strgen.c. -if [ "$#" -gt 0 ]; then - run_gen_script="$1" - shift -else - run_gen_script=0 -fi - -# Whether to test on C11 in addition to C99. -if [ "$#" -gt 0 ]; then - test_c11="$1" - shift -else - test_c11=0 -fi - -# Whether to test 128-bit integers in addition to no 128-bit integers. -if [ "$#" -gt 0 ]; then - test_128_bit="$1" - shift -else - test_128_bit=0 -fi - -# Whether to test with computed goto or not. -if [ "$#" -gt 0 ]; then - test_computed_goto="$1" - shift -else - test_computed_goto=0 -fi - -if [ "$run_64_bit" -ne 0 ]; then - bits=64 -else - bits=32 -fi - -if [ "$test_computed_goto" -eq 0 ]; then - clang_flags="-DBC_NO_COMPUTED_GOTO $clang_flags" - gcc_flags="-DBC_NO_COMPUTED_GOTO $gcc_flags" -fi - -cd "$scriptdir/.." - -# Setup a default compiler. -if [ "$test_with_clang" -ne 0 ]; then - defcc="clang" -elif [ "$test_with_gcc" -ne 0 ]; then - defcc="gcc" -else - defcc="c99" -fi - -export ASAN_OPTIONS="abort_on_error=1,allocator_may_return_null=1" -export UBSAN_OPTIONS="print_stack_trace=1,silence_unsigned_overflow=1" - -build "$debug -std=c99" "$defcc" "-g" "1" "$bits" - -header "Running math library under --standard" - -# Make sure the math library is POSIX compliant. -printf 'quit\n' | bin/bc -ls - -do_make clean_tests - -# Run the clang build sets. -if [ "$test_with_clang" -ne 0 ]; then - build_set "clang" "$run_tests" -fi - -# Run the gcc build sets. -if [ "$test_with_gcc" -ne 0 ]; then - build_set "gcc" "$run_tests" -fi - -if [ "$run_tests" -ne 0 ]; then - - build "$release" "$defcc" "-O3" "1" "$bits" - - # Run karatsuba. - karatsuba - - # Valgrind. - if [ "$run_valgrind" -ne 0 -a "$test_with_gcc" -ne 0 ]; then - vg - fi - - printf '\n' - printf 'Tests successful.\n' - - # I just assume that I am going to be fuzzing when I am done. - header "Building for AFL++..." - - "$scriptdir/fuzz_prep.sh" - - printf '\n' - printf 'Ready for scripts/randmath.py and for fuzzing.\n' - printf '\n' - printf 'Run scripts/randmath.py if you changed any math code.\n' - printf '\n' - printf 'Then if there are no problems, run the fuzzer.\n' - printf '\n' - printf 'Then run `scripts/fuzz_prep.sh -a`.\n' - printf '\n' - printf 'Then run `scripts/afl.py --asan`.\n' - -fi diff --git a/contrib/bc/scripts/release_settings.txt b/contrib/bc/scripts/release_settings.txt deleted file mode 100644 index 1cf572347241..000000000000 --- a/contrib/bc/scripts/release_settings.txt +++ /dev/null @@ -1,16 +0,0 @@ --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -Sbc.history -Sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -Sbc.prompt -Sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -Sbc.history -Sdc.history -sbc.prompt -sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -Sbc.prompt -Sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -Sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -sbc.history -sdc.history -Sbc.prompt -Sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -Sbc.history -Sdc.history -Sbc.prompt -Sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -Sdc.history -sbc.prompt -sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -sbc.history -sdc.history -Sbc.prompt -Sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -Sbc.history -Sdc.history -Sbc.prompt -Sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -Sdc.history -Sbc.prompt -Sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -Sdc.history -Sbc.prompt -Sdc.prompt diff --git a/contrib/bc/scripts/safe-install.sh b/contrib/bc/scripts/safe-install.sh index 041088386682..5774a17e20de 100755 --- a/contrib/bc/scripts/safe-install.sh +++ b/contrib/bc/scripts/safe-install.sh @@ -41,7 +41,7 @@ set -e if test "$mkdirp" ; then umask 022 -case "$2" in +case "$dst" in */*) mkdir -p "${dst%/*}" ;; esac fi @@ -51,15 +51,15 @@ trap 'rm -f "$tmp"' EXIT INT QUIT TERM HUP umask 077 if test "$symlink" ; then -ln -s "$1" "$tmp" +ln -s "$src" "$tmp" else -cat < "$1" > "$tmp" +cat < "$src" > "$tmp" chmod "$mode" "$tmp" fi -mv -f "$tmp" "$2" -test -d "$2" && { -rm -f "$2/$tmp" +mv -f "$tmp" "$dst" +test -d "$dst" && { +rm -f "$dst/$tmp" printf "%s: %s is a directory\n" "$0" "$dst" 1>&2 exit 1 } diff --git a/contrib/bc/scripts/sqrt_frac_guess.bc b/contrib/bc/scripts/sqrt_frac_guess.bc new file mode 100644 index 000000000000..4591e95a216f --- /dev/null +++ b/contrib/bc/scripts/sqrt_frac_guess.bc @@ -0,0 +1,126 @@ +#! /usr/bin/bc +# +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2018-2025 Gavin D. Howard and contributors. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +scale = 20 + +# Adjust this number to try ranges below different powers of 10. +shift = 4 + +# Adjust this to try extra digits. For example, a value of one means that one +# digit is checked (such as 0.09 through 0.01), a value of two means that two +# digits are checked (0.090 through 0.010), etc. +max = shift + 2 + +n = (9 >> shift) +inc = (1 >> max) +stop = (1 >> shift) + +# Uncomment this to test the high part of the ranges. +#n += (1 - (1 >> max + 5)) >> shift + +for (i = n; i >= stop; i -= inc) +{ + # This is the lower limit. + t1 = sqrt(1/(3*i)) + + # Start with the inverse. + t2 = (1/i) + + # And take half its length of course. + l = length(t2$)/2 + + temp = i + odd = 0 + + # We go by powers of 10 below, but there is a degenerate case: an exact + # power of 10, for which length() will return one digit more. So we check + # for that and fix it. + while (temp < 1) + { + temp <<= 1 + odd = !odd + } + + if (temp == 1) + { + odd = !odd + } + + print "i: ", i, "\n" + print "t2: ", t2, "\n" + #print "l: ", l, "\n" + print "odd: ", odd, "\n" + + if (odd) + { + # Limit between 6 and 7.5. + limit1 = 6.7 >> (l$ * 2 + 1) + + # Limit between 1.5 and 1.83-ish. + limit2 = 1.7 >> (l$ * 2 + 1) + print "limit1: ", limit1, "\n" + print "limit2: ", limit2, "\n" + + if (i >= limit1) + { + t2 = (t2 >> l$) + } + else if (i >= limit2) + { + t2 = (t2 >> l$) / 2 + } + else + { + t2 = (t2 >> l$) / 4 + } + } + else + { + # Limit between 2.4 and 3. + limit = 2.7 >> (l$ * 2) + print "limit: ", limit, "\n" + + if (i >= limit) + { + t2 = (t2 >> l$) * 2 + } + else + { + t2 = (t2 >> l$) + } + } + #t2 = 1 + t3 = sqrt(5/(3*i)) + good = (t1 < t2 && t2 < t3) + + print t1, " < ", t2, " < ", t3, ": ", good, "\n\n" + if (!good) sqrt(-1) +} + +halt diff --git a/contrib/bc/scripts/sqrt_int_guess.bc b/contrib/bc/scripts/sqrt_int_guess.bc new file mode 100644 index 000000000000..9fabea874aeb --- /dev/null +++ b/contrib/bc/scripts/sqrt_int_guess.bc @@ -0,0 +1,94 @@ +#! /usr/bin/bc -l +# +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2018-2025 Gavin D. Howard and contributors. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +# Adjust this number to try ranges above different powers of 10. +max = 0 + +n = (1 << max) + +# Uncomment this to test the high part of the ranges. +#n += (1 - (1 >> 10)) + +n + +# Loop from the start number to the next power of 10. +for (i = n; i < (n$ << 1); i += 1) +{ + # This is the lower limit. + t1 = sqrt(1/(3*i)) + + l = length(i$)/2 + + print "i: ", i, "\n" + #print "l: ", l, "\n" + + if (l$ != l) + { + # Limit between 2.4 and 3. + limit = 2.7 << (l$ * 2) + #print "limit: ", limit, "\n" + + if (i >= limit) + { + t2 = 1/(i >> (l$)) * 2 + } + else + { + t2 = 1/(i >> (l$)) + } + } + else + { + # Limit between 3.8-ish and 4.8 + limit = 4.3 << (l$ * 2 - 1) + #print "limit: ", limit, "\n" + + if (i >= limit) + { + t2 = 1/(i >> (l$ - 1)) * 8 + } + else + { + t2 = 1/(i >> (l$ - 1)) * 4 + } + } + + # This is the upper limit. + t3 = sqrt(5/(3*i)) + + # This is true when the guess is in between the limits. + good = (t1 < t2 && t2 < t3) + + print t1, " < ", t2, " < ", t3, ": ", good, "\n" + + # Error if we have a problem. + if (!good) sqrt(-1) +} + +halt diff --git a/contrib/bc/scripts/sqrt_random.bc b/contrib/bc/scripts/sqrt_random.bc new file mode 100644 index 000000000000..08eeddab07a3 --- /dev/null +++ b/contrib/bc/scripts/sqrt_random.bc @@ -0,0 +1,129 @@ +#! /usr/bin/bc +# +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2018-2025 Gavin D. Howard and contributors. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +scale = 0 + +bits = rand() + +# This extracts a bit and takes it out of the original value. +# +# Here, I am getting a bit to say whether we should have a value that is less +# than 1. +bits = divmod(bits, 2, negpow[]) + +# Get a bit that will say whether the value should be an exact square. +bits = divmod(bits, 2, square[]) + +# See below. This is to help bias toward small numbers. +pow = 4 + +# I want to bias toward small numbers, so let's give a 50 percent chance to +# values below 16 or so. +bits = divmod(bits, 2, small[]) + +# Let's keep raising the power limit by 2^4 when the bit is zero. +while (!small[0]) +{ + pow += 4 + bits = divmod(bits, 2, small[]) +} + +limit = 2^pow + +# Okay, this is the starting number. +num = irand(limit) + 1 + +# Figure out if we should have (more) fractional digits. +bits = divmod(bits, 2, extra_digits[]) + +if (square[0]) +{ + # Okay, I lied. If we need a perfect square, square now. + num *= num + + # If we need extra digits, we need to multiply by an even power of 10. + if (extra_digits[0]) + { + extra = (irand(8) + 1) * 2 + } + else + { + extra = 0 + } + + # If we need a number less than 1, just take the inverse, which will still + # be a perfect square. + if (negpow[0]) + { + scale = length(num) + 5 + num = 1/num + scale = 0 + + num >>= extra + } + else + { + num <<= extra + } +} +else +{ + # Get this for later. + l = length(num) + + # If we need extra digits. + if (extra_digits[0]) + { + # Add up to 32 decimal places. + num += frand(irand(32) + 1) + } + + # If we need a value less than 1... + if (negpow[0]) + { + # Move right until the number is + num >>= l + } +} + +bits = divmod(bits, 2, zero_scale[]) + +# Do we want a zero scale? +if (zero_scale[0]) +{ + print "scale = 0\n" +} +else +{ + print "scale = 20\n" +} + +print "sqrt(", num, ")\n" + +halt diff --git a/contrib/bc/scripts/sqrt_random.sh b/contrib/bc/scripts/sqrt_random.sh new file mode 100755 index 000000000000..0f7013da0e0e --- /dev/null +++ b/contrib/bc/scripts/sqrt_random.sh @@ -0,0 +1,77 @@ +#! /bin/sh +# +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2018-2025 Gavin D. Howard and contributors. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +scriptdir=$(dirname "$0") + +gnu=/usr/bin/bc +gdh=/usr/local/bin/bc + +if [ "$#" -lt 1 ]; then + printf 'err: must provide path to new bc\n' + exit 1 +fi + +new="$1" +shift + +unset BC_LINE_LENGTH && unset BC_ENV_ARGS + +gdh_fail_file="sqrt_fails.bc" +new_fail_file="new_sqrt_fails.bc" + +rm -rf "$gdh_fail_file" +rm -rf "$new_fail_file" + +while [ true ]; do + + tst=$("$gdh" -l "$scriptdir/sqrt_random.bc") + err=$? + + if [ "$err" -ne 0 ]; then + printf 'err: failed to create test\n' + exit 2 + fi + + good=$(printf '%s\n' "$tst" | "$gnu" -l) + + gdh_out=$(printf '%s\n' "$tst" | "$gdh" -l) + new_out=$(printf '%s\n' "$tst" | "$new" -l) + + gdh_good=$(printf '%s == %s\n' "$good" "$gdh_out" | "$gnu") + new_good=$(printf '%s == %s\n' "$good" "$new_out" | "$gnu") + + if [ "$gdh_good" -eq 0 ]; then + printf '%s\n' "$tst" >> "$gdh_fail_file" + fi + + if [ "$new_good" -eq 0 ]; then + printf '%s\n' "$tst" >> "$new_fail_file" + fi + +done diff --git a/contrib/bc/scripts/test_settings.txt b/contrib/bc/scripts/test_settings.txt deleted file mode 100644 index e6dd8ac92929..000000000000 --- a/contrib/bc/scripts/test_settings.txt +++ /dev/null @@ -1,93 +0,0 @@ --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -sdc.prompt --Sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -Sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -Sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -Sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -Sbc.history -sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -sbc.history -Sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -Sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -Sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -sdc.prompt --Sbc.sigint_reset -sdc.sigint_reset -Sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -sdc.prompt --Sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -Sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -sdc.prompt --Sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -Sbc.history -sdc.history -sbc.prompt -sdc.prompt --Sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -sbc.history -Sdc.history -sbc.prompt -sdc.prompt --Sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -Sbc.prompt -sdc.prompt --Sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -Sdc.prompt --sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -Sdc.sigint_reset -sbc.tty_mode -Sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -Sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -Sbc.history -sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -Sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -sbc.history -Sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -Sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -Sbc.prompt -sdc.prompt --sbc.sigint_reset -Sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -Sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -Sbc.tty_mode -sdc.tty_mode -Sbc.history -sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -Sbc.tty_mode -sdc.tty_mode -sbc.history -Sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -Sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -Sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -Sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -Sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -Sdc.tty_mode -Sbc.history -sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -Sdc.tty_mode -sbc.history -Sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -Sdc.tty_mode -sbc.history -sdc.history -Sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -Sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -Sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -Sbc.history -Sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -Sbc.history -sdc.history -Sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -Sbc.history -sdc.history -sbc.prompt -Sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -sbc.history -Sdc.history -Sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -sbc.history -Sdc.history -sbc.prompt -Sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -Sbc.prompt -Sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -sbc.tty_mode -Sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -Sbc.history -sdc.history -sbc.prompt -sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -sbc.history -Sdc.history -sbc.prompt -sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -Sbc.prompt -sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -Sdc.prompt --sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -sdc.tty_mode -Sbc.history -sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -sdc.tty_mode -sbc.history -Sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -Sbc.prompt -sdc.prompt --sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -Sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -sbc.history -Sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -sbc.history -sdc.history -Sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -Sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -Sdc.tty_mode -Sbc.history -Sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -Sdc.tty_mode -Sbc.history -sdc.history -Sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -Sdc.tty_mode -Sbc.history -sdc.history -sbc.prompt -Sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -Sbc.history -Sdc.history -Sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -Sbc.history -Sdc.history -sbc.prompt -Sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -sbc.history -Sdc.history -Sbc.prompt -Sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -sdc.tty_mode -Sbc.history -sdc.history -sbc.prompt -sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -sdc.tty_mode -sbc.history -Sdc.history -sbc.prompt -sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -Sbc.prompt -sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -Sdc.prompt --sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -sbc.history -Sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -sbc.history -sdc.history -Sbc.prompt -sdc.prompt --sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -Sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -Sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -sdc.history -Sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -sdc.history -sbc.prompt -Sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -Sdc.tty_mode -Sbc.history -Sdc.history -Sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -Sdc.tty_mode -Sbc.history -Sdc.history -sbc.prompt -Sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -sdc.tty_mode -Sbc.history -Sdc.history -Sbc.prompt -Sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -sdc.history -sbc.prompt -sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -sbc.history -Sdc.history -sbc.prompt -sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -sbc.history -sdc.history -Sbc.prompt -sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -sbc.history -sdc.history -sbc.prompt -Sdc.prompt --sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -Sdc.history -sbc.prompt -sdc.prompt --sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -sdc.history -Sbc.prompt -sdc.prompt --sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -sdc.history -sbc.prompt -Sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -Sdc.history -Sbc.prompt -sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -Sdc.history -sbc.prompt -Sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -sbc.tty_mode -Sdc.tty_mode -Sbc.history -Sdc.history -Sbc.prompt -Sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -Sdc.history -sbc.prompt -sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -sdc.history -Sbc.prompt -sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -sdc.history -sbc.prompt -Sdc.prompt --sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -Sdc.history -Sbc.prompt -sdc.prompt --sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -Sdc.history -sbc.prompt -Sdc.prompt --sbc.sigint_reset -sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -Sdc.history -Sbc.prompt -Sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -Sdc.history -Sbc.prompt -sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -Sdc.history -sbc.prompt -Sdc.prompt --sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -Sdc.history -Sbc.prompt -Sdc.prompt --Sbc.sigint_reset -Sdc.sigint_reset -Sbc.tty_mode -Sdc.tty_mode -Sbc.history -Sdc.history -Sbc.prompt -Sdc.prompt |