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 6376238846SStefan Eßer // This is used by configure.sh to test for Mac OSX. 6476238846SStefan Eßer #ifdef BC_TEST_APPLE 6576238846SStefan Eßer #ifdef __APPLE__ 6676238846SStefan Eßer #error On Mac OSX without _DARWIN_C_SOURCE 6776238846SStefan Eßer #endif // __APPLE__ 6876238846SStefan Eßer #endif // BC_TEST_APPLE 6976238846SStefan Eßer 70d101cdd6SStefan Eßer // Windows has deprecated isatty() and the rest of these. Or doesn't have them. 71d101cdd6SStefan Eßer // So these are just fixes for Windows. 72d101cdd6SStefan Eßer #ifdef _WIN32 73d101cdd6SStefan Eßer 74d101cdd6SStefan Eßer // This one is special. Windows did not like me defining an 75d101cdd6SStefan Eßer // inline function that was not given a definition in a header 76d101cdd6SStefan Eßer // file. This suppresses that by making inline functions non-inline. 77d101cdd6SStefan Eßer #define inline 78d101cdd6SStefan Eßer 79d101cdd6SStefan Eßer #define restrict __restrict 80d101cdd6SStefan Eßer #define strdup _strdup 81d101cdd6SStefan Eßer #define write(f, b, s) _write((f), (b), (unsigned int) (s)) 82d101cdd6SStefan Eßer #define read(f, b, s) _read((f), (b), (unsigned int) (s)) 83d101cdd6SStefan Eßer #define close _close 84d101cdd6SStefan Eßer #define open(f, n, m) \ 85d101cdd6SStefan Eßer _sopen_s((f), (n), (m) | _O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE) 86d101cdd6SStefan Eßer #define sigjmp_buf jmp_buf 87d101cdd6SStefan Eßer #define sigsetjmp(j, s) setjmp(j) 88d101cdd6SStefan Eßer #define siglongjmp longjmp 89d101cdd6SStefan Eßer #define isatty _isatty 90d101cdd6SStefan Eßer #define STDIN_FILENO _fileno(stdin) 91d101cdd6SStefan Eßer #define STDOUT_FILENO _fileno(stdout) 92d101cdd6SStefan Eßer #define STDERR_FILENO _fileno(stderr) 93d101cdd6SStefan Eßer #define S_ISDIR(m) ((m) & (_S_IFDIR)) 94d101cdd6SStefan Eßer #define O_RDONLY _O_RDONLY 95d101cdd6SStefan Eßer #define stat _stat 96d101cdd6SStefan Eßer #define fstat _fstat 97d101cdd6SStefan Eßer #define BC_FILE_SEP '\\' 98d101cdd6SStefan Eßer 99d101cdd6SStefan Eßer #else // _WIN32 100d101cdd6SStefan Eßer #define BC_FILE_SEP '/' 101d101cdd6SStefan Eßer #endif // _WIN32 102d101cdd6SStefan Eßer 103252884aeSStefan Eßer #ifndef BC_ENABLED 104252884aeSStefan Eßer #define BC_ENABLED (1) 105252884aeSStefan Eßer #endif // BC_ENABLED 106252884aeSStefan Eßer 107252884aeSStefan Eßer #ifndef DC_ENABLED 108252884aeSStefan Eßer #define DC_ENABLED (1) 109252884aeSStefan Eßer #endif // DC_ENABLED 110252884aeSStefan Eßer 111d101cdd6SStefan Eßer #ifndef BC_ENABLE_EXTRA_MATH 112d101cdd6SStefan Eßer #define BC_ENABLE_EXTRA_MATH (1) 113d101cdd6SStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 114d101cdd6SStefan Eßer 115662087dfSStefan Eßer #ifndef BC_ENABLE_LIBRARY 116662087dfSStefan Eßer #define BC_ENABLE_LIBRARY (0) 117662087dfSStefan Eßer #endif // BC_ENABLE_LIBRARY 118662087dfSStefan Eßer 119d101cdd6SStefan Eßer #ifndef BC_ENABLE_HISTORY 120d101cdd6SStefan Eßer #define BC_ENABLE_HISTORY (1) 121d101cdd6SStefan Eßer #endif // BC_ENABLE_HISTORY 122d101cdd6SStefan Eßer 123d101cdd6SStefan Eßer #ifndef BC_ENABLE_EDITLINE 124d101cdd6SStefan Eßer #define BC_ENABLE_EDITLINE (0) 125d101cdd6SStefan Eßer #endif // BC_ENABLE_EDITLINE 126d101cdd6SStefan Eßer 127d101cdd6SStefan Eßer #ifndef BC_ENABLE_READLINE 128d101cdd6SStefan Eßer #define BC_ENABLE_READLINE (0) 129d101cdd6SStefan Eßer #endif // BC_ENABLE_READLINE 130d101cdd6SStefan Eßer 131d101cdd6SStefan Eßer #ifndef BC_ENABLE_NLS 132d101cdd6SStefan Eßer #define BC_ENABLE_NLS (0) 133d101cdd6SStefan Eßer #endif // BC_ENABLE_NLS 134d101cdd6SStefan Eßer 135d101cdd6SStefan Eßer #ifdef __OpenBSD__ 136d101cdd6SStefan Eßer #if BC_ENABLE_READLINE 137d101cdd6SStefan Eßer #error Cannot use readline on OpenBSD 138d101cdd6SStefan Eßer #endif // BC_ENABLE_READLINE 139d101cdd6SStefan Eßer #endif // __OpenBSD__ 140d101cdd6SStefan Eßer 141d101cdd6SStefan Eßer #if BC_ENABLE_EDITLINE && BC_ENABLE_READLINE 142d101cdd6SStefan Eßer #error Must enable only one of editline or readline, not both. 143d101cdd6SStefan Eßer #endif // BC_ENABLE_EDITLINE && BC_ENABLE_READLINE 144d101cdd6SStefan Eßer 145d101cdd6SStefan Eßer #if BC_ENABLE_EDITLINE || BC_ENABLE_READLINE 146d101cdd6SStefan Eßer #define BC_ENABLE_LINE_LIB (1) 147d101cdd6SStefan Eßer #else // BC_ENABLE_EDITLINE || BC_ENABLE_READLINE 148d101cdd6SStefan Eßer #define BC_ENABLE_LINE_LIB (0) 149d101cdd6SStefan Eßer #endif // BC_ENABLE_EDITLINE || BC_ENABLE_READLINE 150d101cdd6SStefan Eßer 15144d4804dSStefan Eßer // This is error checking for fuzz builds. 15210328f8bSStefan Eßer #if BC_ENABLE_AFL 15310328f8bSStefan Eßer #ifndef __AFL_HAVE_MANUAL_CONTROL 15444d4804dSStefan Eßer #error Must compile with afl-clang-fast or afl-clang-lto for fuzzing 15510328f8bSStefan Eßer #endif // __AFL_HAVE_MANUAL_CONTROL 15610328f8bSStefan Eßer #endif // BC_ENABLE_AFL 15710328f8bSStefan Eßer 15810328f8bSStefan Eßer #ifndef BC_ENABLE_MEMCHECK 15910328f8bSStefan Eßer #define BC_ENABLE_MEMCHECK (0) 16010328f8bSStefan Eßer #endif // BC_ENABLE_MEMCHECK 16110328f8bSStefan Eßer 16244d4804dSStefan Eßer /** 16344d4804dSStefan Eßer * Mark a variable as unused. 16444d4804dSStefan Eßer * @param e The variable to mark as unused. 16544d4804dSStefan Eßer */ 16644d4804dSStefan Eßer #define BC_UNUSED(e) ((void) (e)) 16744d4804dSStefan Eßer 16844d4804dSStefan Eßer // If users want, they can define this to something like __builtin_expect(e, 1). 16944d4804dSStefan Eßer // It might give a performance improvement. 17044d4804dSStefan Eßer #ifndef BC_LIKELY 17144d4804dSStefan Eßer 17244d4804dSStefan Eßer /** 17344d4804dSStefan Eßer * Mark a branch expression as likely. 17444d4804dSStefan Eßer * @param e The expression to mark as likely. 17544d4804dSStefan Eßer */ 17644d4804dSStefan Eßer #define BC_LIKELY(e) (e) 17744d4804dSStefan Eßer 17844d4804dSStefan Eßer #endif // BC_LIKELY 17944d4804dSStefan Eßer 18044d4804dSStefan Eßer // If users want, they can define this to something like __builtin_expect(e, 0). 18144d4804dSStefan Eßer // It might give a performance improvement. 18244d4804dSStefan Eßer #ifndef BC_UNLIKELY 18344d4804dSStefan Eßer 18444d4804dSStefan Eßer /** 18544d4804dSStefan Eßer * Mark a branch expression as unlikely. 18644d4804dSStefan Eßer * @param e The expression to mark as unlikely. 18744d4804dSStefan Eßer */ 18844d4804dSStefan Eßer #define BC_UNLIKELY(e) (e) 18944d4804dSStefan Eßer 19044d4804dSStefan Eßer #endif // BC_UNLIKELY 19144d4804dSStefan Eßer 19244d4804dSStefan Eßer /** 19344d4804dSStefan Eßer * Mark a branch expression as an error, if true. 19444d4804dSStefan Eßer * @param e The expression to mark as an error, if true. 19544d4804dSStefan Eßer */ 19644d4804dSStefan Eßer #define BC_ERR(e) BC_UNLIKELY(e) 19744d4804dSStefan Eßer 19844d4804dSStefan Eßer /** 19944d4804dSStefan Eßer * Mark a branch expression as not an error, if true. 20044d4804dSStefan Eßer * @param e The expression to mark as not an error, if true. 20144d4804dSStefan Eßer */ 20244d4804dSStefan Eßer #define BC_NO_ERR(s) BC_LIKELY(s) 20344d4804dSStefan Eßer 20444d4804dSStefan Eßer // Disable extra debug code by default. 20544d4804dSStefan Eßer #ifndef BC_DEBUG_CODE 20644d4804dSStefan Eßer #define BC_DEBUG_CODE (0) 20744d4804dSStefan Eßer #endif // BC_DEBUG_CODE 20844d4804dSStefan Eßer 209d101cdd6SStefan Eßer #if defined(__clang__) 210d101cdd6SStefan Eßer #define BC_CLANG (1) 211d101cdd6SStefan Eßer #else // defined(__clang__) 212d101cdd6SStefan Eßer #define BC_CLANG (0) 213d101cdd6SStefan Eßer #endif // defined(__clang__) 214d101cdd6SStefan Eßer 215d101cdd6SStefan Eßer #if defined(__GNUC__) && !BC_CLANG 216d101cdd6SStefan Eßer #define BC_GCC (1) 217d101cdd6SStefan Eßer #else // defined(__GNUC__) && !BC_CLANG 218d101cdd6SStefan Eßer #define BC_GCC (0) 219d101cdd6SStefan Eßer #endif // defined(__GNUC__) && !BC_CLANG 220d101cdd6SStefan Eßer 22144d4804dSStefan Eßer // We want to be able to use _Noreturn on C11 compilers. 22223210c9fSStefan Eßer #if __STDC_VERSION__ >= 201112L 22344d4804dSStefan Eßer 22444d4804dSStefan Eßer #include <stdnoreturn.h> 22544d4804dSStefan Eßer #define BC_NORETURN _Noreturn 22644d4804dSStefan Eßer #define BC_C11 (1) 22744d4804dSStefan Eßer 22844d4804dSStefan Eßer #else // __STDC_VERSION__ 22944d4804dSStefan Eßer 230d101cdd6SStefan Eßer #if BC_CLANG 231d101cdd6SStefan Eßer #if __has_attribute(noreturn) 232d101cdd6SStefan Eßer #define BC_NORETURN __attribute((noreturn)) 233d101cdd6SStefan Eßer #else // __has_attribute(noreturn) 23444d4804dSStefan Eßer #define BC_NORETURN 235d101cdd6SStefan Eßer #endif // __has_attribute(noreturn) 236d101cdd6SStefan Eßer 237d101cdd6SStefan Eßer #else // BC_CLANG 238d101cdd6SStefan Eßer 239d101cdd6SStefan Eßer #define BC_NORETURN 240d101cdd6SStefan Eßer 241d101cdd6SStefan Eßer #endif // BC_CLANG 242d101cdd6SStefan Eßer 24344d4804dSStefan Eßer #define BC_MUST_RETURN 24444d4804dSStefan Eßer #define BC_C11 (0) 24544d4804dSStefan Eßer 24644d4804dSStefan Eßer #endif // __STDC_VERSION__ 24744d4804dSStefan Eßer 24844d4804dSStefan Eßer #define BC_HAS_UNREACHABLE (0) 24944d4804dSStefan Eßer #define BC_HAS_COMPUTED_GOTO (0) 25044d4804dSStefan Eßer 25144d4804dSStefan Eßer // GCC and Clang complain if fallthroughs are not marked with their special 25244d4804dSStefan Eßer // attribute. Jerks. This creates a define for marking the fallthroughs that is 25344d4804dSStefan Eßer // nothing on other compilers. 254d101cdd6SStefan Eßer #if BC_CLANG || BC_GCC 25544d4804dSStefan Eßer 25644d4804dSStefan Eßer #if defined(__has_attribute) 25744d4804dSStefan Eßer 25844d4804dSStefan Eßer #if __has_attribute(fallthrough) 25944d4804dSStefan Eßer #define BC_FALLTHROUGH __attribute__((fallthrough)); 26044d4804dSStefan Eßer #else // __has_attribute(fallthrough) 26144d4804dSStefan Eßer #define BC_FALLTHROUGH 26244d4804dSStefan Eßer #endif // __has_attribute(fallthrough) 26344d4804dSStefan Eßer 264d101cdd6SStefan Eßer #if BC_GCC 26544d4804dSStefan Eßer 26644d4804dSStefan Eßer #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) 26744d4804dSStefan Eßer #undef BC_HAS_UNREACHABLE 26844d4804dSStefan Eßer #define BC_HAS_UNREACHABLE (1) 26944d4804dSStefan Eßer #endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) 27044d4804dSStefan Eßer 271d101cdd6SStefan Eßer #else // BC_GCC 27244d4804dSStefan Eßer 27344d4804dSStefan Eßer #if __clang_major__ >= 4 27444d4804dSStefan Eßer #undef BC_HAS_UNREACHABLE 27544d4804dSStefan Eßer #define BC_HAS_UNREACHABLE (1) 27644d4804dSStefan Eßer #endif // __clang_major__ >= 4 27744d4804dSStefan Eßer 278d101cdd6SStefan Eßer #endif // BC_GCC 27944d4804dSStefan Eßer 28044d4804dSStefan Eßer #else // defined(__has_attribute) 28144d4804dSStefan Eßer #define BC_FALLTHROUGH 28244d4804dSStefan Eßer #endif // defined(__has_attribute) 283d101cdd6SStefan Eßer #else // BC_CLANG || BC_GCC 28444d4804dSStefan Eßer #define BC_FALLTHROUGH 285d101cdd6SStefan Eßer #endif // BC_CLANG || BC_GCC 28644d4804dSStefan Eßer 28744d4804dSStefan Eßer #if BC_HAS_UNREACHABLE 28844d4804dSStefan Eßer 28944d4804dSStefan Eßer #define BC_UNREACHABLE __builtin_unreachable(); 29044d4804dSStefan Eßer 29144d4804dSStefan Eßer #else // BC_HAS_UNREACHABLE 29244d4804dSStefan Eßer 29344d4804dSStefan Eßer #ifdef _WIN32 29444d4804dSStefan Eßer 29544d4804dSStefan Eßer #define BC_UNREACHABLE __assume(0); 29644d4804dSStefan Eßer 29744d4804dSStefan Eßer #else // _WIN32 29844d4804dSStefan Eßer 29944d4804dSStefan Eßer #define BC_UNREACHABLE 30044d4804dSStefan Eßer 30144d4804dSStefan Eßer #endif // _WIN32 30244d4804dSStefan Eßer 30344d4804dSStefan Eßer #endif // BC_HAS_UNREACHABLE 30444d4804dSStefan Eßer 305d101cdd6SStefan Eßer #if BC_GCC 30644d4804dSStefan Eßer 30744d4804dSStefan Eßer #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) 30844d4804dSStefan Eßer 30944d4804dSStefan Eßer #undef BC_HAS_COMPUTED_GOTO 31044d4804dSStefan Eßer #define BC_HAS_COMPUTED_GOTO (1) 31144d4804dSStefan Eßer 31244d4804dSStefan Eßer #endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) 31344d4804dSStefan Eßer 314d101cdd6SStefan Eßer #endif // BC_GCC 31544d4804dSStefan Eßer 316d101cdd6SStefan Eßer #if BC_CLANG 31744d4804dSStefan Eßer 31844d4804dSStefan Eßer #if __clang_major__ >= 4 31944d4804dSStefan Eßer 32044d4804dSStefan Eßer #undef BC_HAS_COMPUTED_GOTO 32144d4804dSStefan Eßer #define BC_HAS_COMPUTED_GOTO (1) 32244d4804dSStefan Eßer 32344d4804dSStefan Eßer #endif // __clang_major__ >= 4 32444d4804dSStefan Eßer 325d101cdd6SStefan Eßer #endif // BC_CLANG 32644d4804dSStefan Eßer 32744d4804dSStefan Eßer #ifdef BC_NO_COMPUTED_GOTO 32844d4804dSStefan Eßer 32944d4804dSStefan Eßer #undef BC_HAS_COMPUTED_GOTO 33044d4804dSStefan Eßer #define BC_HAS_COMPUTED_GOTO (0) 33144d4804dSStefan Eßer 33244d4804dSStefan Eßer #endif // BC_NO_COMPUTED_GOTO 33344d4804dSStefan Eßer 334d101cdd6SStefan Eßer #if BC_GCC 33544d4804dSStefan Eßer #ifdef __OpenBSD__ 33644d4804dSStefan Eßer // The OpenBSD GCC doesn't like inline. 33744d4804dSStefan Eßer #define inline 33844d4804dSStefan Eßer #endif // __OpenBSD__ 339d101cdd6SStefan Eßer #endif // BC_GCC 34044d4804dSStefan Eßer 34144d4804dSStefan Eßer // Workarounds for AIX's POSIX incompatibility. 34244d4804dSStefan Eßer #ifndef SIZE_MAX 34344d4804dSStefan Eßer #define SIZE_MAX __SIZE_MAX__ 34444d4804dSStefan Eßer #endif // SIZE_MAX 34544d4804dSStefan Eßer #ifndef UINTMAX_C 34644d4804dSStefan Eßer #define UINTMAX_C __UINTMAX_C 34744d4804dSStefan Eßer #endif // UINTMAX_C 34844d4804dSStefan Eßer #ifndef UINT32_C 34944d4804dSStefan Eßer #define UINT32_C __UINT32_C 35044d4804dSStefan Eßer #endif // UINT32_C 35144d4804dSStefan Eßer #ifndef UINT_FAST32_MAX 35244d4804dSStefan Eßer #define UINT_FAST32_MAX __UINT_FAST32_MAX__ 35344d4804dSStefan Eßer #endif // UINT_FAST32_MAX 35444d4804dSStefan Eßer #ifndef UINT16_MAX 35544d4804dSStefan Eßer #define UINT16_MAX __UINT16_MAX__ 35644d4804dSStefan Eßer #endif // UINT16_MAX 35744d4804dSStefan Eßer #ifndef SIG_ATOMIC_MAX 35844d4804dSStefan Eßer #define SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__ 35944d4804dSStefan Eßer #endif // SIG_ATOMIC_MAX 36044d4804dSStefan Eßer 36144d4804dSStefan Eßer // Yes, this has to be here. 36250696a6eSStefan Eßer #include <bcl.h> 36350696a6eSStefan Eßer 36444d4804dSStefan Eßer // All of these set defaults for settings. 36544d4804dSStefan Eßer 36644d4804dSStefan Eßer #if BC_ENABLED 36744d4804dSStefan Eßer 36844d4804dSStefan Eßer #ifndef BC_DEFAULT_BANNER 36944d4804dSStefan Eßer #define BC_DEFAULT_BANNER (0) 37044d4804dSStefan Eßer #endif // BC_DEFAULT_BANNER 37144d4804dSStefan Eßer 37244d4804dSStefan Eßer #endif // BC_ENABLED 37344d4804dSStefan Eßer 37444d4804dSStefan Eßer #ifndef BC_DEFAULT_SIGINT_RESET 37544d4804dSStefan Eßer #define BC_DEFAULT_SIGINT_RESET (1) 37644d4804dSStefan Eßer #endif // BC_DEFAULT_SIGINT_RESET 37744d4804dSStefan Eßer 37844d4804dSStefan Eßer #ifndef BC_DEFAULT_TTY_MODE 37944d4804dSStefan Eßer #define BC_DEFAULT_TTY_MODE (1) 38044d4804dSStefan Eßer #endif // BC_DEFAULT_TTY_MODE 38144d4804dSStefan Eßer 38244d4804dSStefan Eßer #ifndef BC_DEFAULT_PROMPT 38344d4804dSStefan Eßer #define BC_DEFAULT_PROMPT BC_DEFAULT_TTY_MODE 38444d4804dSStefan Eßer #endif // BC_DEFAULT_PROMPT 38544d4804dSStefan Eßer 38610041e99SStefan Eßer #ifndef BC_DEFAULT_EXPR_EXIT 38710041e99SStefan Eßer #define BC_DEFAULT_EXPR_EXIT (1) 38810041e99SStefan Eßer #endif // BC_DEFAULT_EXPR_EXIT 38910041e99SStefan Eßer 390d101cdd6SStefan Eßer #ifndef BC_DEFAULT_DIGIT_CLAMP 391d101cdd6SStefan Eßer #define BC_DEFAULT_DIGIT_CLAMP (0) 392d101cdd6SStefan Eßer #endif // BC_DEFAULT_DIGIT_CLAMP 393d101cdd6SStefan Eßer 39444d4804dSStefan Eßer // All of these set defaults for settings. 39544d4804dSStefan Eßer #ifndef DC_DEFAULT_SIGINT_RESET 39644d4804dSStefan Eßer #define DC_DEFAULT_SIGINT_RESET (1) 39744d4804dSStefan Eßer #endif // DC_DEFAULT_SIGINT_RESET 39844d4804dSStefan Eßer 39944d4804dSStefan Eßer #ifndef DC_DEFAULT_TTY_MODE 40044d4804dSStefan Eßer #define DC_DEFAULT_TTY_MODE (0) 40144d4804dSStefan Eßer #endif // DC_DEFAULT_TTY_MODE 40244d4804dSStefan Eßer 40344d4804dSStefan Eßer #ifndef DC_DEFAULT_HISTORY 40444d4804dSStefan Eßer #define DC_DEFAULT_HISTORY DC_DEFAULT_TTY_MODE 40544d4804dSStefan Eßer #endif // DC_DEFAULT_HISTORY 40644d4804dSStefan Eßer 40744d4804dSStefan Eßer #ifndef DC_DEFAULT_PROMPT 40844d4804dSStefan Eßer #define DC_DEFAULT_PROMPT DC_DEFAULT_TTY_MODE 40944d4804dSStefan Eßer #endif // DC_DEFAULT_PROMPT 41044d4804dSStefan Eßer 41110041e99SStefan Eßer #ifndef DC_DEFAULT_EXPR_EXIT 41210041e99SStefan Eßer #define DC_DEFAULT_EXPR_EXIT (1) 41310041e99SStefan Eßer #endif // DC_DEFAULT_EXPR_EXIT 41410041e99SStefan Eßer 415d101cdd6SStefan Eßer #ifndef DC_DEFAULT_DIGIT_CLAMP 416d101cdd6SStefan Eßer #define DC_DEFAULT_DIGIT_CLAMP (0) 417d101cdd6SStefan Eßer #endif // DC_DEFAULT_DIGIT_CLAMP 418d101cdd6SStefan Eßer 41944d4804dSStefan Eßer /// Statuses, which mark either which category of error happened, or some other 42044d4804dSStefan Eßer /// status that matters. 42178bc019dSStefan Eßer typedef enum BcStatus 42278bc019dSStefan Eßer { 42344d4804dSStefan Eßer /// Normal status. 424252884aeSStefan Eßer BC_STATUS_SUCCESS = 0, 42544d4804dSStefan Eßer 42644d4804dSStefan Eßer /// Math error. 427252884aeSStefan Eßer BC_STATUS_ERROR_MATH, 42844d4804dSStefan Eßer 42944d4804dSStefan Eßer /// Parse (and lex) error. 430252884aeSStefan Eßer BC_STATUS_ERROR_PARSE, 43144d4804dSStefan Eßer 43244d4804dSStefan Eßer /// Runtime error. 433252884aeSStefan Eßer BC_STATUS_ERROR_EXEC, 43444d4804dSStefan Eßer 43544d4804dSStefan Eßer /// Fatal error. 436252884aeSStefan Eßer BC_STATUS_ERROR_FATAL, 43744d4804dSStefan Eßer 43844d4804dSStefan Eßer /// EOF status. 439252884aeSStefan Eßer BC_STATUS_EOF, 44044d4804dSStefan Eßer 44144d4804dSStefan Eßer /// Quit status. This means that bc/dc is in the process of quitting. 442252884aeSStefan Eßer BC_STATUS_QUIT, 443252884aeSStefan Eßer 444252884aeSStefan Eßer } BcStatus; 445252884aeSStefan Eßer 44644d4804dSStefan Eßer /// Errors, which are more specific errors. 44778bc019dSStefan Eßer typedef enum BcErr 44878bc019dSStefan Eßer { 44944d4804dSStefan Eßer // Math errors. 45044d4804dSStefan Eßer 45144d4804dSStefan Eßer /// Negative number used when not allowed. 45250696a6eSStefan Eßer BC_ERR_MATH_NEGATIVE, 45344d4804dSStefan Eßer 45444d4804dSStefan Eßer /// Non-integer used when not allowed. 45550696a6eSStefan Eßer BC_ERR_MATH_NON_INTEGER, 45644d4804dSStefan Eßer 45744d4804dSStefan Eßer /// Conversion to a hardware integer would overflow. 45850696a6eSStefan Eßer BC_ERR_MATH_OVERFLOW, 45944d4804dSStefan Eßer 46044d4804dSStefan Eßer /// Divide by zero. 46150696a6eSStefan Eßer BC_ERR_MATH_DIVIDE_BY_ZERO, 462252884aeSStefan Eßer 46344d4804dSStefan Eßer // Fatal errors. 46444d4804dSStefan Eßer 46544d4804dSStefan Eßer /// An allocation or reallocation failed. 46650696a6eSStefan Eßer BC_ERR_FATAL_ALLOC_ERR, 46744d4804dSStefan Eßer 46844d4804dSStefan Eßer /// I/O failure. 46950696a6eSStefan Eßer BC_ERR_FATAL_IO_ERR, 47044d4804dSStefan Eßer 47144d4804dSStefan Eßer /// File error, such as permissions or file does not exist. 47250696a6eSStefan Eßer BC_ERR_FATAL_FILE_ERR, 47344d4804dSStefan Eßer 47444d4804dSStefan Eßer /// File is binary, not text, error. 47550696a6eSStefan Eßer BC_ERR_FATAL_BIN_FILE, 47644d4804dSStefan Eßer 47744d4804dSStefan Eßer /// Attempted to read a directory as a file error. 47850696a6eSStefan Eßer BC_ERR_FATAL_PATH_DIR, 47944d4804dSStefan Eßer 48044d4804dSStefan Eßer /// Invalid option error. 48150696a6eSStefan Eßer BC_ERR_FATAL_OPTION, 48244d4804dSStefan Eßer 48344d4804dSStefan Eßer /// Option with required argument not given an argument. 48450696a6eSStefan Eßer BC_ERR_FATAL_OPTION_NO_ARG, 48544d4804dSStefan Eßer 48644d4804dSStefan Eßer /// Option with no argument given an argument. 48750696a6eSStefan Eßer BC_ERR_FATAL_OPTION_ARG, 488252884aeSStefan Eßer 48944d4804dSStefan Eßer /// Option argument is invalid. 49044d4804dSStefan Eßer BC_ERR_FATAL_ARG, 49144d4804dSStefan Eßer 49244d4804dSStefan Eßer // Runtime errors. 49344d4804dSStefan Eßer 49444d4804dSStefan Eßer /// Invalid ibase value. 49550696a6eSStefan Eßer BC_ERR_EXEC_IBASE, 49644d4804dSStefan Eßer 49744d4804dSStefan Eßer /// Invalid obase value. 49850696a6eSStefan Eßer BC_ERR_EXEC_OBASE, 49944d4804dSStefan Eßer 50044d4804dSStefan Eßer /// Invalid scale value. 50150696a6eSStefan Eßer BC_ERR_EXEC_SCALE, 50244d4804dSStefan Eßer 50344d4804dSStefan Eßer /// Invalid expression parsed by read(). 50450696a6eSStefan Eßer BC_ERR_EXEC_READ_EXPR, 50544d4804dSStefan Eßer 50644d4804dSStefan Eßer /// read() used within an expression given to a read() call. 50750696a6eSStefan Eßer BC_ERR_EXEC_REC_READ, 50844d4804dSStefan Eßer 50944d4804dSStefan Eßer /// Type error. 51050696a6eSStefan Eßer BC_ERR_EXEC_TYPE, 511252884aeSStefan Eßer 51244d4804dSStefan Eßer /// Stack has too few elements error. 51350696a6eSStefan Eßer BC_ERR_EXEC_STACK, 514252884aeSStefan Eßer 51544d4804dSStefan Eßer /// Register stack has too few elements error. 51644d4804dSStefan Eßer BC_ERR_EXEC_STACK_REGISTER, 51744d4804dSStefan Eßer 51844d4804dSStefan Eßer /// Wrong number of arguments error. 51950696a6eSStefan Eßer BC_ERR_EXEC_PARAMS, 52044d4804dSStefan Eßer 52144d4804dSStefan Eßer /// Undefined function error. 52250696a6eSStefan Eßer BC_ERR_EXEC_UNDEF_FUNC, 52344d4804dSStefan Eßer 52444d4804dSStefan Eßer /// Void value used in an expression error. 52550696a6eSStefan Eßer BC_ERR_EXEC_VOID_VAL, 526252884aeSStefan Eßer 52723210c9fSStefan Eßer // Parse (and lex) errors. 52844d4804dSStefan Eßer 52944d4804dSStefan Eßer /// EOF encountered when not expected error. 53050696a6eSStefan Eßer BC_ERR_PARSE_EOF, 53144d4804dSStefan Eßer 53244d4804dSStefan Eßer /// Invalid character error. 53350696a6eSStefan Eßer BC_ERR_PARSE_CHAR, 53444d4804dSStefan Eßer 53544d4804dSStefan Eßer /// Invalid string (no ending quote) error. 53650696a6eSStefan Eßer BC_ERR_PARSE_STRING, 53744d4804dSStefan Eßer 53844d4804dSStefan Eßer /// Invalid comment (no end found) error. 53950696a6eSStefan Eßer BC_ERR_PARSE_COMMENT, 54044d4804dSStefan Eßer 54144d4804dSStefan Eßer /// Invalid token encountered error. 54250696a6eSStefan Eßer BC_ERR_PARSE_TOKEN, 54344d4804dSStefan Eßer 544252884aeSStefan Eßer #if BC_ENABLED 54544d4804dSStefan Eßer 54644d4804dSStefan Eßer /// Invalid expression error. 54750696a6eSStefan Eßer BC_ERR_PARSE_EXPR, 54844d4804dSStefan Eßer 54944d4804dSStefan Eßer /// Expression is empty error. 55050696a6eSStefan Eßer BC_ERR_PARSE_EMPTY_EXPR, 55144d4804dSStefan Eßer 55244d4804dSStefan Eßer /// Print statement is invalid error. 55350696a6eSStefan Eßer BC_ERR_PARSE_PRINT, 55444d4804dSStefan Eßer 55544d4804dSStefan Eßer /// Function definition is invalid error. 55650696a6eSStefan Eßer BC_ERR_PARSE_FUNC, 55744d4804dSStefan Eßer 55844d4804dSStefan Eßer /// Assignment is invalid error. 55950696a6eSStefan Eßer BC_ERR_PARSE_ASSIGN, 56044d4804dSStefan Eßer 56144d4804dSStefan Eßer /// No auto identifiers given for an auto statement error. 56250696a6eSStefan Eßer BC_ERR_PARSE_NO_AUTO, 56344d4804dSStefan Eßer 56444d4804dSStefan Eßer /// Duplicate local (parameter or auto) error. 56550696a6eSStefan Eßer BC_ERR_PARSE_DUP_LOCAL, 56644d4804dSStefan Eßer 56744d4804dSStefan Eßer /// Invalid block (within braces) error. 56850696a6eSStefan Eßer BC_ERR_PARSE_BLOCK, 56944d4804dSStefan Eßer 57044d4804dSStefan Eßer /// Invalid return statement for void functions. 57150696a6eSStefan Eßer BC_ERR_PARSE_RET_VOID, 57244d4804dSStefan Eßer 57344d4804dSStefan Eßer /// Reference attached to a variable, not an array, error. 57450696a6eSStefan Eßer BC_ERR_PARSE_REF_VAR, 575252884aeSStefan Eßer 57644d4804dSStefan Eßer // POSIX-only errors. 57744d4804dSStefan Eßer 57844d4804dSStefan Eßer /// Name length greater than 1 error. 57950696a6eSStefan Eßer BC_ERR_POSIX_NAME_LEN, 58044d4804dSStefan Eßer 58144d4804dSStefan Eßer /// Non-POSIX comment used error. 58250696a6eSStefan Eßer BC_ERR_POSIX_COMMENT, 58344d4804dSStefan Eßer 58444d4804dSStefan Eßer /// Non-POSIX keyword error. 58550696a6eSStefan Eßer BC_ERR_POSIX_KW, 58644d4804dSStefan Eßer 58744d4804dSStefan Eßer /// Non-POSIX . (last) error. 58850696a6eSStefan Eßer BC_ERR_POSIX_DOT, 58944d4804dSStefan Eßer 59044d4804dSStefan Eßer /// Non-POSIX return error. 59150696a6eSStefan Eßer BC_ERR_POSIX_RET, 59244d4804dSStefan Eßer 59344d4804dSStefan Eßer /// Non-POSIX boolean operator used error. 59450696a6eSStefan Eßer BC_ERR_POSIX_BOOL, 59544d4804dSStefan Eßer 59644d4804dSStefan Eßer /// POSIX relation operator used outside if, while, or for statements error. 59750696a6eSStefan Eßer BC_ERR_POSIX_REL_POS, 59844d4804dSStefan Eßer 59944d4804dSStefan Eßer /// Multiple POSIX relation operators used in an if, while, or for statement 60044d4804dSStefan Eßer /// error. 60150696a6eSStefan Eßer BC_ERR_POSIX_MULTIREL, 60244d4804dSStefan Eßer 60344d4804dSStefan Eßer /// Empty statements in POSIX for loop error. 60450696a6eSStefan Eßer BC_ERR_POSIX_FOR, 60544d4804dSStefan Eßer 60610041e99SStefan Eßer /// POSIX's grammar does not allow a function definition right after a 60710041e99SStefan Eßer /// semicolon. 60810041e99SStefan Eßer BC_ERR_POSIX_FUNC_AFTER_SEMICOLON, 60910041e99SStefan Eßer 61044d4804dSStefan Eßer /// Non-POSIX exponential (scientific or engineering) number used error. 61150696a6eSStefan Eßer BC_ERR_POSIX_EXP_NUM, 61244d4804dSStefan Eßer 61344d4804dSStefan Eßer /// Non-POSIX array reference error. 61450696a6eSStefan Eßer BC_ERR_POSIX_REF, 61544d4804dSStefan Eßer 61644d4804dSStefan Eßer /// Non-POSIX void error. 61750696a6eSStefan Eßer BC_ERR_POSIX_VOID, 61844d4804dSStefan Eßer 61944d4804dSStefan Eßer /// Non-POSIX brace position used error. 62050696a6eSStefan Eßer BC_ERR_POSIX_BRACE, 62144d4804dSStefan Eßer 62244d4804dSStefan Eßer /// String used in expression. 62344d4804dSStefan Eßer BC_ERR_POSIX_EXPR_STRING, 62444d4804dSStefan Eßer 625252884aeSStefan Eßer #endif // BC_ENABLED 626252884aeSStefan Eßer 62744d4804dSStefan Eßer // Number of elements. 62850696a6eSStefan Eßer BC_ERR_NELEMS, 629252884aeSStefan Eßer 630252884aeSStefan Eßer #if BC_ENABLED 63144d4804dSStefan Eßer 63244d4804dSStefan Eßer /// A marker for the start of POSIX errors. 63350696a6eSStefan Eßer BC_ERR_POSIX_START = BC_ERR_POSIX_NAME_LEN, 63444d4804dSStefan Eßer 63544d4804dSStefan Eßer /// A marker for the end of POSIX errors. 63644d4804dSStefan Eßer BC_ERR_POSIX_END = BC_ERR_POSIX_EXPR_STRING, 63744d4804dSStefan Eßer 638252884aeSStefan Eßer #endif // BC_ENABLED 639252884aeSStefan Eßer 64050696a6eSStefan Eßer } BcErr; 641252884aeSStefan Eßer 64244d4804dSStefan Eßer // The indices of each category of error in bc_errs[], and used in bc_err_ids[] 64344d4804dSStefan Eßer // to associate actual errors with their categories. 64444d4804dSStefan Eßer 64544d4804dSStefan Eßer /// Math error category. 646252884aeSStefan Eßer #define BC_ERR_IDX_MATH (0) 64744d4804dSStefan Eßer 64844d4804dSStefan Eßer /// Parse (and lex) error category. 649252884aeSStefan Eßer #define BC_ERR_IDX_PARSE (1) 65044d4804dSStefan Eßer 65144d4804dSStefan Eßer /// Runtime error category. 652252884aeSStefan Eßer #define BC_ERR_IDX_EXEC (2) 65344d4804dSStefan Eßer 65444d4804dSStefan Eßer /// Fatal error category. 655252884aeSStefan Eßer #define BC_ERR_IDX_FATAL (3) 65644d4804dSStefan Eßer 65744d4804dSStefan Eßer /// Number of categories. 658252884aeSStefan Eßer #define BC_ERR_IDX_NELEMS (4) 659252884aeSStefan Eßer 66044d4804dSStefan Eßer // If bc is enabled, we add an extra category for POSIX warnings. 661252884aeSStefan Eßer #if BC_ENABLED 66244d4804dSStefan Eßer 66344d4804dSStefan Eßer /// POSIX warning category. 664252884aeSStefan Eßer #define BC_ERR_IDX_WARN (BC_ERR_IDX_NELEMS) 66544d4804dSStefan Eßer 666252884aeSStefan Eßer #endif // BC_ENABLED 667252884aeSStefan Eßer 668d101cdd6SStefan Eßer /** 669d101cdd6SStefan Eßer * The mode bc is in. This is basically what input it is processing. 670d101cdd6SStefan Eßer */ 671d101cdd6SStefan Eßer typedef enum BcMode 672d101cdd6SStefan Eßer { 673d101cdd6SStefan Eßer /// Expressions mode. 674d101cdd6SStefan Eßer BC_MODE_EXPRS, 675d101cdd6SStefan Eßer 676d101cdd6SStefan Eßer /// File mode. 677d101cdd6SStefan Eßer BC_MODE_FILE, 678d101cdd6SStefan Eßer 679d101cdd6SStefan Eßer /// stdin mode. 680d101cdd6SStefan Eßer BC_MODE_STDIN, 681d101cdd6SStefan Eßer 682d101cdd6SStefan Eßer } BcMode; 683d101cdd6SStefan Eßer 68444d4804dSStefan Eßer /// Do a longjmp(). This is what to use when activating an "exception", i.e., a 68544d4804dSStefan Eßer /// longjmp(). With debug code, it will print the name of the function it jumped 68644d4804dSStefan Eßer /// from. 68744d4804dSStefan Eßer #if BC_DEBUG_CODE 68844d4804dSStefan Eßer #define BC_JMP bc_vm_jmp(__func__) 68944d4804dSStefan Eßer #else // BC_DEBUG_CODE 69044d4804dSStefan Eßer #define BC_JMP bc_vm_jmp() 69144d4804dSStefan Eßer #endif // BC_DEBUG_CODE 69244d4804dSStefan Eßer 693d101cdd6SStefan Eßer #if !BC_ENABLE_LIBRARY 694d101cdd6SStefan Eßer 69544d4804dSStefan Eßer /// Returns true if an exception is in flight, false otherwise. 696d101cdd6SStefan Eßer #define BC_SIG_EXC(vm) \ 697d101cdd6SStefan Eßer BC_UNLIKELY((vm)->status != (sig_atomic_t) BC_STATUS_SUCCESS || (vm)->sig) 69844d4804dSStefan Eßer 69944d4804dSStefan Eßer /// Returns true if there is *no* exception in flight, false otherwise. 700d101cdd6SStefan Eßer #define BC_NO_SIG_EXC(vm) \ 701d101cdd6SStefan Eßer BC_LIKELY((vm)->status == (sig_atomic_t) BC_STATUS_SUCCESS && !(vm)->sig) 702d101cdd6SStefan Eßer 703d101cdd6SStefan Eßer #ifndef _WIN32 704d101cdd6SStefan Eßer #define BC_SIG_INTERRUPT(vm) \ 705d101cdd6SStefan Eßer BC_UNLIKELY((vm)->sig != 0 && (vm)->sig != SIGWINCH) 706d101cdd6SStefan Eßer #else // _WIN32 707d101cdd6SStefan Eßer #define BC_SIG_INTERRUPT(vm) BC_UNLIKELY((vm)->sig != 0) 708d101cdd6SStefan Eßer #endif // _WIN32 70944d4804dSStefan Eßer 710103d7cdfSStefan Eßer #if BC_DEBUG 71144d4804dSStefan Eßer 71244d4804dSStefan Eßer /// Assert that signals are locked. There are non-async-signal-safe functions in 71344d4804dSStefan Eßer /// bc, and they *must* have signals locked. Other functions are expected to 71444d4804dSStefan Eßer /// *not* have signals locked, for reasons. So this is a pre-built assert 71544d4804dSStefan Eßer /// (no-op in non-debug mode) that check that signals are locked. 71678bc019dSStefan Eßer #define BC_SIG_ASSERT_LOCKED \ 71778bc019dSStefan Eßer do \ 71878bc019dSStefan Eßer { \ 719d101cdd6SStefan Eßer assert(vm->sig_lock); \ 72078bc019dSStefan Eßer } \ 72178bc019dSStefan Eßer while (0) 72244d4804dSStefan Eßer 72344d4804dSStefan Eßer /// Assert that signals are unlocked. There are non-async-signal-safe functions 72444d4804dSStefan Eßer /// in bc, and they *must* have signals locked. Other functions are expected to 72544d4804dSStefan Eßer /// *not* have signals locked, for reasons. So this is a pre-built assert 72644d4804dSStefan Eßer /// (no-op in non-debug mode) that check that signals are unlocked. 72778bc019dSStefan Eßer #define BC_SIG_ASSERT_NOT_LOCKED \ 72878bc019dSStefan Eßer do \ 72978bc019dSStefan Eßer { \ 730d101cdd6SStefan Eßer assert(vm->sig_lock == 0); \ 73178bc019dSStefan Eßer } \ 73278bc019dSStefan Eßer while (0) 73344d4804dSStefan Eßer 734103d7cdfSStefan Eßer #else // BC_DEBUG 73544d4804dSStefan Eßer 73644d4804dSStefan Eßer /// Assert that signals are locked. There are non-async-signal-safe functions in 73744d4804dSStefan Eßer /// bc, and they *must* have signals locked. Other functions are expected to 73844d4804dSStefan Eßer /// *not* have signals locked, for reasons. So this is a pre-built assert 73944d4804dSStefan Eßer /// (no-op in non-debug mode) that check that signals are locked. 74044d4804dSStefan Eßer #define BC_SIG_ASSERT_LOCKED 74144d4804dSStefan Eßer 74244d4804dSStefan Eßer /// Assert that signals are unlocked. There are non-async-signal-safe functions 74344d4804dSStefan Eßer /// in bc, and they *must* have signals locked. Other functions are expected to 74444d4804dSStefan Eßer /// *not* have signals locked, for reasons. So this is a pre-built assert 74544d4804dSStefan Eßer /// (no-op in non-debug mode) that check that signals are unlocked. 74644d4804dSStefan Eßer #define BC_SIG_ASSERT_NOT_LOCKED 74744d4804dSStefan Eßer 748103d7cdfSStefan Eßer #endif // BC_DEBUG 74944d4804dSStefan Eßer 75044d4804dSStefan Eßer /// Locks signals. 75144d4804dSStefan Eßer #define BC_SIG_LOCK \ 75278bc019dSStefan Eßer do \ 75378bc019dSStefan Eßer { \ 75444d4804dSStefan Eßer BC_SIG_ASSERT_NOT_LOCKED; \ 755d101cdd6SStefan Eßer vm->sig_lock = 1; \ 75678bc019dSStefan Eßer } \ 75778bc019dSStefan Eßer while (0) 75844d4804dSStefan Eßer 75944d4804dSStefan Eßer /// Unlocks signals. If a signal happened, then this will cause a jump. 76044d4804dSStefan Eßer #define BC_SIG_UNLOCK \ 76178bc019dSStefan Eßer do \ 76278bc019dSStefan Eßer { \ 76344d4804dSStefan Eßer BC_SIG_ASSERT_LOCKED; \ 764d101cdd6SStefan Eßer vm->sig_lock = 0; \ 765d101cdd6SStefan Eßer if (vm->sig) BC_JMP; \ 76678bc019dSStefan Eßer } \ 76778bc019dSStefan Eßer while (0) 76844d4804dSStefan Eßer 76944d4804dSStefan Eßer /// Locks signals, regardless of if they are already locked. This is really only 77044d4804dSStefan Eßer /// used after labels that longjmp() goes to after the jump because the cleanup 77144d4804dSStefan Eßer /// code must have signals locked, and BC_LONGJMP_CONT will unlock signals if it 77244d4804dSStefan Eßer /// doesn't jump. 77344d4804dSStefan Eßer #define BC_SIG_MAYLOCK \ 77478bc019dSStefan Eßer do \ 77578bc019dSStefan Eßer { \ 776d101cdd6SStefan Eßer vm->sig_lock = 1; \ 77778bc019dSStefan Eßer } \ 77878bc019dSStefan Eßer while (0) 77944d4804dSStefan Eßer 78044d4804dSStefan Eßer /// Unlocks signals, regardless of if they were already unlocked. If a signal 78144d4804dSStefan Eßer /// happened, then this will cause a jump. 78244d4804dSStefan Eßer #define BC_SIG_MAYUNLOCK \ 78378bc019dSStefan Eßer do \ 78478bc019dSStefan Eßer { \ 785d101cdd6SStefan Eßer vm->sig_lock = 0; \ 786d101cdd6SStefan Eßer if (vm->sig) BC_JMP; \ 78778bc019dSStefan Eßer } \ 78878bc019dSStefan Eßer while (0) 78944d4804dSStefan Eßer 790d101cdd6SStefan Eßer /** 79144d4804dSStefan Eßer * Locks signals, but stores the old lock state, to be restored later by 79244d4804dSStefan Eßer * BC_SIG_TRYUNLOCK. 79344d4804dSStefan Eßer * @param v The variable to store the old lock state to. 79444d4804dSStefan Eßer */ 79544d4804dSStefan Eßer #define BC_SIG_TRYLOCK(v) \ 79678bc019dSStefan Eßer do \ 79778bc019dSStefan Eßer { \ 798d101cdd6SStefan Eßer v = vm->sig_lock; \ 799d101cdd6SStefan Eßer vm->sig_lock = 1; \ 80078bc019dSStefan Eßer } \ 80178bc019dSStefan Eßer while (0) 80244d4804dSStefan Eßer 803d101cdd6SStefan Eßer /** 804d101cdd6SStefan Eßer * Restores the previous state of a signal lock, and if it is now unlocked, 80544d4804dSStefan Eßer * initiates an exception/jump. 80644d4804dSStefan Eßer * @param v The old lock state. 80744d4804dSStefan Eßer */ 80844d4804dSStefan Eßer #define BC_SIG_TRYUNLOCK(v) \ 80978bc019dSStefan Eßer do \ 81078bc019dSStefan Eßer { \ 811d101cdd6SStefan Eßer vm->sig_lock = (v); \ 812d101cdd6SStefan Eßer if (!(v) && vm->sig) BC_JMP; \ 81378bc019dSStefan Eßer } \ 81478bc019dSStefan Eßer while (0) 81544d4804dSStefan Eßer 816d101cdd6SStefan Eßer /// Stops a stack unwinding. Technically, a stack unwinding needs to be done 817d101cdd6SStefan Eßer /// manually, but it will always be done unless certain flags are cleared. This 818d101cdd6SStefan Eßer /// clears the flags. 819d101cdd6SStefan Eßer #define BC_LONGJMP_STOP \ 820d101cdd6SStefan Eßer do \ 821d101cdd6SStefan Eßer { \ 822d101cdd6SStefan Eßer vm->sig_pop = 0; \ 823d101cdd6SStefan Eßer vm->sig = 0; \ 824d101cdd6SStefan Eßer } \ 825d101cdd6SStefan Eßer while (0) 826d101cdd6SStefan Eßer 827d101cdd6SStefan Eßer /** 828d101cdd6SStefan Eßer * Sets a jump like BC_SETJMP, but unlike BC_SETJMP, it assumes signals are 829d101cdd6SStefan Eßer * locked and will just set the jump. This does *not* have a call to 830d101cdd6SStefan Eßer * bc_vec_grow() because it is assumed that BC_SETJMP_LOCKED(l) is used *after* 831d101cdd6SStefan Eßer * the initializations that need the setjmp(). 832d101cdd6SStefan Eßer * param l The label to jump to on a longjmp(). 833d101cdd6SStefan Eßer */ 834d101cdd6SStefan Eßer #define BC_SETJMP_LOCKED(vm, l) \ 835d101cdd6SStefan Eßer do \ 836d101cdd6SStefan Eßer { \ 837d101cdd6SStefan Eßer sigjmp_buf sjb; \ 838d101cdd6SStefan Eßer BC_SIG_ASSERT_LOCKED; \ 839d101cdd6SStefan Eßer if (sigsetjmp(sjb, 0)) \ 840d101cdd6SStefan Eßer { \ 841d101cdd6SStefan Eßer assert(BC_SIG_EXC(vm)); \ 842d101cdd6SStefan Eßer goto l; \ 843d101cdd6SStefan Eßer } \ 844d101cdd6SStefan Eßer bc_vec_push(&vm->jmp_bufs, &sjb); \ 845d101cdd6SStefan Eßer } \ 846d101cdd6SStefan Eßer while (0) 847d101cdd6SStefan Eßer 848d101cdd6SStefan Eßer /// Used after cleanup labels set by BC_SETJMP and BC_SETJMP_LOCKED to jump to 849d101cdd6SStefan Eßer /// the next place. This is what continues the stack unwinding. This basically 850d101cdd6SStefan Eßer /// copies BC_SIG_UNLOCK into itself, but that is because its condition for 851d101cdd6SStefan Eßer /// jumping is BC_SIG_EXC, not just that a signal happened. 852d101cdd6SStefan Eßer #define BC_LONGJMP_CONT(vm) \ 853d101cdd6SStefan Eßer do \ 854d101cdd6SStefan Eßer { \ 855d101cdd6SStefan Eßer BC_SIG_ASSERT_LOCKED; \ 856d101cdd6SStefan Eßer if (!vm->sig_pop) bc_vec_pop(&vm->jmp_bufs); \ 857d101cdd6SStefan Eßer vm->sig_lock = 0; \ 858d101cdd6SStefan Eßer if (BC_SIG_EXC(vm)) BC_JMP; \ 859d101cdd6SStefan Eßer } \ 860d101cdd6SStefan Eßer while (0) 861d101cdd6SStefan Eßer 862d101cdd6SStefan Eßer #else // !BC_ENABLE_LIBRARY 863d101cdd6SStefan Eßer 864d101cdd6SStefan Eßer #define BC_SIG_LOCK 865d101cdd6SStefan Eßer #define BC_SIG_UNLOCK 866d101cdd6SStefan Eßer #define BC_SIG_MAYLOCK 867d101cdd6SStefan Eßer #define BC_SIG_TRYLOCK(lock) 868d101cdd6SStefan Eßer #define BC_SIG_TRYUNLOCK(lock) 869d101cdd6SStefan Eßer #define BC_SIG_ASSERT_LOCKED 870d101cdd6SStefan Eßer 871d101cdd6SStefan Eßer /// Returns true if an exception is in flight, false otherwise. 872d101cdd6SStefan Eßer #define BC_SIG_EXC(vm) \ 873d101cdd6SStefan Eßer BC_UNLIKELY(vm->status != (sig_atomic_t) BC_STATUS_SUCCESS) 874d101cdd6SStefan Eßer 875d101cdd6SStefan Eßer /// Returns true if there is *no* exception in flight, false otherwise. 876d101cdd6SStefan Eßer #define BC_NO_SIG_EXC(vm) \ 877d101cdd6SStefan Eßer BC_LIKELY(vm->status == (sig_atomic_t) BC_STATUS_SUCCESS) 878d101cdd6SStefan Eßer 879d101cdd6SStefan Eßer /// Used after cleanup labels set by BC_SETJMP and BC_SETJMP_LOCKED to jump to 880d101cdd6SStefan Eßer /// the next place. This is what continues the stack unwinding. This basically 881d101cdd6SStefan Eßer /// copies BC_SIG_UNLOCK into itself, but that is because its condition for 882d101cdd6SStefan Eßer /// jumping is BC_SIG_EXC, not just that a signal happened. 883d101cdd6SStefan Eßer #define BC_LONGJMP_CONT(vm) \ 884d101cdd6SStefan Eßer do \ 885d101cdd6SStefan Eßer { \ 886d101cdd6SStefan Eßer bc_vec_pop(&vm->jmp_bufs); \ 887d101cdd6SStefan Eßer if (BC_SIG_EXC(vm)) BC_JMP; \ 888d101cdd6SStefan Eßer } \ 889d101cdd6SStefan Eßer while (0) 890d101cdd6SStefan Eßer 891d101cdd6SStefan Eßer #endif // !BC_ENABLE_LIBRARY 892d101cdd6SStefan Eßer 89344d4804dSStefan Eßer /** 89444d4804dSStefan Eßer * Sets a jump, and sets it up as well so that if a longjmp() happens, bc will 89544d4804dSStefan Eßer * immediately goto a label where some cleanup code is. This one assumes that 89644d4804dSStefan Eßer * signals are not locked and will lock them, set the jump, and unlock them. 89744d4804dSStefan Eßer * Setting the jump also includes pushing the jmp_buf onto the jmp_buf stack. 89844d4804dSStefan Eßer * This grows the jmp_bufs vector first to prevent a fatal error from happening 89944d4804dSStefan Eßer * after the setjmp(). This is done because BC_SETJMP(l) is assumed to be used 90044d4804dSStefan Eßer * *before* the actual initialization calls that need the setjmp(). 90144d4804dSStefan Eßer * param l The label to jump to on a longjmp(). 90244d4804dSStefan Eßer */ 903d101cdd6SStefan Eßer #define BC_SETJMP(vm, l) \ 90478bc019dSStefan Eßer do \ 90578bc019dSStefan Eßer { \ 90644d4804dSStefan Eßer sigjmp_buf sjb; \ 90744d4804dSStefan Eßer BC_SIG_LOCK; \ 908d101cdd6SStefan Eßer bc_vec_grow(&vm->jmp_bufs, 1); \ 90978bc019dSStefan Eßer if (sigsetjmp(sjb, 0)) \ 91078bc019dSStefan Eßer { \ 911d101cdd6SStefan Eßer assert(BC_SIG_EXC(vm)); \ 91244d4804dSStefan Eßer goto l; \ 91344d4804dSStefan Eßer } \ 914d101cdd6SStefan Eßer bc_vec_push(&vm->jmp_bufs, &sjb); \ 91544d4804dSStefan Eßer BC_SIG_UNLOCK; \ 91678bc019dSStefan Eßer } \ 91778bc019dSStefan Eßer while (0) 91844d4804dSStefan Eßer 91944d4804dSStefan Eßer /// Unsets a jump. It always assumes signals are locked. This basically just 92044d4804dSStefan Eßer /// pops a jmp_buf off of the stack of jmp_bufs, and since the jump mechanism 92144d4804dSStefan Eßer /// always jumps to the location at the top of the stack, this effectively 92244d4804dSStefan Eßer /// undoes a setjmp(). 923d101cdd6SStefan Eßer #define BC_UNSETJMP(vm) \ 92478bc019dSStefan Eßer do \ 92578bc019dSStefan Eßer { \ 92644d4804dSStefan Eßer BC_SIG_ASSERT_LOCKED; \ 927d101cdd6SStefan Eßer bc_vec_pop(&vm->jmp_bufs); \ 92878bc019dSStefan Eßer } \ 92978bc019dSStefan Eßer while (0) 93044d4804dSStefan Eßer 931d101cdd6SStefan Eßer #if BC_ENABLE_LIBRARY 932d101cdd6SStefan Eßer 933d101cdd6SStefan Eßer #define BC_SETJMP_LOCKED(vm, l) BC_SETJMP(vm, l) 93444d4804dSStefan Eßer 93544d4804dSStefan Eßer // Various convenience macros for calling the bc's error handling routine. 93644d4804dSStefan Eßer 93744d4804dSStefan Eßer /** 93844d4804dSStefan Eßer * Call bc's error handling routine. 93944d4804dSStefan Eßer * @param e The error. 94044d4804dSStefan Eßer * @param l The line of the script that the error happened. 94144d4804dSStefan Eßer * @param ... Extra arguments for error messages as necessary. 94244d4804dSStefan Eßer */ 94344d4804dSStefan Eßer #define bc_error(e, l, ...) (bc_vm_handleError((e))) 94444d4804dSStefan Eßer 94544d4804dSStefan Eßer /** 94644d4804dSStefan Eßer * Call bc's error handling routine. 94744d4804dSStefan Eßer * @param e The error. 94844d4804dSStefan Eßer */ 94944d4804dSStefan Eßer #define bc_err(e) (bc_vm_handleError((e))) 95044d4804dSStefan Eßer 95144d4804dSStefan Eßer /** 95244d4804dSStefan Eßer * Call bc's error handling routine. 95344d4804dSStefan Eßer * @param e The error. 95444d4804dSStefan Eßer */ 95544d4804dSStefan Eßer #define bc_verr(e, ...) (bc_vm_handleError((e))) 95644d4804dSStefan Eßer 95744d4804dSStefan Eßer #else // BC_ENABLE_LIBRARY 95844d4804dSStefan Eßer 959d101cdd6SStefan Eßer // Various convenience macros for calling the bc's error handling routine. 960d101cdd6SStefan Eßer 96144d4804dSStefan Eßer /** 96244d4804dSStefan Eßer * Call bc's error handling routine. 96344d4804dSStefan Eßer * @param e The error. 96444d4804dSStefan Eßer * @param l The line of the script that the error happened. 96544d4804dSStefan Eßer * @param ... Extra arguments for error messages as necessary. 96644d4804dSStefan Eßer */ 967103d7cdfSStefan Eßer #if BC_DEBUG 968d101cdd6SStefan Eßer #define bc_error(e, l, ...) \ 969d101cdd6SStefan Eßer (bc_vm_handleError((e), __FILE__, __LINE__, (l), __VA_ARGS__)) 970103d7cdfSStefan Eßer #else // BC_DEBUG 97144d4804dSStefan Eßer #define bc_error(e, l, ...) (bc_vm_handleError((e), (l), __VA_ARGS__)) 972103d7cdfSStefan Eßer #endif // BC_DEBUG 97344d4804dSStefan Eßer 97444d4804dSStefan Eßer /** 97544d4804dSStefan Eßer * Call bc's error handling routine. 97644d4804dSStefan Eßer * @param e The error. 97744d4804dSStefan Eßer */ 978103d7cdfSStefan Eßer #if BC_DEBUG 979d101cdd6SStefan Eßer #define bc_err(e) (bc_vm_handleError((e), __FILE__, __LINE__, 0)) 980103d7cdfSStefan Eßer #else // BC_DEBUG 98144d4804dSStefan Eßer #define bc_err(e) (bc_vm_handleError((e), 0)) 982103d7cdfSStefan Eßer #endif // BC_DEBUG 98344d4804dSStefan Eßer 98444d4804dSStefan Eßer /** 98544d4804dSStefan Eßer * Call bc's error handling routine. 98644d4804dSStefan Eßer * @param e The error. 98744d4804dSStefan Eßer */ 988103d7cdfSStefan Eßer #if BC_DEBUG 989d101cdd6SStefan Eßer #define bc_verr(e, ...) \ 990d101cdd6SStefan Eßer (bc_vm_handleError((e), __FILE__, __LINE__, 0, __VA_ARGS__)) 991103d7cdfSStefan Eßer #else // BC_DEBUG 99244d4804dSStefan Eßer #define bc_verr(e, ...) (bc_vm_handleError((e), 0, __VA_ARGS__)) 993103d7cdfSStefan Eßer #endif // BC_DEBUG 99444d4804dSStefan Eßer 99544d4804dSStefan Eßer #endif // BC_ENABLE_LIBRARY 99644d4804dSStefan Eßer 99744d4804dSStefan Eßer /** 99844d4804dSStefan Eßer * Returns true if status @a s is an error, false otherwise. 99944d4804dSStefan Eßer * @param s The status to test. 100044d4804dSStefan Eßer * @return True if @a s is an error, false otherwise. 100144d4804dSStefan Eßer */ 100244d4804dSStefan Eßer #define BC_STATUS_IS_ERROR(s) \ 100344d4804dSStefan Eßer ((s) >= BC_STATUS_ERROR_MATH && (s) <= BC_STATUS_ERROR_FATAL) 100444d4804dSStefan Eßer 100544d4804dSStefan Eßer // Convenience macros that can be placed at the beginning and exits of functions 100644d4804dSStefan Eßer // for easy marking of where functions are entered and exited. 100744d4804dSStefan Eßer #if BC_DEBUG_CODE 100844d4804dSStefan Eßer #define BC_FUNC_ENTER \ 100978bc019dSStefan Eßer do \ 101078bc019dSStefan Eßer { \ 101144d4804dSStefan Eßer size_t bc_func_enter_i; \ 1012d101cdd6SStefan Eßer for (bc_func_enter_i = 0; bc_func_enter_i < vm->func_depth; \ 101344d4804dSStefan Eßer ++bc_func_enter_i) \ 101444d4804dSStefan Eßer { \ 1015d101cdd6SStefan Eßer bc_file_puts(&vm->ferr, bc_flush_none, " "); \ 101644d4804dSStefan Eßer } \ 1017d101cdd6SStefan Eßer vm->func_depth += 1; \ 1018d101cdd6SStefan Eßer bc_file_printf(&vm->ferr, "Entering %s\n", __func__); \ 1019d101cdd6SStefan Eßer bc_file_flush(&vm->ferr, bc_flush_none); \ 102078bc019dSStefan Eßer } \ 102178bc019dSStefan Eßer while (0); 102244d4804dSStefan Eßer 102344d4804dSStefan Eßer #define BC_FUNC_EXIT \ 102478bc019dSStefan Eßer do \ 102578bc019dSStefan Eßer { \ 102644d4804dSStefan Eßer size_t bc_func_enter_i; \ 1027d101cdd6SStefan Eßer vm->func_depth -= 1; \ 1028d101cdd6SStefan Eßer for (bc_func_enter_i = 0; bc_func_enter_i < vm->func_depth; \ 102944d4804dSStefan Eßer ++bc_func_enter_i) \ 103044d4804dSStefan Eßer { \ 1031d101cdd6SStefan Eßer bc_file_puts(&vm->ferr, bc_flush_none, " "); \ 103244d4804dSStefan Eßer } \ 1033d101cdd6SStefan Eßer bc_file_printf(&vm->ferr, "Leaving %s\n", __func__); \ 1034d101cdd6SStefan Eßer bc_file_flush(&vm->ferr, bc_flush_none); \ 103578bc019dSStefan Eßer } \ 103678bc019dSStefan Eßer while (0); 103744d4804dSStefan Eßer #else // BC_DEBUG_CODE 103844d4804dSStefan Eßer #define BC_FUNC_ENTER 103944d4804dSStefan Eßer #define BC_FUNC_EXIT 104044d4804dSStefan Eßer #endif // BC_DEBUG_CODE 104144d4804dSStefan Eßer 1042252884aeSStefan Eßer #endif // BC_STATUS_H 1043