1252884aeSStefan Eßer /* 2252884aeSStefan Eßer * ***************************************************************************** 3252884aeSStefan Eßer * 43aa99676SStefan Eßer * SPDX-License-Identifier: BSD-2-Clause 5252884aeSStefan Eßer * 6d101cdd6SStefan Eßer * Copyright (c) 2018-2023 Gavin D. Howard and contributors. 7252884aeSStefan Eßer * 8252884aeSStefan Eßer * Redistribution and use in source and binary forms, with or without 9252884aeSStefan Eßer * modification, are permitted provided that the following conditions are met: 10252884aeSStefan Eßer * 11252884aeSStefan Eßer * * Redistributions of source code must retain the above copyright notice, this 12252884aeSStefan Eßer * list of conditions and the following disclaimer. 13252884aeSStefan Eßer * 14252884aeSStefan Eßer * * Redistributions in binary form must reproduce the above copyright notice, 15252884aeSStefan Eßer * this list of conditions and the following disclaimer in the documentation 16252884aeSStefan Eßer * and/or other materials provided with the distribution. 17252884aeSStefan Eßer * 18252884aeSStefan Eßer * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19252884aeSStefan Eßer * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20252884aeSStefan Eßer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21252884aeSStefan Eßer * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22252884aeSStefan Eßer * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23252884aeSStefan Eßer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24252884aeSStefan Eßer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25252884aeSStefan Eßer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26252884aeSStefan Eßer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27252884aeSStefan Eßer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28252884aeSStefan Eßer * POSSIBILITY OF SUCH DAMAGE. 29252884aeSStefan Eßer * 30252884aeSStefan Eßer * ***************************************************************************** 31252884aeSStefan Eßer * 3244d4804dSStefan Eßer * All bc status codes and cross-platform portability. 33252884aeSStefan Eßer * 34252884aeSStefan Eßer */ 35252884aeSStefan Eßer 36252884aeSStefan Eßer #ifndef BC_STATUS_H 37252884aeSStefan Eßer #define BC_STATUS_H 38252884aeSStefan Eßer 39d101cdd6SStefan Eßer #ifdef _WIN32 40d101cdd6SStefan Eßer #include <Windows.h> 41d101cdd6SStefan Eßer #include <BaseTsd.h> 42d101cdd6SStefan Eßer #include <stdio.h> 43d101cdd6SStefan Eßer #include <io.h> 44d101cdd6SStefan Eßer #endif // _WIN32 45d101cdd6SStefan Eßer 46252884aeSStefan Eßer #include <stdint.h> 47d101cdd6SStefan Eßer #include <sys/types.h> 48252884aeSStefan Eßer 4944d4804dSStefan Eßer // This is used by configure.sh to test for OpenBSD. 5044d4804dSStefan Eßer #ifdef BC_TEST_OPENBSD 5144d4804dSStefan Eßer #ifdef __OpenBSD__ 5244d4804dSStefan Eßer #error On OpenBSD without _BSD_SOURCE 5344d4804dSStefan Eßer #endif // __OpenBSD__ 5444d4804dSStefan Eßer #endif // BC_TEST_OPENBSD 5544d4804dSStefan Eßer 5678bc019dSStefan Eßer // This is used by configure.sh to test for FreeBSD. 5778bc019dSStefan Eßer #ifdef BC_TEST_FREEBSD 5878bc019dSStefan Eßer #ifdef __FreeBSD__ 5978bc019dSStefan Eßer #error On FreeBSD with _POSIX_C_SOURCE 6078bc019dSStefan Eßer #endif // __FreeBSD__ 6178bc019dSStefan Eßer #endif // BC_TEST_FREEBSD 6278bc019dSStefan Eßer 63d101cdd6SStefan Eßer // Windows has deprecated isatty() and the rest of these. Or doesn't have them. 64d101cdd6SStefan Eßer // So these are just fixes for Windows. 65d101cdd6SStefan Eßer #ifdef _WIN32 66d101cdd6SStefan Eßer 67d101cdd6SStefan Eßer // This one is special. Windows did not like me defining an 68d101cdd6SStefan Eßer // inline function that was not given a definition in a header 69d101cdd6SStefan Eßer // file. This suppresses that by making inline functions non-inline. 70d101cdd6SStefan Eßer #define inline 71d101cdd6SStefan Eßer 72d101cdd6SStefan Eßer #define restrict __restrict 73d101cdd6SStefan Eßer #define strdup _strdup 74d101cdd6SStefan Eßer #define write(f, b, s) _write((f), (b), (unsigned int) (s)) 75d101cdd6SStefan Eßer #define read(f, b, s) _read((f), (b), (unsigned int) (s)) 76d101cdd6SStefan Eßer #define close _close 77d101cdd6SStefan Eßer #define open(f, n, m) \ 78d101cdd6SStefan Eßer _sopen_s((f), (n), (m) | _O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE) 79d101cdd6SStefan Eßer #define sigjmp_buf jmp_buf 80d101cdd6SStefan Eßer #define sigsetjmp(j, s) setjmp(j) 81d101cdd6SStefan Eßer #define siglongjmp longjmp 82d101cdd6SStefan Eßer #define isatty _isatty 83d101cdd6SStefan Eßer #define STDIN_FILENO _fileno(stdin) 84d101cdd6SStefan Eßer #define STDOUT_FILENO _fileno(stdout) 85d101cdd6SStefan Eßer #define STDERR_FILENO _fileno(stderr) 86d101cdd6SStefan Eßer #define S_ISDIR(m) ((m) & (_S_IFDIR)) 87d101cdd6SStefan Eßer #define O_RDONLY _O_RDONLY 88d101cdd6SStefan Eßer #define stat _stat 89d101cdd6SStefan Eßer #define fstat _fstat 90d101cdd6SStefan Eßer #define BC_FILE_SEP '\\' 91d101cdd6SStefan Eßer 92d101cdd6SStefan Eßer #else // _WIN32 93d101cdd6SStefan Eßer #define BC_FILE_SEP '/' 94d101cdd6SStefan Eßer #endif // _WIN32 95d101cdd6SStefan Eßer 96252884aeSStefan Eßer #ifndef BC_ENABLED 97252884aeSStefan Eßer #define BC_ENABLED (1) 98252884aeSStefan Eßer #endif // BC_ENABLED 99252884aeSStefan Eßer 100252884aeSStefan Eßer #ifndef DC_ENABLED 101252884aeSStefan Eßer #define DC_ENABLED (1) 102252884aeSStefan Eßer #endif // DC_ENABLED 103252884aeSStefan Eßer 104d101cdd6SStefan Eßer #ifndef BC_ENABLE_EXTRA_MATH 105d101cdd6SStefan Eßer #define BC_ENABLE_EXTRA_MATH (1) 106d101cdd6SStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 107d101cdd6SStefan Eßer 108662087dfSStefan Eßer #ifndef BC_ENABLE_LIBRARY 109662087dfSStefan Eßer #define BC_ENABLE_LIBRARY (0) 110662087dfSStefan Eßer #endif // BC_ENABLE_LIBRARY 111662087dfSStefan Eßer 112d101cdd6SStefan Eßer #ifndef BC_ENABLE_HISTORY 113d101cdd6SStefan Eßer #define BC_ENABLE_HISTORY (1) 114d101cdd6SStefan Eßer #endif // BC_ENABLE_HISTORY 115d101cdd6SStefan Eßer 116d101cdd6SStefan Eßer #ifndef BC_ENABLE_EDITLINE 117d101cdd6SStefan Eßer #define BC_ENABLE_EDITLINE (0) 118d101cdd6SStefan Eßer #endif // BC_ENABLE_EDITLINE 119d101cdd6SStefan Eßer 120d101cdd6SStefan Eßer #ifndef BC_ENABLE_READLINE 121d101cdd6SStefan Eßer #define BC_ENABLE_READLINE (0) 122d101cdd6SStefan Eßer #endif // BC_ENABLE_READLINE 123d101cdd6SStefan Eßer 124d101cdd6SStefan Eßer #ifndef BC_ENABLE_NLS 125d101cdd6SStefan Eßer #define BC_ENABLE_NLS (0) 126d101cdd6SStefan Eßer #endif // BC_ENABLE_NLS 127d101cdd6SStefan Eßer 128d101cdd6SStefan Eßer #ifdef __OpenBSD__ 129d101cdd6SStefan Eßer #if BC_ENABLE_READLINE 130d101cdd6SStefan Eßer #error Cannot use readline on OpenBSD 131d101cdd6SStefan Eßer #endif // BC_ENABLE_READLINE 132d101cdd6SStefan Eßer #endif // __OpenBSD__ 133d101cdd6SStefan Eßer 134d101cdd6SStefan Eßer #if BC_ENABLE_EDITLINE && BC_ENABLE_READLINE 135d101cdd6SStefan Eßer #error Must enable only one of editline or readline, not both. 136d101cdd6SStefan Eßer #endif // BC_ENABLE_EDITLINE && BC_ENABLE_READLINE 137d101cdd6SStefan Eßer 138d101cdd6SStefan Eßer #if BC_ENABLE_EDITLINE || BC_ENABLE_READLINE 139d101cdd6SStefan Eßer #define BC_ENABLE_LINE_LIB (1) 140d101cdd6SStefan Eßer #else // BC_ENABLE_EDITLINE || BC_ENABLE_READLINE 141d101cdd6SStefan Eßer #define BC_ENABLE_LINE_LIB (0) 142d101cdd6SStefan Eßer #endif // BC_ENABLE_EDITLINE || BC_ENABLE_READLINE 143d101cdd6SStefan Eßer 14444d4804dSStefan Eßer // This is error checking for fuzz builds. 14510328f8bSStefan Eßer #if BC_ENABLE_AFL 14610328f8bSStefan Eßer #ifndef __AFL_HAVE_MANUAL_CONTROL 14744d4804dSStefan Eßer #error Must compile with afl-clang-fast or afl-clang-lto for fuzzing 14810328f8bSStefan Eßer #endif // __AFL_HAVE_MANUAL_CONTROL 14910328f8bSStefan Eßer #endif // BC_ENABLE_AFL 15010328f8bSStefan Eßer 15110328f8bSStefan Eßer #ifndef BC_ENABLE_MEMCHECK 15210328f8bSStefan Eßer #define BC_ENABLE_MEMCHECK (0) 15310328f8bSStefan Eßer #endif // BC_ENABLE_MEMCHECK 15410328f8bSStefan Eßer 15544d4804dSStefan Eßer /** 15644d4804dSStefan Eßer * Mark a variable as unused. 15744d4804dSStefan Eßer * @param e The variable to mark as unused. 15844d4804dSStefan Eßer */ 15944d4804dSStefan Eßer #define BC_UNUSED(e) ((void) (e)) 16044d4804dSStefan Eßer 16144d4804dSStefan Eßer // If users want, they can define this to something like __builtin_expect(e, 1). 16244d4804dSStefan Eßer // It might give a performance improvement. 16344d4804dSStefan Eßer #ifndef BC_LIKELY 16444d4804dSStefan Eßer 16544d4804dSStefan Eßer /** 16644d4804dSStefan Eßer * Mark a branch expression as likely. 16744d4804dSStefan Eßer * @param e The expression to mark as likely. 16844d4804dSStefan Eßer */ 16944d4804dSStefan Eßer #define BC_LIKELY(e) (e) 17044d4804dSStefan Eßer 17144d4804dSStefan Eßer #endif // BC_LIKELY 17244d4804dSStefan Eßer 17344d4804dSStefan Eßer // If users want, they can define this to something like __builtin_expect(e, 0). 17444d4804dSStefan Eßer // It might give a performance improvement. 17544d4804dSStefan Eßer #ifndef BC_UNLIKELY 17644d4804dSStefan Eßer 17744d4804dSStefan Eßer /** 17844d4804dSStefan Eßer * Mark a branch expression as unlikely. 17944d4804dSStefan Eßer * @param e The expression to mark as unlikely. 18044d4804dSStefan Eßer */ 18144d4804dSStefan Eßer #define BC_UNLIKELY(e) (e) 18244d4804dSStefan Eßer 18344d4804dSStefan Eßer #endif // BC_UNLIKELY 18444d4804dSStefan Eßer 18544d4804dSStefan Eßer /** 18644d4804dSStefan Eßer * Mark a branch expression as an error, if true. 18744d4804dSStefan Eßer * @param e The expression to mark as an error, if true. 18844d4804dSStefan Eßer */ 18944d4804dSStefan Eßer #define BC_ERR(e) BC_UNLIKELY(e) 19044d4804dSStefan Eßer 19144d4804dSStefan Eßer /** 19244d4804dSStefan Eßer * Mark a branch expression as not an error, if true. 19344d4804dSStefan Eßer * @param e The expression to mark as not an error, if true. 19444d4804dSStefan Eßer */ 19544d4804dSStefan Eßer #define BC_NO_ERR(s) BC_LIKELY(s) 19644d4804dSStefan Eßer 19744d4804dSStefan Eßer // Disable extra debug code by default. 19844d4804dSStefan Eßer #ifndef BC_DEBUG_CODE 19944d4804dSStefan Eßer #define BC_DEBUG_CODE (0) 20044d4804dSStefan Eßer #endif // BC_DEBUG_CODE 20144d4804dSStefan Eßer 202d101cdd6SStefan Eßer #if defined(__clang__) 203d101cdd6SStefan Eßer #define BC_CLANG (1) 204d101cdd6SStefan Eßer #else // defined(__clang__) 205d101cdd6SStefan Eßer #define BC_CLANG (0) 206d101cdd6SStefan Eßer #endif // defined(__clang__) 207d101cdd6SStefan Eßer 208d101cdd6SStefan Eßer #if defined(__GNUC__) && !BC_CLANG 209d101cdd6SStefan Eßer #define BC_GCC (1) 210d101cdd6SStefan Eßer #else // defined(__GNUC__) && !BC_CLANG 211d101cdd6SStefan Eßer #define BC_GCC (0) 212d101cdd6SStefan Eßer #endif // defined(__GNUC__) && !BC_CLANG 213d101cdd6SStefan Eßer 21444d4804dSStefan Eßer // We want to be able to use _Noreturn on C11 compilers. 21523210c9fSStefan Eßer #if __STDC_VERSION__ >= 201112L 21644d4804dSStefan Eßer 21744d4804dSStefan Eßer #include <stdnoreturn.h> 21844d4804dSStefan Eßer #define BC_NORETURN _Noreturn 21944d4804dSStefan Eßer #define BC_C11 (1) 22044d4804dSStefan Eßer 22144d4804dSStefan Eßer #else // __STDC_VERSION__ 22244d4804dSStefan Eßer 223d101cdd6SStefan Eßer #if BC_CLANG 224d101cdd6SStefan Eßer #if __has_attribute(noreturn) 225d101cdd6SStefan Eßer #define BC_NORETURN __attribute((noreturn)) 226d101cdd6SStefan Eßer #else // __has_attribute(noreturn) 22744d4804dSStefan Eßer #define BC_NORETURN 228d101cdd6SStefan Eßer #endif // __has_attribute(noreturn) 229d101cdd6SStefan Eßer 230d101cdd6SStefan Eßer #else // BC_CLANG 231d101cdd6SStefan Eßer 232d101cdd6SStefan Eßer #define BC_NORETURN 233d101cdd6SStefan Eßer 234d101cdd6SStefan Eßer #endif // BC_CLANG 235d101cdd6SStefan Eßer 23644d4804dSStefan Eßer #define BC_MUST_RETURN 23744d4804dSStefan Eßer #define BC_C11 (0) 23844d4804dSStefan Eßer 23944d4804dSStefan Eßer #endif // __STDC_VERSION__ 24044d4804dSStefan Eßer 24144d4804dSStefan Eßer #define BC_HAS_UNREACHABLE (0) 24244d4804dSStefan Eßer #define BC_HAS_COMPUTED_GOTO (0) 24344d4804dSStefan Eßer 24444d4804dSStefan Eßer // GCC and Clang complain if fallthroughs are not marked with their special 24544d4804dSStefan Eßer // attribute. Jerks. This creates a define for marking the fallthroughs that is 24644d4804dSStefan Eßer // nothing on other compilers. 247d101cdd6SStefan Eßer #if BC_CLANG || BC_GCC 24844d4804dSStefan Eßer 24944d4804dSStefan Eßer #if defined(__has_attribute) 25044d4804dSStefan Eßer 25144d4804dSStefan Eßer #if __has_attribute(fallthrough) 25244d4804dSStefan Eßer #define BC_FALLTHROUGH __attribute__((fallthrough)); 25344d4804dSStefan Eßer #else // __has_attribute(fallthrough) 25444d4804dSStefan Eßer #define BC_FALLTHROUGH 25544d4804dSStefan Eßer #endif // __has_attribute(fallthrough) 25644d4804dSStefan Eßer 257d101cdd6SStefan Eßer #if BC_GCC 25844d4804dSStefan Eßer 25944d4804dSStefan Eßer #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) 26044d4804dSStefan Eßer #undef BC_HAS_UNREACHABLE 26144d4804dSStefan Eßer #define BC_HAS_UNREACHABLE (1) 26244d4804dSStefan Eßer #endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) 26344d4804dSStefan Eßer 264d101cdd6SStefan Eßer #else // BC_GCC 26544d4804dSStefan Eßer 26644d4804dSStefan Eßer #if __clang_major__ >= 4 26744d4804dSStefan Eßer #undef BC_HAS_UNREACHABLE 26844d4804dSStefan Eßer #define BC_HAS_UNREACHABLE (1) 26944d4804dSStefan Eßer #endif // __clang_major__ >= 4 27044d4804dSStefan Eßer 271d101cdd6SStefan Eßer #endif // BC_GCC 27244d4804dSStefan Eßer 27344d4804dSStefan Eßer #else // defined(__has_attribute) 27444d4804dSStefan Eßer #define BC_FALLTHROUGH 27544d4804dSStefan Eßer #endif // defined(__has_attribute) 276d101cdd6SStefan Eßer #else // BC_CLANG || BC_GCC 27744d4804dSStefan Eßer #define BC_FALLTHROUGH 278d101cdd6SStefan Eßer #endif // BC_CLANG || BC_GCC 27944d4804dSStefan Eßer 28044d4804dSStefan Eßer #if BC_HAS_UNREACHABLE 28144d4804dSStefan Eßer 28244d4804dSStefan Eßer #define BC_UNREACHABLE __builtin_unreachable(); 28344d4804dSStefan Eßer 28444d4804dSStefan Eßer #else // BC_HAS_UNREACHABLE 28544d4804dSStefan Eßer 28644d4804dSStefan Eßer #ifdef _WIN32 28744d4804dSStefan Eßer 28844d4804dSStefan Eßer #define BC_UNREACHABLE __assume(0); 28944d4804dSStefan Eßer 29044d4804dSStefan Eßer #else // _WIN32 29144d4804dSStefan Eßer 29244d4804dSStefan Eßer #define BC_UNREACHABLE 29344d4804dSStefan Eßer 29444d4804dSStefan Eßer #endif // _WIN32 29544d4804dSStefan Eßer 29644d4804dSStefan Eßer #endif // BC_HAS_UNREACHABLE 29744d4804dSStefan Eßer 298d101cdd6SStefan Eßer #if BC_GCC 29944d4804dSStefan Eßer 30044d4804dSStefan Eßer #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) 30144d4804dSStefan Eßer 30244d4804dSStefan Eßer #undef BC_HAS_COMPUTED_GOTO 30344d4804dSStefan Eßer #define BC_HAS_COMPUTED_GOTO (1) 30444d4804dSStefan Eßer 30544d4804dSStefan Eßer #endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) 30644d4804dSStefan Eßer 307d101cdd6SStefan Eßer #endif // BC_GCC 30844d4804dSStefan Eßer 309d101cdd6SStefan Eßer #if BC_CLANG 31044d4804dSStefan Eßer 31144d4804dSStefan Eßer #if __clang_major__ >= 4 31244d4804dSStefan Eßer 31344d4804dSStefan Eßer #undef BC_HAS_COMPUTED_GOTO 31444d4804dSStefan Eßer #define BC_HAS_COMPUTED_GOTO (1) 31544d4804dSStefan Eßer 31644d4804dSStefan Eßer #endif // __clang_major__ >= 4 31744d4804dSStefan Eßer 318d101cdd6SStefan Eßer #endif // BC_CLANG 31944d4804dSStefan Eßer 32044d4804dSStefan Eßer #ifdef BC_NO_COMPUTED_GOTO 32144d4804dSStefan Eßer 32244d4804dSStefan Eßer #undef BC_HAS_COMPUTED_GOTO 32344d4804dSStefan Eßer #define BC_HAS_COMPUTED_GOTO (0) 32444d4804dSStefan Eßer 32544d4804dSStefan Eßer #endif // BC_NO_COMPUTED_GOTO 32644d4804dSStefan Eßer 327d101cdd6SStefan Eßer #if BC_GCC 32844d4804dSStefan Eßer #ifdef __OpenBSD__ 32944d4804dSStefan Eßer // The OpenBSD GCC doesn't like inline. 33044d4804dSStefan Eßer #define inline 33144d4804dSStefan Eßer #endif // __OpenBSD__ 332d101cdd6SStefan Eßer #endif // BC_GCC 33344d4804dSStefan Eßer 33444d4804dSStefan Eßer // Workarounds for AIX's POSIX incompatibility. 33544d4804dSStefan Eßer #ifndef SIZE_MAX 33644d4804dSStefan Eßer #define SIZE_MAX __SIZE_MAX__ 33744d4804dSStefan Eßer #endif // SIZE_MAX 33844d4804dSStefan Eßer #ifndef UINTMAX_C 33944d4804dSStefan Eßer #define UINTMAX_C __UINTMAX_C 34044d4804dSStefan Eßer #endif // UINTMAX_C 34144d4804dSStefan Eßer #ifndef UINT32_C 34244d4804dSStefan Eßer #define UINT32_C __UINT32_C 34344d4804dSStefan Eßer #endif // UINT32_C 34444d4804dSStefan Eßer #ifndef UINT_FAST32_MAX 34544d4804dSStefan Eßer #define UINT_FAST32_MAX __UINT_FAST32_MAX__ 34644d4804dSStefan Eßer #endif // UINT_FAST32_MAX 34744d4804dSStefan Eßer #ifndef UINT16_MAX 34844d4804dSStefan Eßer #define UINT16_MAX __UINT16_MAX__ 34944d4804dSStefan Eßer #endif // UINT16_MAX 35044d4804dSStefan Eßer #ifndef SIG_ATOMIC_MAX 35144d4804dSStefan Eßer #define SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__ 35244d4804dSStefan Eßer #endif // SIG_ATOMIC_MAX 35344d4804dSStefan Eßer 35444d4804dSStefan Eßer // Yes, this has to be here. 35550696a6eSStefan Eßer #include <bcl.h> 35650696a6eSStefan Eßer 35744d4804dSStefan Eßer // All of these set defaults for settings. 35844d4804dSStefan Eßer 35944d4804dSStefan Eßer #if BC_ENABLED 36044d4804dSStefan Eßer 36144d4804dSStefan Eßer #ifndef BC_DEFAULT_BANNER 36244d4804dSStefan Eßer #define BC_DEFAULT_BANNER (0) 36344d4804dSStefan Eßer #endif // BC_DEFAULT_BANNER 36444d4804dSStefan Eßer 36544d4804dSStefan Eßer #endif // BC_ENABLED 36644d4804dSStefan Eßer 36744d4804dSStefan Eßer #ifndef BC_DEFAULT_SIGINT_RESET 36844d4804dSStefan Eßer #define BC_DEFAULT_SIGINT_RESET (1) 36944d4804dSStefan Eßer #endif // BC_DEFAULT_SIGINT_RESET 37044d4804dSStefan Eßer 37144d4804dSStefan Eßer #ifndef BC_DEFAULT_TTY_MODE 37244d4804dSStefan Eßer #define BC_DEFAULT_TTY_MODE (1) 37344d4804dSStefan Eßer #endif // BC_DEFAULT_TTY_MODE 37444d4804dSStefan Eßer 37544d4804dSStefan Eßer #ifndef BC_DEFAULT_PROMPT 37644d4804dSStefan Eßer #define BC_DEFAULT_PROMPT BC_DEFAULT_TTY_MODE 37744d4804dSStefan Eßer #endif // BC_DEFAULT_PROMPT 37844d4804dSStefan Eßer 37910041e99SStefan Eßer #ifndef BC_DEFAULT_EXPR_EXIT 38010041e99SStefan Eßer #define BC_DEFAULT_EXPR_EXIT (1) 38110041e99SStefan Eßer #endif // BC_DEFAULT_EXPR_EXIT 38210041e99SStefan Eßer 383d101cdd6SStefan Eßer #ifndef BC_DEFAULT_DIGIT_CLAMP 384d101cdd6SStefan Eßer #define BC_DEFAULT_DIGIT_CLAMP (0) 385d101cdd6SStefan Eßer #endif // BC_DEFAULT_DIGIT_CLAMP 386d101cdd6SStefan Eßer 38744d4804dSStefan Eßer // All of these set defaults for settings. 38844d4804dSStefan Eßer #ifndef DC_DEFAULT_SIGINT_RESET 38944d4804dSStefan Eßer #define DC_DEFAULT_SIGINT_RESET (1) 39044d4804dSStefan Eßer #endif // DC_DEFAULT_SIGINT_RESET 39144d4804dSStefan Eßer 39244d4804dSStefan Eßer #ifndef DC_DEFAULT_TTY_MODE 39344d4804dSStefan Eßer #define DC_DEFAULT_TTY_MODE (0) 39444d4804dSStefan Eßer #endif // DC_DEFAULT_TTY_MODE 39544d4804dSStefan Eßer 39644d4804dSStefan Eßer #ifndef DC_DEFAULT_HISTORY 39744d4804dSStefan Eßer #define DC_DEFAULT_HISTORY DC_DEFAULT_TTY_MODE 39844d4804dSStefan Eßer #endif // DC_DEFAULT_HISTORY 39944d4804dSStefan Eßer 40044d4804dSStefan Eßer #ifndef DC_DEFAULT_PROMPT 40144d4804dSStefan Eßer #define DC_DEFAULT_PROMPT DC_DEFAULT_TTY_MODE 40244d4804dSStefan Eßer #endif // DC_DEFAULT_PROMPT 40344d4804dSStefan Eßer 40410041e99SStefan Eßer #ifndef DC_DEFAULT_EXPR_EXIT 40510041e99SStefan Eßer #define DC_DEFAULT_EXPR_EXIT (1) 40610041e99SStefan Eßer #endif // DC_DEFAULT_EXPR_EXIT 40710041e99SStefan Eßer 408d101cdd6SStefan Eßer #ifndef DC_DEFAULT_DIGIT_CLAMP 409d101cdd6SStefan Eßer #define DC_DEFAULT_DIGIT_CLAMP (0) 410d101cdd6SStefan Eßer #endif // DC_DEFAULT_DIGIT_CLAMP 411d101cdd6SStefan Eßer 41244d4804dSStefan Eßer /// Statuses, which mark either which category of error happened, or some other 41344d4804dSStefan Eßer /// status that matters. 41478bc019dSStefan Eßer typedef enum BcStatus 41578bc019dSStefan Eßer { 41644d4804dSStefan Eßer /// Normal status. 417252884aeSStefan Eßer BC_STATUS_SUCCESS = 0, 41844d4804dSStefan Eßer 41944d4804dSStefan Eßer /// Math error. 420252884aeSStefan Eßer BC_STATUS_ERROR_MATH, 42144d4804dSStefan Eßer 42244d4804dSStefan Eßer /// Parse (and lex) error. 423252884aeSStefan Eßer BC_STATUS_ERROR_PARSE, 42444d4804dSStefan Eßer 42544d4804dSStefan Eßer /// Runtime error. 426252884aeSStefan Eßer BC_STATUS_ERROR_EXEC, 42744d4804dSStefan Eßer 42844d4804dSStefan Eßer /// Fatal error. 429252884aeSStefan Eßer BC_STATUS_ERROR_FATAL, 43044d4804dSStefan Eßer 43144d4804dSStefan Eßer /// EOF status. 432252884aeSStefan Eßer BC_STATUS_EOF, 43344d4804dSStefan Eßer 43444d4804dSStefan Eßer /// Quit status. This means that bc/dc is in the process of quitting. 435252884aeSStefan Eßer BC_STATUS_QUIT, 436252884aeSStefan Eßer 437252884aeSStefan Eßer } BcStatus; 438252884aeSStefan Eßer 43944d4804dSStefan Eßer /// Errors, which are more specific errors. 44078bc019dSStefan Eßer typedef enum BcErr 44178bc019dSStefan Eßer { 44244d4804dSStefan Eßer // Math errors. 44344d4804dSStefan Eßer 44444d4804dSStefan Eßer /// Negative number used when not allowed. 44550696a6eSStefan Eßer BC_ERR_MATH_NEGATIVE, 44644d4804dSStefan Eßer 44744d4804dSStefan Eßer /// Non-integer used when not allowed. 44850696a6eSStefan Eßer BC_ERR_MATH_NON_INTEGER, 44944d4804dSStefan Eßer 45044d4804dSStefan Eßer /// Conversion to a hardware integer would overflow. 45150696a6eSStefan Eßer BC_ERR_MATH_OVERFLOW, 45244d4804dSStefan Eßer 45344d4804dSStefan Eßer /// Divide by zero. 45450696a6eSStefan Eßer BC_ERR_MATH_DIVIDE_BY_ZERO, 455252884aeSStefan Eßer 45644d4804dSStefan Eßer // Fatal errors. 45744d4804dSStefan Eßer 45844d4804dSStefan Eßer /// An allocation or reallocation failed. 45950696a6eSStefan Eßer BC_ERR_FATAL_ALLOC_ERR, 46044d4804dSStefan Eßer 46144d4804dSStefan Eßer /// I/O failure. 46250696a6eSStefan Eßer BC_ERR_FATAL_IO_ERR, 46344d4804dSStefan Eßer 46444d4804dSStefan Eßer /// File error, such as permissions or file does not exist. 46550696a6eSStefan Eßer BC_ERR_FATAL_FILE_ERR, 46644d4804dSStefan Eßer 46744d4804dSStefan Eßer /// File is binary, not text, error. 46850696a6eSStefan Eßer BC_ERR_FATAL_BIN_FILE, 46944d4804dSStefan Eßer 47044d4804dSStefan Eßer /// Attempted to read a directory as a file error. 47150696a6eSStefan Eßer BC_ERR_FATAL_PATH_DIR, 47244d4804dSStefan Eßer 47344d4804dSStefan Eßer /// Invalid option error. 47450696a6eSStefan Eßer BC_ERR_FATAL_OPTION, 47544d4804dSStefan Eßer 47644d4804dSStefan Eßer /// Option with required argument not given an argument. 47750696a6eSStefan Eßer BC_ERR_FATAL_OPTION_NO_ARG, 47844d4804dSStefan Eßer 47944d4804dSStefan Eßer /// Option with no argument given an argument. 48050696a6eSStefan Eßer BC_ERR_FATAL_OPTION_ARG, 481252884aeSStefan Eßer 48244d4804dSStefan Eßer /// Option argument is invalid. 48344d4804dSStefan Eßer BC_ERR_FATAL_ARG, 48444d4804dSStefan Eßer 48544d4804dSStefan Eßer // Runtime errors. 48644d4804dSStefan Eßer 48744d4804dSStefan Eßer /// Invalid ibase value. 48850696a6eSStefan Eßer BC_ERR_EXEC_IBASE, 48944d4804dSStefan Eßer 49044d4804dSStefan Eßer /// Invalid obase value. 49150696a6eSStefan Eßer BC_ERR_EXEC_OBASE, 49244d4804dSStefan Eßer 49344d4804dSStefan Eßer /// Invalid scale value. 49450696a6eSStefan Eßer BC_ERR_EXEC_SCALE, 49544d4804dSStefan Eßer 49644d4804dSStefan Eßer /// Invalid expression parsed by read(). 49750696a6eSStefan Eßer BC_ERR_EXEC_READ_EXPR, 49844d4804dSStefan Eßer 49944d4804dSStefan Eßer /// read() used within an expression given to a read() call. 50050696a6eSStefan Eßer BC_ERR_EXEC_REC_READ, 50144d4804dSStefan Eßer 50244d4804dSStefan Eßer /// Type error. 50350696a6eSStefan Eßer BC_ERR_EXEC_TYPE, 504252884aeSStefan Eßer 50544d4804dSStefan Eßer /// Stack has too few elements error. 50650696a6eSStefan Eßer BC_ERR_EXEC_STACK, 507252884aeSStefan Eßer 50844d4804dSStefan Eßer /// Register stack has too few elements error. 50944d4804dSStefan Eßer BC_ERR_EXEC_STACK_REGISTER, 51044d4804dSStefan Eßer 51144d4804dSStefan Eßer /// Wrong number of arguments error. 51250696a6eSStefan Eßer BC_ERR_EXEC_PARAMS, 51344d4804dSStefan Eßer 51444d4804dSStefan Eßer /// Undefined function error. 51550696a6eSStefan Eßer BC_ERR_EXEC_UNDEF_FUNC, 51644d4804dSStefan Eßer 51744d4804dSStefan Eßer /// Void value used in an expression error. 51850696a6eSStefan Eßer BC_ERR_EXEC_VOID_VAL, 519252884aeSStefan Eßer 52023210c9fSStefan Eßer // Parse (and lex) errors. 52144d4804dSStefan Eßer 52244d4804dSStefan Eßer /// EOF encountered when not expected error. 52350696a6eSStefan Eßer BC_ERR_PARSE_EOF, 52444d4804dSStefan Eßer 52544d4804dSStefan Eßer /// Invalid character error. 52650696a6eSStefan Eßer BC_ERR_PARSE_CHAR, 52744d4804dSStefan Eßer 52844d4804dSStefan Eßer /// Invalid string (no ending quote) error. 52950696a6eSStefan Eßer BC_ERR_PARSE_STRING, 53044d4804dSStefan Eßer 53144d4804dSStefan Eßer /// Invalid comment (no end found) error. 53250696a6eSStefan Eßer BC_ERR_PARSE_COMMENT, 53344d4804dSStefan Eßer 53444d4804dSStefan Eßer /// Invalid token encountered error. 53550696a6eSStefan Eßer BC_ERR_PARSE_TOKEN, 53644d4804dSStefan Eßer 537252884aeSStefan Eßer #if BC_ENABLED 53844d4804dSStefan Eßer 53944d4804dSStefan Eßer /// Invalid expression error. 54050696a6eSStefan Eßer BC_ERR_PARSE_EXPR, 54144d4804dSStefan Eßer 54244d4804dSStefan Eßer /// Expression is empty error. 54350696a6eSStefan Eßer BC_ERR_PARSE_EMPTY_EXPR, 54444d4804dSStefan Eßer 54544d4804dSStefan Eßer /// Print statement is invalid error. 54650696a6eSStefan Eßer BC_ERR_PARSE_PRINT, 54744d4804dSStefan Eßer 54844d4804dSStefan Eßer /// Function definition is invalid error. 54950696a6eSStefan Eßer BC_ERR_PARSE_FUNC, 55044d4804dSStefan Eßer 55144d4804dSStefan Eßer /// Assignment is invalid error. 55250696a6eSStefan Eßer BC_ERR_PARSE_ASSIGN, 55344d4804dSStefan Eßer 55444d4804dSStefan Eßer /// No auto identifiers given for an auto statement error. 55550696a6eSStefan Eßer BC_ERR_PARSE_NO_AUTO, 55644d4804dSStefan Eßer 55744d4804dSStefan Eßer /// Duplicate local (parameter or auto) error. 55850696a6eSStefan Eßer BC_ERR_PARSE_DUP_LOCAL, 55944d4804dSStefan Eßer 56044d4804dSStefan Eßer /// Invalid block (within braces) error. 56150696a6eSStefan Eßer BC_ERR_PARSE_BLOCK, 56244d4804dSStefan Eßer 56344d4804dSStefan Eßer /// Invalid return statement for void functions. 56450696a6eSStefan Eßer BC_ERR_PARSE_RET_VOID, 56544d4804dSStefan Eßer 56644d4804dSStefan Eßer /// Reference attached to a variable, not an array, error. 56750696a6eSStefan Eßer BC_ERR_PARSE_REF_VAR, 568252884aeSStefan Eßer 56944d4804dSStefan Eßer // POSIX-only errors. 57044d4804dSStefan Eßer 57144d4804dSStefan Eßer /// Name length greater than 1 error. 57250696a6eSStefan Eßer BC_ERR_POSIX_NAME_LEN, 57344d4804dSStefan Eßer 57444d4804dSStefan Eßer /// Non-POSIX comment used error. 57550696a6eSStefan Eßer BC_ERR_POSIX_COMMENT, 57644d4804dSStefan Eßer 57744d4804dSStefan Eßer /// Non-POSIX keyword error. 57850696a6eSStefan Eßer BC_ERR_POSIX_KW, 57944d4804dSStefan Eßer 58044d4804dSStefan Eßer /// Non-POSIX . (last) error. 58150696a6eSStefan Eßer BC_ERR_POSIX_DOT, 58244d4804dSStefan Eßer 58344d4804dSStefan Eßer /// Non-POSIX return error. 58450696a6eSStefan Eßer BC_ERR_POSIX_RET, 58544d4804dSStefan Eßer 58644d4804dSStefan Eßer /// Non-POSIX boolean operator used error. 58750696a6eSStefan Eßer BC_ERR_POSIX_BOOL, 58844d4804dSStefan Eßer 58944d4804dSStefan Eßer /// POSIX relation operator used outside if, while, or for statements error. 59050696a6eSStefan Eßer BC_ERR_POSIX_REL_POS, 59144d4804dSStefan Eßer 59244d4804dSStefan Eßer /// Multiple POSIX relation operators used in an if, while, or for statement 59344d4804dSStefan Eßer /// error. 59450696a6eSStefan Eßer BC_ERR_POSIX_MULTIREL, 59544d4804dSStefan Eßer 59644d4804dSStefan Eßer /// Empty statements in POSIX for loop error. 59750696a6eSStefan Eßer BC_ERR_POSIX_FOR, 59844d4804dSStefan Eßer 59910041e99SStefan Eßer /// POSIX's grammar does not allow a function definition right after a 60010041e99SStefan Eßer /// semicolon. 60110041e99SStefan Eßer BC_ERR_POSIX_FUNC_AFTER_SEMICOLON, 60210041e99SStefan Eßer 60344d4804dSStefan Eßer /// Non-POSIX exponential (scientific or engineering) number used error. 60450696a6eSStefan Eßer BC_ERR_POSIX_EXP_NUM, 60544d4804dSStefan Eßer 60644d4804dSStefan Eßer /// Non-POSIX array reference error. 60750696a6eSStefan Eßer BC_ERR_POSIX_REF, 60844d4804dSStefan Eßer 60944d4804dSStefan Eßer /// Non-POSIX void error. 61050696a6eSStefan Eßer BC_ERR_POSIX_VOID, 61144d4804dSStefan Eßer 61244d4804dSStefan Eßer /// Non-POSIX brace position used error. 61350696a6eSStefan Eßer BC_ERR_POSIX_BRACE, 61444d4804dSStefan Eßer 61544d4804dSStefan Eßer /// String used in expression. 61644d4804dSStefan Eßer BC_ERR_POSIX_EXPR_STRING, 61744d4804dSStefan Eßer 618252884aeSStefan Eßer #endif // BC_ENABLED 619252884aeSStefan Eßer 62044d4804dSStefan Eßer // Number of elements. 62150696a6eSStefan Eßer BC_ERR_NELEMS, 622252884aeSStefan Eßer 623252884aeSStefan Eßer #if BC_ENABLED 62444d4804dSStefan Eßer 62544d4804dSStefan Eßer /// A marker for the start of POSIX errors. 62650696a6eSStefan Eßer BC_ERR_POSIX_START = BC_ERR_POSIX_NAME_LEN, 62744d4804dSStefan Eßer 62844d4804dSStefan Eßer /// A marker for the end of POSIX errors. 62944d4804dSStefan Eßer BC_ERR_POSIX_END = BC_ERR_POSIX_EXPR_STRING, 63044d4804dSStefan Eßer 631252884aeSStefan Eßer #endif // BC_ENABLED 632252884aeSStefan Eßer 63350696a6eSStefan Eßer } BcErr; 634252884aeSStefan Eßer 63544d4804dSStefan Eßer // The indices of each category of error in bc_errs[], and used in bc_err_ids[] 63644d4804dSStefan Eßer // to associate actual errors with their categories. 63744d4804dSStefan Eßer 63844d4804dSStefan Eßer /// Math error category. 639252884aeSStefan Eßer #define BC_ERR_IDX_MATH (0) 64044d4804dSStefan Eßer 64144d4804dSStefan Eßer /// Parse (and lex) error category. 642252884aeSStefan Eßer #define BC_ERR_IDX_PARSE (1) 64344d4804dSStefan Eßer 64444d4804dSStefan Eßer /// Runtime error category. 645252884aeSStefan Eßer #define BC_ERR_IDX_EXEC (2) 64644d4804dSStefan Eßer 64744d4804dSStefan Eßer /// Fatal error category. 648252884aeSStefan Eßer #define BC_ERR_IDX_FATAL (3) 64944d4804dSStefan Eßer 65044d4804dSStefan Eßer /// Number of categories. 651252884aeSStefan Eßer #define BC_ERR_IDX_NELEMS (4) 652252884aeSStefan Eßer 65344d4804dSStefan Eßer // If bc is enabled, we add an extra category for POSIX warnings. 654252884aeSStefan Eßer #if BC_ENABLED 65544d4804dSStefan Eßer 65644d4804dSStefan Eßer /// POSIX warning category. 657252884aeSStefan Eßer #define BC_ERR_IDX_WARN (BC_ERR_IDX_NELEMS) 65844d4804dSStefan Eßer 659252884aeSStefan Eßer #endif // BC_ENABLED 660252884aeSStefan Eßer 661d101cdd6SStefan Eßer /** 662d101cdd6SStefan Eßer * The mode bc is in. This is basically what input it is processing. 663d101cdd6SStefan Eßer */ 664d101cdd6SStefan Eßer typedef enum BcMode 665d101cdd6SStefan Eßer { 666d101cdd6SStefan Eßer /// Expressions mode. 667d101cdd6SStefan Eßer BC_MODE_EXPRS, 668d101cdd6SStefan Eßer 669d101cdd6SStefan Eßer /// File mode. 670d101cdd6SStefan Eßer BC_MODE_FILE, 671d101cdd6SStefan Eßer 672d101cdd6SStefan Eßer /// stdin mode. 673d101cdd6SStefan Eßer BC_MODE_STDIN, 674d101cdd6SStefan Eßer 675d101cdd6SStefan Eßer } BcMode; 676d101cdd6SStefan Eßer 67744d4804dSStefan Eßer /// Do a longjmp(). This is what to use when activating an "exception", i.e., a 67844d4804dSStefan Eßer /// longjmp(). With debug code, it will print the name of the function it jumped 67944d4804dSStefan Eßer /// from. 68044d4804dSStefan Eßer #if BC_DEBUG_CODE 68144d4804dSStefan Eßer #define BC_JMP bc_vm_jmp(__func__) 68244d4804dSStefan Eßer #else // BC_DEBUG_CODE 68344d4804dSStefan Eßer #define BC_JMP bc_vm_jmp() 68444d4804dSStefan Eßer #endif // BC_DEBUG_CODE 68544d4804dSStefan Eßer 686d101cdd6SStefan Eßer #if !BC_ENABLE_LIBRARY 687d101cdd6SStefan Eßer 68844d4804dSStefan Eßer /// Returns true if an exception is in flight, false otherwise. 689d101cdd6SStefan Eßer #define BC_SIG_EXC(vm) \ 690d101cdd6SStefan Eßer BC_UNLIKELY((vm)->status != (sig_atomic_t) BC_STATUS_SUCCESS || (vm)->sig) 69144d4804dSStefan Eßer 69244d4804dSStefan Eßer /// Returns true if there is *no* exception in flight, false otherwise. 693d101cdd6SStefan Eßer #define BC_NO_SIG_EXC(vm) \ 694d101cdd6SStefan Eßer BC_LIKELY((vm)->status == (sig_atomic_t) BC_STATUS_SUCCESS && !(vm)->sig) 695d101cdd6SStefan Eßer 696d101cdd6SStefan Eßer #ifndef _WIN32 697d101cdd6SStefan Eßer #define BC_SIG_INTERRUPT(vm) \ 698d101cdd6SStefan Eßer BC_UNLIKELY((vm)->sig != 0 && (vm)->sig != SIGWINCH) 699d101cdd6SStefan Eßer #else // _WIN32 700d101cdd6SStefan Eßer #define BC_SIG_INTERRUPT(vm) BC_UNLIKELY((vm)->sig != 0) 701d101cdd6SStefan Eßer #endif // _WIN32 70244d4804dSStefan Eßer 70344d4804dSStefan Eßer #ifndef NDEBUG 70444d4804dSStefan Eßer 70544d4804dSStefan Eßer /// Assert that signals are locked. There are non-async-signal-safe functions in 70644d4804dSStefan Eßer /// bc, and they *must* have signals locked. Other functions are expected to 70744d4804dSStefan Eßer /// *not* have signals locked, for reasons. So this is a pre-built assert 70844d4804dSStefan Eßer /// (no-op in non-debug mode) that check that signals are locked. 70978bc019dSStefan Eßer #define BC_SIG_ASSERT_LOCKED \ 71078bc019dSStefan Eßer do \ 71178bc019dSStefan Eßer { \ 712d101cdd6SStefan Eßer assert(vm->sig_lock); \ 71378bc019dSStefan Eßer } \ 71478bc019dSStefan Eßer while (0) 71544d4804dSStefan Eßer 71644d4804dSStefan Eßer /// Assert that signals are unlocked. There are non-async-signal-safe functions 71744d4804dSStefan Eßer /// in bc, and they *must* have signals locked. Other functions are expected to 71844d4804dSStefan Eßer /// *not* have signals locked, for reasons. So this is a pre-built assert 71944d4804dSStefan Eßer /// (no-op in non-debug mode) that check that signals are unlocked. 72078bc019dSStefan Eßer #define BC_SIG_ASSERT_NOT_LOCKED \ 72178bc019dSStefan Eßer do \ 72278bc019dSStefan Eßer { \ 723d101cdd6SStefan Eßer assert(vm->sig_lock == 0); \ 72478bc019dSStefan Eßer } \ 72578bc019dSStefan Eßer while (0) 72644d4804dSStefan Eßer 72744d4804dSStefan Eßer #else // NDEBUG 72844d4804dSStefan Eßer 72944d4804dSStefan Eßer /// Assert that signals are locked. There are non-async-signal-safe functions in 73044d4804dSStefan Eßer /// bc, and they *must* have signals locked. Other functions are expected to 73144d4804dSStefan Eßer /// *not* have signals locked, for reasons. So this is a pre-built assert 73244d4804dSStefan Eßer /// (no-op in non-debug mode) that check that signals are locked. 73344d4804dSStefan Eßer #define BC_SIG_ASSERT_LOCKED 73444d4804dSStefan Eßer 73544d4804dSStefan Eßer /// Assert that signals are unlocked. There are non-async-signal-safe functions 73644d4804dSStefan Eßer /// in bc, and they *must* have signals locked. Other functions are expected to 73744d4804dSStefan Eßer /// *not* have signals locked, for reasons. So this is a pre-built assert 73844d4804dSStefan Eßer /// (no-op in non-debug mode) that check that signals are unlocked. 73944d4804dSStefan Eßer #define BC_SIG_ASSERT_NOT_LOCKED 74044d4804dSStefan Eßer 74144d4804dSStefan Eßer #endif // NDEBUG 74244d4804dSStefan Eßer 74344d4804dSStefan Eßer /// Locks signals. 74444d4804dSStefan Eßer #define BC_SIG_LOCK \ 74578bc019dSStefan Eßer do \ 74678bc019dSStefan Eßer { \ 74744d4804dSStefan Eßer BC_SIG_ASSERT_NOT_LOCKED; \ 748d101cdd6SStefan Eßer vm->sig_lock = 1; \ 74978bc019dSStefan Eßer } \ 75078bc019dSStefan Eßer while (0) 75144d4804dSStefan Eßer 75244d4804dSStefan Eßer /// Unlocks signals. If a signal happened, then this will cause a jump. 75344d4804dSStefan Eßer #define BC_SIG_UNLOCK \ 75478bc019dSStefan Eßer do \ 75578bc019dSStefan Eßer { \ 75644d4804dSStefan Eßer BC_SIG_ASSERT_LOCKED; \ 757d101cdd6SStefan Eßer vm->sig_lock = 0; \ 758d101cdd6SStefan Eßer if (vm->sig) BC_JMP; \ 75978bc019dSStefan Eßer } \ 76078bc019dSStefan Eßer while (0) 76144d4804dSStefan Eßer 76244d4804dSStefan Eßer /// Locks signals, regardless of if they are already locked. This is really only 76344d4804dSStefan Eßer /// used after labels that longjmp() goes to after the jump because the cleanup 76444d4804dSStefan Eßer /// code must have signals locked, and BC_LONGJMP_CONT will unlock signals if it 76544d4804dSStefan Eßer /// doesn't jump. 76644d4804dSStefan Eßer #define BC_SIG_MAYLOCK \ 76778bc019dSStefan Eßer do \ 76878bc019dSStefan Eßer { \ 769d101cdd6SStefan Eßer vm->sig_lock = 1; \ 77078bc019dSStefan Eßer } \ 77178bc019dSStefan Eßer while (0) 77244d4804dSStefan Eßer 77344d4804dSStefan Eßer /// Unlocks signals, regardless of if they were already unlocked. If a signal 77444d4804dSStefan Eßer /// happened, then this will cause a jump. 77544d4804dSStefan Eßer #define BC_SIG_MAYUNLOCK \ 77678bc019dSStefan Eßer do \ 77778bc019dSStefan Eßer { \ 778d101cdd6SStefan Eßer vm->sig_lock = 0; \ 779d101cdd6SStefan Eßer if (vm->sig) BC_JMP; \ 78078bc019dSStefan Eßer } \ 78178bc019dSStefan Eßer while (0) 78244d4804dSStefan Eßer 783d101cdd6SStefan Eßer /** 78444d4804dSStefan Eßer * Locks signals, but stores the old lock state, to be restored later by 78544d4804dSStefan Eßer * BC_SIG_TRYUNLOCK. 78644d4804dSStefan Eßer * @param v The variable to store the old lock state to. 78744d4804dSStefan Eßer */ 78844d4804dSStefan Eßer #define BC_SIG_TRYLOCK(v) \ 78978bc019dSStefan Eßer do \ 79078bc019dSStefan Eßer { \ 791d101cdd6SStefan Eßer v = vm->sig_lock; \ 792d101cdd6SStefan Eßer vm->sig_lock = 1; \ 79378bc019dSStefan Eßer } \ 79478bc019dSStefan Eßer while (0) 79544d4804dSStefan Eßer 796d101cdd6SStefan Eßer /** 797d101cdd6SStefan Eßer * Restores the previous state of a signal lock, and if it is now unlocked, 79844d4804dSStefan Eßer * initiates an exception/jump. 79944d4804dSStefan Eßer * @param v The old lock state. 80044d4804dSStefan Eßer */ 80144d4804dSStefan Eßer #define BC_SIG_TRYUNLOCK(v) \ 80278bc019dSStefan Eßer do \ 80378bc019dSStefan Eßer { \ 804d101cdd6SStefan Eßer vm->sig_lock = (v); \ 805d101cdd6SStefan Eßer if (!(v) && vm->sig) BC_JMP; \ 80678bc019dSStefan Eßer } \ 80778bc019dSStefan Eßer while (0) 80844d4804dSStefan Eßer 809d101cdd6SStefan Eßer /// Stops a stack unwinding. Technically, a stack unwinding needs to be done 810d101cdd6SStefan Eßer /// manually, but it will always be done unless certain flags are cleared. This 811d101cdd6SStefan Eßer /// clears the flags. 812d101cdd6SStefan Eßer #define BC_LONGJMP_STOP \ 813d101cdd6SStefan Eßer do \ 814d101cdd6SStefan Eßer { \ 815d101cdd6SStefan Eßer vm->sig_pop = 0; \ 816d101cdd6SStefan Eßer vm->sig = 0; \ 817d101cdd6SStefan Eßer } \ 818d101cdd6SStefan Eßer while (0) 819d101cdd6SStefan Eßer 820d101cdd6SStefan Eßer /** 821d101cdd6SStefan Eßer * Sets a jump like BC_SETJMP, but unlike BC_SETJMP, it assumes signals are 822d101cdd6SStefan Eßer * locked and will just set the jump. This does *not* have a call to 823d101cdd6SStefan Eßer * bc_vec_grow() because it is assumed that BC_SETJMP_LOCKED(l) is used *after* 824d101cdd6SStefan Eßer * the initializations that need the setjmp(). 825d101cdd6SStefan Eßer * param l The label to jump to on a longjmp(). 826d101cdd6SStefan Eßer */ 827d101cdd6SStefan Eßer #define BC_SETJMP_LOCKED(vm, l) \ 828d101cdd6SStefan Eßer do \ 829d101cdd6SStefan Eßer { \ 830d101cdd6SStefan Eßer sigjmp_buf sjb; \ 831d101cdd6SStefan Eßer BC_SIG_ASSERT_LOCKED; \ 832d101cdd6SStefan Eßer if (sigsetjmp(sjb, 0)) \ 833d101cdd6SStefan Eßer { \ 834d101cdd6SStefan Eßer assert(BC_SIG_EXC(vm)); \ 835d101cdd6SStefan Eßer goto l; \ 836d101cdd6SStefan Eßer } \ 837d101cdd6SStefan Eßer bc_vec_push(&vm->jmp_bufs, &sjb); \ 838d101cdd6SStefan Eßer } \ 839d101cdd6SStefan Eßer while (0) 840d101cdd6SStefan Eßer 841d101cdd6SStefan Eßer /// Used after cleanup labels set by BC_SETJMP and BC_SETJMP_LOCKED to jump to 842d101cdd6SStefan Eßer /// the next place. This is what continues the stack unwinding. This basically 843d101cdd6SStefan Eßer /// copies BC_SIG_UNLOCK into itself, but that is because its condition for 844d101cdd6SStefan Eßer /// jumping is BC_SIG_EXC, not just that a signal happened. 845d101cdd6SStefan Eßer #define BC_LONGJMP_CONT(vm) \ 846d101cdd6SStefan Eßer do \ 847d101cdd6SStefan Eßer { \ 848d101cdd6SStefan Eßer BC_SIG_ASSERT_LOCKED; \ 849d101cdd6SStefan Eßer if (!vm->sig_pop) bc_vec_pop(&vm->jmp_bufs); \ 850d101cdd6SStefan Eßer vm->sig_lock = 0; \ 851d101cdd6SStefan Eßer if (BC_SIG_EXC(vm)) BC_JMP; \ 852d101cdd6SStefan Eßer } \ 853d101cdd6SStefan Eßer while (0) 854d101cdd6SStefan Eßer 855d101cdd6SStefan Eßer #else // !BC_ENABLE_LIBRARY 856d101cdd6SStefan Eßer 857d101cdd6SStefan Eßer #define BC_SIG_LOCK 858d101cdd6SStefan Eßer #define BC_SIG_UNLOCK 859d101cdd6SStefan Eßer #define BC_SIG_MAYLOCK 860d101cdd6SStefan Eßer #define BC_SIG_TRYLOCK(lock) 861d101cdd6SStefan Eßer #define BC_SIG_TRYUNLOCK(lock) 862d101cdd6SStefan Eßer #define BC_SIG_ASSERT_LOCKED 863d101cdd6SStefan Eßer 864d101cdd6SStefan Eßer /// Returns true if an exception is in flight, false otherwise. 865d101cdd6SStefan Eßer #define BC_SIG_EXC(vm) \ 866d101cdd6SStefan Eßer BC_UNLIKELY(vm->status != (sig_atomic_t) BC_STATUS_SUCCESS) 867d101cdd6SStefan Eßer 868d101cdd6SStefan Eßer /// Returns true if there is *no* exception in flight, false otherwise. 869d101cdd6SStefan Eßer #define BC_NO_SIG_EXC(vm) \ 870d101cdd6SStefan Eßer BC_LIKELY(vm->status == (sig_atomic_t) BC_STATUS_SUCCESS) 871d101cdd6SStefan Eßer 872d101cdd6SStefan Eßer /// Used after cleanup labels set by BC_SETJMP and BC_SETJMP_LOCKED to jump to 873d101cdd6SStefan Eßer /// the next place. This is what continues the stack unwinding. This basically 874d101cdd6SStefan Eßer /// copies BC_SIG_UNLOCK into itself, but that is because its condition for 875d101cdd6SStefan Eßer /// jumping is BC_SIG_EXC, not just that a signal happened. 876d101cdd6SStefan Eßer #define BC_LONGJMP_CONT(vm) \ 877d101cdd6SStefan Eßer do \ 878d101cdd6SStefan Eßer { \ 879d101cdd6SStefan Eßer bc_vec_pop(&vm->jmp_bufs); \ 880d101cdd6SStefan Eßer if (BC_SIG_EXC(vm)) BC_JMP; \ 881d101cdd6SStefan Eßer } \ 882d101cdd6SStefan Eßer while (0) 883d101cdd6SStefan Eßer 884d101cdd6SStefan Eßer #endif // !BC_ENABLE_LIBRARY 885d101cdd6SStefan Eßer 88644d4804dSStefan Eßer /** 88744d4804dSStefan Eßer * Sets a jump, and sets it up as well so that if a longjmp() happens, bc will 88844d4804dSStefan Eßer * immediately goto a label where some cleanup code is. This one assumes that 88944d4804dSStefan Eßer * signals are not locked and will lock them, set the jump, and unlock them. 89044d4804dSStefan Eßer * Setting the jump also includes pushing the jmp_buf onto the jmp_buf stack. 89144d4804dSStefan Eßer * This grows the jmp_bufs vector first to prevent a fatal error from happening 89244d4804dSStefan Eßer * after the setjmp(). This is done because BC_SETJMP(l) is assumed to be used 89344d4804dSStefan Eßer * *before* the actual initialization calls that need the setjmp(). 89444d4804dSStefan Eßer * param l The label to jump to on a longjmp(). 89544d4804dSStefan Eßer */ 896d101cdd6SStefan Eßer #define BC_SETJMP(vm, l) \ 89778bc019dSStefan Eßer do \ 89878bc019dSStefan Eßer { \ 89944d4804dSStefan Eßer sigjmp_buf sjb; \ 90044d4804dSStefan Eßer BC_SIG_LOCK; \ 901d101cdd6SStefan Eßer bc_vec_grow(&vm->jmp_bufs, 1); \ 90278bc019dSStefan Eßer if (sigsetjmp(sjb, 0)) \ 90378bc019dSStefan Eßer { \ 904d101cdd6SStefan Eßer assert(BC_SIG_EXC(vm)); \ 90544d4804dSStefan Eßer goto l; \ 90644d4804dSStefan Eßer } \ 907d101cdd6SStefan Eßer bc_vec_push(&vm->jmp_bufs, &sjb); \ 90844d4804dSStefan Eßer BC_SIG_UNLOCK; \ 90978bc019dSStefan Eßer } \ 91078bc019dSStefan Eßer while (0) 91144d4804dSStefan Eßer 91244d4804dSStefan Eßer /// Unsets a jump. It always assumes signals are locked. This basically just 91344d4804dSStefan Eßer /// pops a jmp_buf off of the stack of jmp_bufs, and since the jump mechanism 91444d4804dSStefan Eßer /// always jumps to the location at the top of the stack, this effectively 91544d4804dSStefan Eßer /// undoes a setjmp(). 916d101cdd6SStefan Eßer #define BC_UNSETJMP(vm) \ 91778bc019dSStefan Eßer do \ 91878bc019dSStefan Eßer { \ 91944d4804dSStefan Eßer BC_SIG_ASSERT_LOCKED; \ 920d101cdd6SStefan Eßer bc_vec_pop(&vm->jmp_bufs); \ 92178bc019dSStefan Eßer } \ 92278bc019dSStefan Eßer while (0) 92344d4804dSStefan Eßer 924d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY 925d101cdd6SStefan Eßer 926d101cdd6SStefan Eßer #define BC_SETJMP_LOCKED(vm, l) BC_SETJMP(vm, l) 92744d4804dSStefan Eßer 92844d4804dSStefan Eßer // Various convenience macros for calling the bc's error handling routine. 92944d4804dSStefan Eßer 93044d4804dSStefan Eßer /** 93144d4804dSStefan Eßer * Call bc's error handling routine. 93244d4804dSStefan Eßer * @param e The error. 93344d4804dSStefan Eßer * @param l The line of the script that the error happened. 93444d4804dSStefan Eßer * @param ... Extra arguments for error messages as necessary. 93544d4804dSStefan Eßer */ 93644d4804dSStefan Eßer #define bc_error(e, l, ...) (bc_vm_handleError((e))) 93744d4804dSStefan Eßer 93844d4804dSStefan Eßer /** 93944d4804dSStefan Eßer * Call bc's error handling routine. 94044d4804dSStefan Eßer * @param e The error. 94144d4804dSStefan Eßer */ 94244d4804dSStefan Eßer #define bc_err(e) (bc_vm_handleError((e))) 94344d4804dSStefan Eßer 94444d4804dSStefan Eßer /** 94544d4804dSStefan Eßer * Call bc's error handling routine. 94644d4804dSStefan Eßer * @param e The error. 94744d4804dSStefan Eßer */ 94844d4804dSStefan Eßer #define bc_verr(e, ...) (bc_vm_handleError((e))) 94944d4804dSStefan Eßer 95044d4804dSStefan Eßer #else // BC_ENABLE_LIBRARY 95144d4804dSStefan Eßer 952d101cdd6SStefan Eßer // Various convenience macros for calling the bc's error handling routine. 953d101cdd6SStefan Eßer 95444d4804dSStefan Eßer /** 95544d4804dSStefan Eßer * Call bc's error handling routine. 95644d4804dSStefan Eßer * @param e The error. 95744d4804dSStefan Eßer * @param l The line of the script that the error happened. 95844d4804dSStefan Eßer * @param ... Extra arguments for error messages as necessary. 95944d4804dSStefan Eßer */ 960d101cdd6SStefan Eßer #ifndef NDEBUG 961d101cdd6SStefan Eßer #define bc_error(e, l, ...) \ 962d101cdd6SStefan Eßer (bc_vm_handleError((e), __FILE__, __LINE__, (l), __VA_ARGS__)) 963d101cdd6SStefan Eßer #else // NDEBUG 96444d4804dSStefan Eßer #define bc_error(e, l, ...) (bc_vm_handleError((e), (l), __VA_ARGS__)) 965d101cdd6SStefan Eßer #endif // NDEBUG 96644d4804dSStefan Eßer 96744d4804dSStefan Eßer /** 96844d4804dSStefan Eßer * Call bc's error handling routine. 96944d4804dSStefan Eßer * @param e The error. 97044d4804dSStefan Eßer */ 971d101cdd6SStefan Eßer #ifndef NDEBUG 972d101cdd6SStefan Eßer #define bc_err(e) (bc_vm_handleError((e), __FILE__, __LINE__, 0)) 973d101cdd6SStefan Eßer #else // NDEBUG 97444d4804dSStefan Eßer #define bc_err(e) (bc_vm_handleError((e), 0)) 975d101cdd6SStefan Eßer #endif // NDEBUG 97644d4804dSStefan Eßer 97744d4804dSStefan Eßer /** 97844d4804dSStefan Eßer * Call bc's error handling routine. 97944d4804dSStefan Eßer * @param e The error. 98044d4804dSStefan Eßer */ 981d101cdd6SStefan Eßer #ifndef NDEBUG 982d101cdd6SStefan Eßer #define bc_verr(e, ...) \ 983d101cdd6SStefan Eßer (bc_vm_handleError((e), __FILE__, __LINE__, 0, __VA_ARGS__)) 984d101cdd6SStefan Eßer #else // NDEBUG 98544d4804dSStefan Eßer #define bc_verr(e, ...) (bc_vm_handleError((e), 0, __VA_ARGS__)) 986d101cdd6SStefan Eßer #endif // NDEBUG 98744d4804dSStefan Eßer 98844d4804dSStefan Eßer #endif // BC_ENABLE_LIBRARY 98944d4804dSStefan Eßer 99044d4804dSStefan Eßer /** 99144d4804dSStefan Eßer * Returns true if status @a s is an error, false otherwise. 99244d4804dSStefan Eßer * @param s The status to test. 99344d4804dSStefan Eßer * @return True if @a s is an error, false otherwise. 99444d4804dSStefan Eßer */ 99544d4804dSStefan Eßer #define BC_STATUS_IS_ERROR(s) \ 99644d4804dSStefan Eßer ((s) >= BC_STATUS_ERROR_MATH && (s) <= BC_STATUS_ERROR_FATAL) 99744d4804dSStefan Eßer 99844d4804dSStefan Eßer // Convenience macros that can be placed at the beginning and exits of functions 99944d4804dSStefan Eßer // for easy marking of where functions are entered and exited. 100044d4804dSStefan Eßer #if BC_DEBUG_CODE 100144d4804dSStefan Eßer #define BC_FUNC_ENTER \ 100278bc019dSStefan Eßer do \ 100378bc019dSStefan Eßer { \ 100444d4804dSStefan Eßer size_t bc_func_enter_i; \ 1005d101cdd6SStefan Eßer for (bc_func_enter_i = 0; bc_func_enter_i < vm->func_depth; \ 100644d4804dSStefan Eßer ++bc_func_enter_i) \ 100744d4804dSStefan Eßer { \ 1008d101cdd6SStefan Eßer bc_file_puts(&vm->ferr, bc_flush_none, " "); \ 100944d4804dSStefan Eßer } \ 1010d101cdd6SStefan Eßer vm->func_depth += 1; \ 1011d101cdd6SStefan Eßer bc_file_printf(&vm->ferr, "Entering %s\n", __func__); \ 1012d101cdd6SStefan Eßer bc_file_flush(&vm->ferr, bc_flush_none); \ 101378bc019dSStefan Eßer } \ 101478bc019dSStefan Eßer while (0); 101544d4804dSStefan Eßer 101644d4804dSStefan Eßer #define BC_FUNC_EXIT \ 101778bc019dSStefan Eßer do \ 101878bc019dSStefan Eßer { \ 101944d4804dSStefan Eßer size_t bc_func_enter_i; \ 1020d101cdd6SStefan Eßer vm->func_depth -= 1; \ 1021d101cdd6SStefan Eßer for (bc_func_enter_i = 0; bc_func_enter_i < vm->func_depth; \ 102244d4804dSStefan Eßer ++bc_func_enter_i) \ 102344d4804dSStefan Eßer { \ 1024d101cdd6SStefan Eßer bc_file_puts(&vm->ferr, bc_flush_none, " "); \ 102544d4804dSStefan Eßer } \ 1026d101cdd6SStefan Eßer bc_file_printf(&vm->ferr, "Leaving %s\n", __func__); \ 1027d101cdd6SStefan Eßer bc_file_flush(&vm->ferr, bc_flush_none); \ 102878bc019dSStefan Eßer } \ 102978bc019dSStefan Eßer while (0); 103044d4804dSStefan Eßer #else // BC_DEBUG_CODE 103144d4804dSStefan Eßer #define BC_FUNC_ENTER 103244d4804dSStefan Eßer #define BC_FUNC_EXIT 103344d4804dSStefan Eßer #endif // BC_DEBUG_CODE 103444d4804dSStefan Eßer 1035252884aeSStefan Eßer #endif // BC_STATUS_H 1036