xref: /freebsd/contrib/bc/include/status.h (revision 10041e99)
1252884aeSStefan Eßer /*
2252884aeSStefan Eßer  * *****************************************************************************
3252884aeSStefan Eßer  *
43aa99676SStefan Eßer  * SPDX-License-Identifier: BSD-2-Clause
5252884aeSStefan Eßer  *
610328f8bSStefan Eßer  * Copyright (c) 2018-2021 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 
39252884aeSStefan Eßer #include <stdint.h>
40252884aeSStefan Eßer 
4144d4804dSStefan Eßer // This is used by configure.sh to test for OpenBSD.
4244d4804dSStefan Eßer #ifdef BC_TEST_OPENBSD
4344d4804dSStefan Eßer #ifdef __OpenBSD__
4444d4804dSStefan Eßer #error On OpenBSD without _BSD_SOURCE
4544d4804dSStefan Eßer #endif // __OpenBSD__
4644d4804dSStefan Eßer #endif // BC_TEST_OPENBSD
4744d4804dSStefan Eßer 
48252884aeSStefan Eßer #ifndef BC_ENABLED
49252884aeSStefan Eßer #define BC_ENABLED (1)
50252884aeSStefan Eßer #endif // BC_ENABLED
51252884aeSStefan Eßer 
52252884aeSStefan Eßer #ifndef DC_ENABLED
53252884aeSStefan Eßer #define DC_ENABLED (1)
54252884aeSStefan Eßer #endif // DC_ENABLED
55252884aeSStefan Eßer 
56662087dfSStefan Eßer #ifndef BC_ENABLE_LIBRARY
57662087dfSStefan Eßer #define BC_ENABLE_LIBRARY (0)
58662087dfSStefan Eßer #endif // BC_ENABLE_LIBRARY
59662087dfSStefan Eßer 
6044d4804dSStefan Eßer // This is error checking for fuzz builds.
6110328f8bSStefan Eßer #if BC_ENABLE_AFL
6210328f8bSStefan Eßer #ifndef __AFL_HAVE_MANUAL_CONTROL
6344d4804dSStefan Eßer #error Must compile with afl-clang-fast or afl-clang-lto for fuzzing
6410328f8bSStefan Eßer #endif // __AFL_HAVE_MANUAL_CONTROL
6510328f8bSStefan Eßer #endif // BC_ENABLE_AFL
6610328f8bSStefan Eßer 
6710328f8bSStefan Eßer #ifndef BC_ENABLE_MEMCHECK
6810328f8bSStefan Eßer #define BC_ENABLE_MEMCHECK (0)
6910328f8bSStefan Eßer #endif // BC_ENABLE_MEMCHECK
7010328f8bSStefan Eßer 
7144d4804dSStefan Eßer /**
7244d4804dSStefan Eßer  * Mark a variable as unused.
7344d4804dSStefan Eßer  * @param e  The variable to mark as unused.
7444d4804dSStefan Eßer  */
7544d4804dSStefan Eßer #define BC_UNUSED(e) ((void) (e))
7644d4804dSStefan Eßer 
7744d4804dSStefan Eßer // If users want, they can define this to something like __builtin_expect(e, 1).
7844d4804dSStefan Eßer // It might give a performance improvement.
7944d4804dSStefan Eßer #ifndef BC_LIKELY
8044d4804dSStefan Eßer 
8144d4804dSStefan Eßer /**
8244d4804dSStefan Eßer  * Mark a branch expression as likely.
8344d4804dSStefan Eßer  * @param e  The expression to mark as likely.
8444d4804dSStefan Eßer  */
8544d4804dSStefan Eßer #define BC_LIKELY(e) (e)
8644d4804dSStefan Eßer 
8744d4804dSStefan Eßer #endif // BC_LIKELY
8844d4804dSStefan Eßer 
8944d4804dSStefan Eßer // If users want, they can define this to something like __builtin_expect(e, 0).
9044d4804dSStefan Eßer // It might give a performance improvement.
9144d4804dSStefan Eßer #ifndef BC_UNLIKELY
9244d4804dSStefan Eßer 
9344d4804dSStefan Eßer /**
9444d4804dSStefan Eßer  * Mark a branch expression as unlikely.
9544d4804dSStefan Eßer  * @param e  The expression to mark as unlikely.
9644d4804dSStefan Eßer  */
9744d4804dSStefan Eßer #define BC_UNLIKELY(e) (e)
9844d4804dSStefan Eßer 
9944d4804dSStefan Eßer #endif // BC_UNLIKELY
10044d4804dSStefan Eßer 
10144d4804dSStefan Eßer /**
10244d4804dSStefan Eßer  * Mark a branch expression as an error, if true.
10344d4804dSStefan Eßer  * @param e  The expression to mark as an error, if true.
10444d4804dSStefan Eßer  */
10544d4804dSStefan Eßer #define BC_ERR(e) BC_UNLIKELY(e)
10644d4804dSStefan Eßer 
10744d4804dSStefan Eßer /**
10844d4804dSStefan Eßer  * Mark a branch expression as not an error, if true.
10944d4804dSStefan Eßer  * @param e  The expression to mark as not an error, if true.
11044d4804dSStefan Eßer  */
11144d4804dSStefan Eßer #define BC_NO_ERR(s) BC_LIKELY(s)
11244d4804dSStefan Eßer 
11344d4804dSStefan Eßer // Disable extra debug code by default.
11444d4804dSStefan Eßer #ifndef BC_DEBUG_CODE
11544d4804dSStefan Eßer #define BC_DEBUG_CODE (0)
11644d4804dSStefan Eßer #endif // BC_DEBUG_CODE
11744d4804dSStefan Eßer 
11844d4804dSStefan Eßer // We want to be able to use _Noreturn on C11 compilers.
11944d4804dSStefan Eßer #if __STDC_VERSION__ >= 201100L
12044d4804dSStefan Eßer 
12144d4804dSStefan Eßer #include <stdnoreturn.h>
12244d4804dSStefan Eßer #define BC_NORETURN _Noreturn
12344d4804dSStefan Eßer #define BC_C11 (1)
12444d4804dSStefan Eßer 
12544d4804dSStefan Eßer #else // __STDC_VERSION__
12644d4804dSStefan Eßer 
12744d4804dSStefan Eßer #define BC_NORETURN
12844d4804dSStefan Eßer #define BC_MUST_RETURN
12944d4804dSStefan Eßer #define BC_C11 (0)
13044d4804dSStefan Eßer 
13144d4804dSStefan Eßer #endif // __STDC_VERSION__
13244d4804dSStefan Eßer 
13344d4804dSStefan Eßer #define BC_HAS_UNREACHABLE (0)
13444d4804dSStefan Eßer #define BC_HAS_COMPUTED_GOTO (0)
13544d4804dSStefan Eßer 
13644d4804dSStefan Eßer // GCC and Clang complain if fallthroughs are not marked with their special
13744d4804dSStefan Eßer // attribute. Jerks. This creates a define for marking the fallthroughs that is
13844d4804dSStefan Eßer // nothing on other compilers.
13944d4804dSStefan Eßer #if defined(__clang__) || defined(__GNUC__)
14044d4804dSStefan Eßer 
14144d4804dSStefan Eßer #if defined(__has_attribute)
14244d4804dSStefan Eßer 
14344d4804dSStefan Eßer #if __has_attribute(fallthrough)
14444d4804dSStefan Eßer #define BC_FALLTHROUGH __attribute__((fallthrough));
14544d4804dSStefan Eßer #else // __has_attribute(fallthrough)
14644d4804dSStefan Eßer #define BC_FALLTHROUGH
14744d4804dSStefan Eßer #endif // __has_attribute(fallthrough)
14844d4804dSStefan Eßer 
14944d4804dSStefan Eßer #ifdef __GNUC__
15044d4804dSStefan Eßer 
15144d4804dSStefan Eßer #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
15244d4804dSStefan Eßer #undef BC_HAS_UNREACHABLE
15344d4804dSStefan Eßer #define BC_HAS_UNREACHABLE (1)
15444d4804dSStefan Eßer #endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
15544d4804dSStefan Eßer 
15644d4804dSStefan Eßer #else // __GNUC__
15744d4804dSStefan Eßer 
15844d4804dSStefan Eßer #if __clang_major__ >= 4
15944d4804dSStefan Eßer #undef BC_HAS_UNREACHABLE
16044d4804dSStefan Eßer #define BC_HAS_UNREACHABLE (1)
16144d4804dSStefan Eßer #endif // __clang_major__ >= 4
16244d4804dSStefan Eßer 
16344d4804dSStefan Eßer #endif // __GNUC__
16444d4804dSStefan Eßer 
16544d4804dSStefan Eßer #else // defined(__has_attribute)
16644d4804dSStefan Eßer #define BC_FALLTHROUGH
16744d4804dSStefan Eßer #endif // defined(__has_attribute)
16844d4804dSStefan Eßer #else // defined(__clang__) || defined(__GNUC__)
16944d4804dSStefan Eßer #define BC_FALLTHROUGH
17044d4804dSStefan Eßer #endif // defined(__clang__) || defined(__GNUC__)
17144d4804dSStefan Eßer 
17244d4804dSStefan Eßer #if BC_HAS_UNREACHABLE
17344d4804dSStefan Eßer 
17444d4804dSStefan Eßer #define BC_UNREACHABLE __builtin_unreachable();
17544d4804dSStefan Eßer 
17644d4804dSStefan Eßer #else // BC_HAS_UNREACHABLE
17744d4804dSStefan Eßer 
17844d4804dSStefan Eßer #ifdef _WIN32
17944d4804dSStefan Eßer 
18044d4804dSStefan Eßer #define BC_UNREACHABLE __assume(0);
18144d4804dSStefan Eßer 
18244d4804dSStefan Eßer #else // _WIN32
18344d4804dSStefan Eßer 
18444d4804dSStefan Eßer #define BC_UNREACHABLE
18544d4804dSStefan Eßer 
18644d4804dSStefan Eßer #endif // _WIN32
18744d4804dSStefan Eßer 
18844d4804dSStefan Eßer #endif // BC_HAS_UNREACHABLE
18944d4804dSStefan Eßer 
19044d4804dSStefan Eßer #ifdef __GNUC__
19144d4804dSStefan Eßer 
19244d4804dSStefan Eßer #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
19344d4804dSStefan Eßer 
19444d4804dSStefan Eßer #undef BC_HAS_COMPUTED_GOTO
19544d4804dSStefan Eßer #define BC_HAS_COMPUTED_GOTO (1)
19644d4804dSStefan Eßer 
19744d4804dSStefan Eßer #endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
19844d4804dSStefan Eßer 
19944d4804dSStefan Eßer #endif // __GNUC__
20044d4804dSStefan Eßer 
20144d4804dSStefan Eßer #ifdef __clang__
20244d4804dSStefan Eßer 
20344d4804dSStefan Eßer #if __clang_major__ >= 4
20444d4804dSStefan Eßer 
20544d4804dSStefan Eßer #undef BC_HAS_COMPUTED_GOTO
20644d4804dSStefan Eßer #define BC_HAS_COMPUTED_GOTO (1)
20744d4804dSStefan Eßer 
20844d4804dSStefan Eßer #endif // __clang_major__ >= 4
20944d4804dSStefan Eßer 
21044d4804dSStefan Eßer #endif // __GNUC__
21144d4804dSStefan Eßer 
21244d4804dSStefan Eßer #ifdef BC_NO_COMPUTED_GOTO
21344d4804dSStefan Eßer 
21444d4804dSStefan Eßer #undef BC_HAS_COMPUTED_GOTO
21544d4804dSStefan Eßer #define BC_HAS_COMPUTED_GOTO (0)
21644d4804dSStefan Eßer 
21744d4804dSStefan Eßer #endif // BC_NO_COMPUTED_GOTO
21844d4804dSStefan Eßer 
21944d4804dSStefan Eßer #ifdef __GNUC__
22044d4804dSStefan Eßer #ifdef __OpenBSD__
22144d4804dSStefan Eßer // The OpenBSD GCC doesn't like inline.
22244d4804dSStefan Eßer #define inline
22344d4804dSStefan Eßer #endif // __OpenBSD__
22444d4804dSStefan Eßer #endif // __GNUC__
22544d4804dSStefan Eßer 
22644d4804dSStefan Eßer // Workarounds for AIX's POSIX incompatibility.
22744d4804dSStefan Eßer #ifndef SIZE_MAX
22844d4804dSStefan Eßer #define SIZE_MAX __SIZE_MAX__
22944d4804dSStefan Eßer #endif // SIZE_MAX
23044d4804dSStefan Eßer #ifndef UINTMAX_C
23144d4804dSStefan Eßer #define UINTMAX_C __UINTMAX_C
23244d4804dSStefan Eßer #endif // UINTMAX_C
23344d4804dSStefan Eßer #ifndef UINT32_C
23444d4804dSStefan Eßer #define UINT32_C __UINT32_C
23544d4804dSStefan Eßer #endif // UINT32_C
23644d4804dSStefan Eßer #ifndef UINT_FAST32_MAX
23744d4804dSStefan Eßer #define UINT_FAST32_MAX __UINT_FAST32_MAX__
23844d4804dSStefan Eßer #endif // UINT_FAST32_MAX
23944d4804dSStefan Eßer #ifndef UINT16_MAX
24044d4804dSStefan Eßer #define UINT16_MAX __UINT16_MAX__
24144d4804dSStefan Eßer #endif // UINT16_MAX
24244d4804dSStefan Eßer #ifndef SIG_ATOMIC_MAX
24344d4804dSStefan Eßer #define SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__
24444d4804dSStefan Eßer #endif // SIG_ATOMIC_MAX
24544d4804dSStefan Eßer 
24644d4804dSStefan Eßer // Yes, this has to be here.
24750696a6eSStefan Eßer #include <bcl.h>
24850696a6eSStefan Eßer 
24944d4804dSStefan Eßer // All of these set defaults for settings.
25044d4804dSStefan Eßer 
25144d4804dSStefan Eßer #if BC_ENABLED
25244d4804dSStefan Eßer 
25344d4804dSStefan Eßer #ifndef BC_DEFAULT_BANNER
25444d4804dSStefan Eßer #define BC_DEFAULT_BANNER (0)
25544d4804dSStefan Eßer #endif // BC_DEFAULT_BANNER
25644d4804dSStefan Eßer 
25744d4804dSStefan Eßer #endif // BC_ENABLED
25844d4804dSStefan Eßer 
25944d4804dSStefan Eßer #ifndef BC_DEFAULT_SIGINT_RESET
26044d4804dSStefan Eßer #define BC_DEFAULT_SIGINT_RESET (1)
26144d4804dSStefan Eßer #endif // BC_DEFAULT_SIGINT_RESET
26244d4804dSStefan Eßer 
26344d4804dSStefan Eßer #ifndef BC_DEFAULT_TTY_MODE
26444d4804dSStefan Eßer #define BC_DEFAULT_TTY_MODE (1)
26544d4804dSStefan Eßer #endif // BC_DEFAULT_TTY_MODE
26644d4804dSStefan Eßer 
26744d4804dSStefan Eßer #ifndef BC_DEFAULT_PROMPT
26844d4804dSStefan Eßer #define BC_DEFAULT_PROMPT BC_DEFAULT_TTY_MODE
26944d4804dSStefan Eßer #endif // BC_DEFAULT_PROMPT
27044d4804dSStefan Eßer 
27110041e99SStefan Eßer #ifndef BC_DEFAULT_EXPR_EXIT
27210041e99SStefan Eßer #define BC_DEFAULT_EXPR_EXIT (1)
27310041e99SStefan Eßer #endif // BC_DEFAULT_EXPR_EXIT
27410041e99SStefan Eßer 
27544d4804dSStefan Eßer // All of these set defaults for settings.
27644d4804dSStefan Eßer #ifndef DC_DEFAULT_SIGINT_RESET
27744d4804dSStefan Eßer #define DC_DEFAULT_SIGINT_RESET (1)
27844d4804dSStefan Eßer #endif // DC_DEFAULT_SIGINT_RESET
27944d4804dSStefan Eßer 
28044d4804dSStefan Eßer #ifndef DC_DEFAULT_TTY_MODE
28144d4804dSStefan Eßer #define DC_DEFAULT_TTY_MODE (0)
28244d4804dSStefan Eßer #endif // DC_DEFAULT_TTY_MODE
28344d4804dSStefan Eßer 
28444d4804dSStefan Eßer #ifndef DC_DEFAULT_HISTORY
28544d4804dSStefan Eßer #define DC_DEFAULT_HISTORY DC_DEFAULT_TTY_MODE
28644d4804dSStefan Eßer #endif // DC_DEFAULT_HISTORY
28744d4804dSStefan Eßer 
28844d4804dSStefan Eßer #ifndef DC_DEFAULT_PROMPT
28944d4804dSStefan Eßer #define DC_DEFAULT_PROMPT DC_DEFAULT_TTY_MODE
29044d4804dSStefan Eßer #endif // DC_DEFAULT_PROMPT
29144d4804dSStefan Eßer 
29210041e99SStefan Eßer #ifndef DC_DEFAULT_EXPR_EXIT
29310041e99SStefan Eßer #define DC_DEFAULT_EXPR_EXIT (1)
29410041e99SStefan Eßer #endif // DC_DEFAULT_EXPR_EXIT
29510041e99SStefan Eßer 
29644d4804dSStefan Eßer /// Statuses, which mark either which category of error happened, or some other
29744d4804dSStefan Eßer /// status that matters.
298252884aeSStefan Eßer typedef enum BcStatus {
299252884aeSStefan Eßer 
30044d4804dSStefan Eßer 	/// Normal status.
301252884aeSStefan Eßer 	BC_STATUS_SUCCESS = 0,
30244d4804dSStefan Eßer 
30344d4804dSStefan Eßer 	/// Math error.
304252884aeSStefan Eßer 	BC_STATUS_ERROR_MATH,
30544d4804dSStefan Eßer 
30644d4804dSStefan Eßer 	/// Parse (and lex) error.
307252884aeSStefan Eßer 	BC_STATUS_ERROR_PARSE,
30844d4804dSStefan Eßer 
30944d4804dSStefan Eßer 	/// Runtime error.
310252884aeSStefan Eßer 	BC_STATUS_ERROR_EXEC,
31144d4804dSStefan Eßer 
31244d4804dSStefan Eßer 	/// Fatal error.
313252884aeSStefan Eßer 	BC_STATUS_ERROR_FATAL,
31444d4804dSStefan Eßer 
31544d4804dSStefan Eßer 	/// EOF status.
316252884aeSStefan Eßer 	BC_STATUS_EOF,
31744d4804dSStefan Eßer 
31844d4804dSStefan Eßer 	/// Quit status. This means that bc/dc is in the process of quitting.
319252884aeSStefan Eßer 	BC_STATUS_QUIT,
320252884aeSStefan Eßer 
321252884aeSStefan Eßer } BcStatus;
322252884aeSStefan Eßer 
32344d4804dSStefan Eßer /// Errors, which are more specific errors.
32450696a6eSStefan Eßer typedef enum BcErr {
325252884aeSStefan Eßer 
32644d4804dSStefan Eßer 	// Math errors.
32744d4804dSStefan Eßer 
32844d4804dSStefan Eßer 	/// Negative number used when not allowed.
32950696a6eSStefan Eßer 	BC_ERR_MATH_NEGATIVE,
33044d4804dSStefan Eßer 
33144d4804dSStefan Eßer 	/// Non-integer used when not allowed.
33250696a6eSStefan Eßer 	BC_ERR_MATH_NON_INTEGER,
33344d4804dSStefan Eßer 
33444d4804dSStefan Eßer 	/// Conversion to a hardware integer would overflow.
33550696a6eSStefan Eßer 	BC_ERR_MATH_OVERFLOW,
33644d4804dSStefan Eßer 
33744d4804dSStefan Eßer 	/// Divide by zero.
33850696a6eSStefan Eßer 	BC_ERR_MATH_DIVIDE_BY_ZERO,
339252884aeSStefan Eßer 
34044d4804dSStefan Eßer 	// Fatal errors.
34144d4804dSStefan Eßer 
34244d4804dSStefan Eßer 	/// An allocation or reallocation failed.
34350696a6eSStefan Eßer 	BC_ERR_FATAL_ALLOC_ERR,
34444d4804dSStefan Eßer 
34544d4804dSStefan Eßer 	/// I/O failure.
34650696a6eSStefan Eßer 	BC_ERR_FATAL_IO_ERR,
34744d4804dSStefan Eßer 
34844d4804dSStefan Eßer 	/// File error, such as permissions or file does not exist.
34950696a6eSStefan Eßer 	BC_ERR_FATAL_FILE_ERR,
35044d4804dSStefan Eßer 
35144d4804dSStefan Eßer 	/// File is binary, not text, error.
35250696a6eSStefan Eßer 	BC_ERR_FATAL_BIN_FILE,
35344d4804dSStefan Eßer 
35444d4804dSStefan Eßer 	/// Attempted to read a directory as a file error.
35550696a6eSStefan Eßer 	BC_ERR_FATAL_PATH_DIR,
35644d4804dSStefan Eßer 
35744d4804dSStefan Eßer 	/// Invalid option error.
35850696a6eSStefan Eßer 	BC_ERR_FATAL_OPTION,
35944d4804dSStefan Eßer 
36044d4804dSStefan Eßer 	/// Option with required argument not given an argument.
36150696a6eSStefan Eßer 	BC_ERR_FATAL_OPTION_NO_ARG,
36244d4804dSStefan Eßer 
36344d4804dSStefan Eßer 	/// Option with no argument given an argument.
36450696a6eSStefan Eßer 	BC_ERR_FATAL_OPTION_ARG,
365252884aeSStefan Eßer 
36644d4804dSStefan Eßer 	/// Option argument is invalid.
36744d4804dSStefan Eßer 	BC_ERR_FATAL_ARG,
36844d4804dSStefan Eßer 
36944d4804dSStefan Eßer 	// Runtime errors.
37044d4804dSStefan Eßer 
37144d4804dSStefan Eßer 	/// Invalid ibase value.
37250696a6eSStefan Eßer 	BC_ERR_EXEC_IBASE,
37344d4804dSStefan Eßer 
37444d4804dSStefan Eßer 	/// Invalid obase value.
37550696a6eSStefan Eßer 	BC_ERR_EXEC_OBASE,
37644d4804dSStefan Eßer 
37744d4804dSStefan Eßer 	/// Invalid scale value.
37850696a6eSStefan Eßer 	BC_ERR_EXEC_SCALE,
37944d4804dSStefan Eßer 
38044d4804dSStefan Eßer 	/// Invalid expression parsed by read().
38150696a6eSStefan Eßer 	BC_ERR_EXEC_READ_EXPR,
38244d4804dSStefan Eßer 
38344d4804dSStefan Eßer 	/// read() used within an expression given to a read() call.
38450696a6eSStefan Eßer 	BC_ERR_EXEC_REC_READ,
38544d4804dSStefan Eßer 
38644d4804dSStefan Eßer 	/// Type error.
38750696a6eSStefan Eßer 	BC_ERR_EXEC_TYPE,
388252884aeSStefan Eßer 
38944d4804dSStefan Eßer 	/// Stack has too few elements error.
39050696a6eSStefan Eßer 	BC_ERR_EXEC_STACK,
391252884aeSStefan Eßer 
39244d4804dSStefan Eßer 	/// Register stack has too few elements error.
39344d4804dSStefan Eßer 	BC_ERR_EXEC_STACK_REGISTER,
39444d4804dSStefan Eßer 
39544d4804dSStefan Eßer 	/// Wrong number of arguments error.
39650696a6eSStefan Eßer 	BC_ERR_EXEC_PARAMS,
39744d4804dSStefan Eßer 
39844d4804dSStefan Eßer 	/// Undefined function error.
39950696a6eSStefan Eßer 	BC_ERR_EXEC_UNDEF_FUNC,
40044d4804dSStefan Eßer 
40144d4804dSStefan Eßer 	/// Void value used in an expression error.
40250696a6eSStefan Eßer 	BC_ERR_EXEC_VOID_VAL,
403252884aeSStefan Eßer 
40444d4804dSStefan Eßer 	// Parse (and lex errors).
40544d4804dSStefan Eßer 
40644d4804dSStefan Eßer 	/// EOF encountered when not expected error.
40750696a6eSStefan Eßer 	BC_ERR_PARSE_EOF,
40844d4804dSStefan Eßer 
40944d4804dSStefan Eßer 	/// Invalid character error.
41050696a6eSStefan Eßer 	BC_ERR_PARSE_CHAR,
41144d4804dSStefan Eßer 
41244d4804dSStefan Eßer 	/// Invalid string (no ending quote) error.
41350696a6eSStefan Eßer 	BC_ERR_PARSE_STRING,
41444d4804dSStefan Eßer 
41544d4804dSStefan Eßer 	/// Invalid comment (no end found) error.
41650696a6eSStefan Eßer 	BC_ERR_PARSE_COMMENT,
41744d4804dSStefan Eßer 
41844d4804dSStefan Eßer 	/// Invalid token encountered error.
41950696a6eSStefan Eßer 	BC_ERR_PARSE_TOKEN,
42044d4804dSStefan Eßer 
421252884aeSStefan Eßer #if BC_ENABLED
42244d4804dSStefan Eßer 
42344d4804dSStefan Eßer 	/// Invalid expression error.
42450696a6eSStefan Eßer 	BC_ERR_PARSE_EXPR,
42544d4804dSStefan Eßer 
42644d4804dSStefan Eßer 	/// Expression is empty error.
42750696a6eSStefan Eßer 	BC_ERR_PARSE_EMPTY_EXPR,
42844d4804dSStefan Eßer 
42944d4804dSStefan Eßer 	/// Print statement is invalid error.
43050696a6eSStefan Eßer 	BC_ERR_PARSE_PRINT,
43144d4804dSStefan Eßer 
43244d4804dSStefan Eßer 	/// Function definition is invalid error.
43350696a6eSStefan Eßer 	BC_ERR_PARSE_FUNC,
43444d4804dSStefan Eßer 
43544d4804dSStefan Eßer 	/// Assignment is invalid error.
43650696a6eSStefan Eßer 	BC_ERR_PARSE_ASSIGN,
43744d4804dSStefan Eßer 
43844d4804dSStefan Eßer 	/// No auto identifiers given for an auto statement error.
43950696a6eSStefan Eßer 	BC_ERR_PARSE_NO_AUTO,
44044d4804dSStefan Eßer 
44144d4804dSStefan Eßer 	/// Duplicate local (parameter or auto) error.
44250696a6eSStefan Eßer 	BC_ERR_PARSE_DUP_LOCAL,
44344d4804dSStefan Eßer 
44444d4804dSStefan Eßer 	/// Invalid block (within braces) error.
44550696a6eSStefan Eßer 	BC_ERR_PARSE_BLOCK,
44644d4804dSStefan Eßer 
44744d4804dSStefan Eßer 	/// Invalid return statement for void functions.
44850696a6eSStefan Eßer 	BC_ERR_PARSE_RET_VOID,
44944d4804dSStefan Eßer 
45044d4804dSStefan Eßer 	/// Reference attached to a variable, not an array, error.
45150696a6eSStefan Eßer 	BC_ERR_PARSE_REF_VAR,
452252884aeSStefan Eßer 
45344d4804dSStefan Eßer 	// POSIX-only errors.
45444d4804dSStefan Eßer 
45544d4804dSStefan Eßer 	/// Name length greater than 1 error.
45650696a6eSStefan Eßer 	BC_ERR_POSIX_NAME_LEN,
45744d4804dSStefan Eßer 
45844d4804dSStefan Eßer 	/// Non-POSIX comment used error.
45950696a6eSStefan Eßer 	BC_ERR_POSIX_COMMENT,
46044d4804dSStefan Eßer 
46144d4804dSStefan Eßer 	/// Non-POSIX keyword error.
46250696a6eSStefan Eßer 	BC_ERR_POSIX_KW,
46344d4804dSStefan Eßer 
46444d4804dSStefan Eßer 	/// Non-POSIX . (last) error.
46550696a6eSStefan Eßer 	BC_ERR_POSIX_DOT,
46644d4804dSStefan Eßer 
46744d4804dSStefan Eßer 	/// Non-POSIX return error.
46850696a6eSStefan Eßer 	BC_ERR_POSIX_RET,
46944d4804dSStefan Eßer 
47044d4804dSStefan Eßer 	/// Non-POSIX boolean operator used error.
47150696a6eSStefan Eßer 	BC_ERR_POSIX_BOOL,
47244d4804dSStefan Eßer 
47344d4804dSStefan Eßer 	/// POSIX relation operator used outside if, while, or for statements error.
47450696a6eSStefan Eßer 	BC_ERR_POSIX_REL_POS,
47544d4804dSStefan Eßer 
47644d4804dSStefan Eßer 	/// Multiple POSIX relation operators used in an if, while, or for statement
47744d4804dSStefan Eßer 	/// error.
47850696a6eSStefan Eßer 	BC_ERR_POSIX_MULTIREL,
47944d4804dSStefan Eßer 
48044d4804dSStefan Eßer 	/// Empty statements in POSIX for loop error.
48150696a6eSStefan Eßer 	BC_ERR_POSIX_FOR,
48244d4804dSStefan Eßer 
48310041e99SStefan Eßer 	/// POSIX's grammar does not allow a function definition right after a
48410041e99SStefan Eßer 	/// semicolon.
48510041e99SStefan Eßer 	BC_ERR_POSIX_FUNC_AFTER_SEMICOLON,
48610041e99SStefan Eßer 
48744d4804dSStefan Eßer 	/// Non-POSIX exponential (scientific or engineering) number used error.
48850696a6eSStefan Eßer 	BC_ERR_POSIX_EXP_NUM,
48944d4804dSStefan Eßer 
49044d4804dSStefan Eßer 	/// Non-POSIX array reference error.
49150696a6eSStefan Eßer 	BC_ERR_POSIX_REF,
49244d4804dSStefan Eßer 
49344d4804dSStefan Eßer 	/// Non-POSIX void error.
49450696a6eSStefan Eßer 	BC_ERR_POSIX_VOID,
49544d4804dSStefan Eßer 
49644d4804dSStefan Eßer 	/// Non-POSIX brace position used error.
49750696a6eSStefan Eßer 	BC_ERR_POSIX_BRACE,
49844d4804dSStefan Eßer 
49944d4804dSStefan Eßer 	/// String used in expression.
50044d4804dSStefan Eßer 	BC_ERR_POSIX_EXPR_STRING,
50144d4804dSStefan Eßer 
502252884aeSStefan Eßer #endif // BC_ENABLED
503252884aeSStefan Eßer 
50444d4804dSStefan Eßer 	// Number of elements.
50550696a6eSStefan Eßer 	BC_ERR_NELEMS,
506252884aeSStefan Eßer 
507252884aeSStefan Eßer #if BC_ENABLED
50844d4804dSStefan Eßer 
50944d4804dSStefan Eßer 	/// A marker for the start of POSIX errors.
51050696a6eSStefan Eßer 	BC_ERR_POSIX_START = BC_ERR_POSIX_NAME_LEN,
51144d4804dSStefan Eßer 
51244d4804dSStefan Eßer 	/// A marker for the end of POSIX errors.
51344d4804dSStefan Eßer 	BC_ERR_POSIX_END = BC_ERR_POSIX_EXPR_STRING,
51444d4804dSStefan Eßer 
515252884aeSStefan Eßer #endif // BC_ENABLED
516252884aeSStefan Eßer 
51750696a6eSStefan Eßer } BcErr;
518252884aeSStefan Eßer 
51944d4804dSStefan Eßer // The indices of each category of error in bc_errs[], and used in bc_err_ids[]
52044d4804dSStefan Eßer // to associate actual errors with their categories.
52144d4804dSStefan Eßer 
52244d4804dSStefan Eßer /// Math error category.
523252884aeSStefan Eßer #define BC_ERR_IDX_MATH (0)
52444d4804dSStefan Eßer 
52544d4804dSStefan Eßer /// Parse (and lex) error category.
526252884aeSStefan Eßer #define BC_ERR_IDX_PARSE (1)
52744d4804dSStefan Eßer 
52844d4804dSStefan Eßer /// Runtime error category.
529252884aeSStefan Eßer #define BC_ERR_IDX_EXEC (2)
53044d4804dSStefan Eßer 
53144d4804dSStefan Eßer /// Fatal error category.
532252884aeSStefan Eßer #define BC_ERR_IDX_FATAL (3)
53344d4804dSStefan Eßer 
53444d4804dSStefan Eßer /// Number of categories.
535252884aeSStefan Eßer #define BC_ERR_IDX_NELEMS (4)
536252884aeSStefan Eßer 
53744d4804dSStefan Eßer // If bc is enabled, we add an extra category for POSIX warnings.
538252884aeSStefan Eßer #if BC_ENABLED
53944d4804dSStefan Eßer 
54044d4804dSStefan Eßer /// POSIX warning category.
541252884aeSStefan Eßer #define BC_ERR_IDX_WARN (BC_ERR_IDX_NELEMS)
54244d4804dSStefan Eßer 
543252884aeSStefan Eßer #endif // BC_ENABLED
544252884aeSStefan Eßer 
54544d4804dSStefan Eßer /// Do a longjmp(). This is what to use when activating an "exception", i.e., a
54644d4804dSStefan Eßer /// longjmp(). With debug code, it will print the name of the function it jumped
54744d4804dSStefan Eßer /// from.
54844d4804dSStefan Eßer #if BC_DEBUG_CODE
54944d4804dSStefan Eßer #define BC_JMP bc_vm_jmp(__func__)
55044d4804dSStefan Eßer #else // BC_DEBUG_CODE
55144d4804dSStefan Eßer #define BC_JMP bc_vm_jmp()
55244d4804dSStefan Eßer #endif // BC_DEBUG_CODE
55344d4804dSStefan Eßer 
55444d4804dSStefan Eßer /// Returns true if an exception is in flight, false otherwise.
55544d4804dSStefan Eßer #define BC_SIG_EXC \
55644d4804dSStefan Eßer 	BC_UNLIKELY(vm.status != (sig_atomic_t) BC_STATUS_SUCCESS || vm.sig)
55744d4804dSStefan Eßer 
55844d4804dSStefan Eßer /// Returns true if there is *no* exception in flight, false otherwise.
55944d4804dSStefan Eßer #define BC_NO_SIG_EXC \
56044d4804dSStefan Eßer 	BC_LIKELY(vm.status == (sig_atomic_t) BC_STATUS_SUCCESS && !vm.sig)
56144d4804dSStefan Eßer 
56244d4804dSStefan Eßer #ifndef NDEBUG
56344d4804dSStefan Eßer 
56444d4804dSStefan Eßer /// Assert that signals are locked. There are non-async-signal-safe functions in
56544d4804dSStefan Eßer /// bc, and they *must* have signals locked. Other functions are expected to
56644d4804dSStefan Eßer /// *not* have signals locked, for reasons. So this is a pre-built assert
56744d4804dSStefan Eßer /// (no-op in non-debug mode) that check that signals are locked.
56844d4804dSStefan Eßer #define BC_SIG_ASSERT_LOCKED do { assert(vm.sig_lock); } while (0)
56944d4804dSStefan Eßer 
57044d4804dSStefan Eßer /// Assert that signals are unlocked. There are non-async-signal-safe functions
57144d4804dSStefan Eßer /// in bc, and they *must* have signals locked. Other functions are expected to
57244d4804dSStefan Eßer /// *not* have signals locked, for reasons. So this is a pre-built assert
57344d4804dSStefan Eßer /// (no-op in non-debug mode) that check that signals are unlocked.
57444d4804dSStefan Eßer #define BC_SIG_ASSERT_NOT_LOCKED do { assert(vm.sig_lock == 0); } while (0)
57544d4804dSStefan Eßer 
57644d4804dSStefan Eßer #else // NDEBUG
57744d4804dSStefan Eßer 
57844d4804dSStefan Eßer /// Assert that signals are locked. There are non-async-signal-safe functions in
57944d4804dSStefan Eßer /// bc, and they *must* have signals locked. Other functions are expected to
58044d4804dSStefan Eßer /// *not* have signals locked, for reasons. So this is a pre-built assert
58144d4804dSStefan Eßer /// (no-op in non-debug mode) that check that signals are locked.
58244d4804dSStefan Eßer #define BC_SIG_ASSERT_LOCKED
58344d4804dSStefan Eßer 
58444d4804dSStefan Eßer /// Assert that signals are unlocked. There are non-async-signal-safe functions
58544d4804dSStefan Eßer /// in bc, and they *must* have signals locked. Other functions are expected to
58644d4804dSStefan Eßer /// *not* have signals locked, for reasons. So this is a pre-built assert
58744d4804dSStefan Eßer /// (no-op in non-debug mode) that check that signals are unlocked.
58844d4804dSStefan Eßer #define BC_SIG_ASSERT_NOT_LOCKED
58944d4804dSStefan Eßer 
59044d4804dSStefan Eßer #endif // NDEBUG
59144d4804dSStefan Eßer 
59244d4804dSStefan Eßer /// Locks signals.
59344d4804dSStefan Eßer #define BC_SIG_LOCK               \
59444d4804dSStefan Eßer 	do {                          \
59544d4804dSStefan Eßer 		BC_SIG_ASSERT_NOT_LOCKED; \
59644d4804dSStefan Eßer 		vm.sig_lock = 1;          \
59744d4804dSStefan Eßer 	} while (0)
59844d4804dSStefan Eßer 
59944d4804dSStefan Eßer /// Unlocks signals. If a signal happened, then this will cause a jump.
60044d4804dSStefan Eßer #define BC_SIG_UNLOCK         \
60144d4804dSStefan Eßer 	do {                      \
60244d4804dSStefan Eßer 		BC_SIG_ASSERT_LOCKED; \
60344d4804dSStefan Eßer 		vm.sig_lock = 0;      \
60444d4804dSStefan Eßer 		if (vm.sig) BC_JMP;   \
60544d4804dSStefan Eßer 	} while (0)
60644d4804dSStefan Eßer 
60744d4804dSStefan Eßer /// Locks signals, regardless of if they are already locked. This is really only
60844d4804dSStefan Eßer /// used after labels that longjmp() goes to after the jump because the cleanup
60944d4804dSStefan Eßer /// code must have signals locked, and BC_LONGJMP_CONT will unlock signals if it
61044d4804dSStefan Eßer /// doesn't jump.
61144d4804dSStefan Eßer #define BC_SIG_MAYLOCK   \
61244d4804dSStefan Eßer 	do {                 \
61344d4804dSStefan Eßer 		vm.sig_lock = 1; \
61444d4804dSStefan Eßer 	} while (0)
61544d4804dSStefan Eßer 
61644d4804dSStefan Eßer /// Unlocks signals, regardless of if they were already unlocked. If a signal
61744d4804dSStefan Eßer /// happened, then this will cause a jump.
61844d4804dSStefan Eßer #define BC_SIG_MAYUNLOCK    \
61944d4804dSStefan Eßer 	do {                    \
62044d4804dSStefan Eßer 		vm.sig_lock = 0;    \
62144d4804dSStefan Eßer 		if (vm.sig) BC_JMP; \
62244d4804dSStefan Eßer 	} while (0)
62344d4804dSStefan Eßer 
62444d4804dSStefan Eßer /*
62544d4804dSStefan Eßer  * Locks signals, but stores the old lock state, to be restored later by
62644d4804dSStefan Eßer  * BC_SIG_TRYUNLOCK.
62744d4804dSStefan Eßer  * @param v  The variable to store the old lock state to.
62844d4804dSStefan Eßer  */
62944d4804dSStefan Eßer #define BC_SIG_TRYLOCK(v) \
63044d4804dSStefan Eßer 	do {                  \
63144d4804dSStefan Eßer 		v = vm.sig_lock;  \
63244d4804dSStefan Eßer 		vm.sig_lock = 1;  \
63344d4804dSStefan Eßer 	} while (0)
63444d4804dSStefan Eßer 
63544d4804dSStefan Eßer /* Restores the previous state of a signal lock, and if it is now unlocked,
63644d4804dSStefan Eßer  * initiates an exception/jump.
63744d4804dSStefan Eßer  * @param v  The old lock state.
63844d4804dSStefan Eßer  */
63944d4804dSStefan Eßer #define BC_SIG_TRYUNLOCK(v)         \
64044d4804dSStefan Eßer 	do {                            \
64144d4804dSStefan Eßer 		vm.sig_lock = (v);          \
64244d4804dSStefan Eßer 		if (!(v) && vm.sig) BC_JMP; \
64344d4804dSStefan Eßer 	} while (0)
64444d4804dSStefan Eßer 
64544d4804dSStefan Eßer /**
64644d4804dSStefan Eßer  * Sets a jump, and sets it up as well so that if a longjmp() happens, bc will
64744d4804dSStefan Eßer  * immediately goto a label where some cleanup code is. This one assumes that
64844d4804dSStefan Eßer  * signals are not locked and will lock them, set the jump, and unlock them.
64944d4804dSStefan Eßer  * Setting the jump also includes pushing the jmp_buf onto the jmp_buf stack.
65044d4804dSStefan Eßer  * This grows the jmp_bufs vector first to prevent a fatal error from happening
65144d4804dSStefan Eßer  * after the setjmp(). This is done because BC_SETJMP(l) is assumed to be used
65244d4804dSStefan Eßer  * *before* the actual initialization calls that need the setjmp().
65344d4804dSStefan Eßer  * param l  The label to jump to on a longjmp().
65444d4804dSStefan Eßer  */
65544d4804dSStefan Eßer #define BC_SETJMP(l)                     \
65644d4804dSStefan Eßer 	do {                                 \
65744d4804dSStefan Eßer 		sigjmp_buf sjb;                  \
65844d4804dSStefan Eßer 		BC_SIG_LOCK;                     \
65944d4804dSStefan Eßer 		bc_vec_grow(&vm.jmp_bufs, 1);    \
66044d4804dSStefan Eßer 		if (sigsetjmp(sjb, 0)) {         \
66144d4804dSStefan Eßer 			assert(BC_SIG_EXC);          \
66244d4804dSStefan Eßer 			goto l;                      \
66344d4804dSStefan Eßer 		}                                \
66444d4804dSStefan Eßer 		bc_vec_push(&vm.jmp_bufs, &sjb); \
66544d4804dSStefan Eßer 		BC_SIG_UNLOCK;                   \
66644d4804dSStefan Eßer 	} while (0)
66744d4804dSStefan Eßer 
66844d4804dSStefan Eßer /**
66944d4804dSStefan Eßer  * Sets a jump like BC_SETJMP, but unlike BC_SETJMP, it assumes signals are
67044d4804dSStefan Eßer  * locked and will just set the jump. This does *not* have a call to
67144d4804dSStefan Eßer  * bc_vec_grow() because it is assumed that BC_SETJMP_LOCKED(l) is used *after*
67244d4804dSStefan Eßer  * the initializations that need the setjmp().
67344d4804dSStefan Eßer  * param l  The label to jump to on a longjmp().
67444d4804dSStefan Eßer  */
67544d4804dSStefan Eßer #define BC_SETJMP_LOCKED(l)              \
67644d4804dSStefan Eßer 	do {                                 \
67744d4804dSStefan Eßer 		sigjmp_buf sjb;                  \
67844d4804dSStefan Eßer 		BC_SIG_ASSERT_LOCKED;            \
67944d4804dSStefan Eßer 		if (sigsetjmp(sjb, 0)) {         \
68044d4804dSStefan Eßer 			assert(BC_SIG_EXC);          \
68144d4804dSStefan Eßer 			goto l;                      \
68244d4804dSStefan Eßer 		}                                \
68344d4804dSStefan Eßer 		bc_vec_push(&vm.jmp_bufs, &sjb); \
68444d4804dSStefan Eßer 	} while (0)
68544d4804dSStefan Eßer 
68644d4804dSStefan Eßer /// Used after cleanup labels set by BC_SETJMP and BC_SETJMP_LOCKED to jump to
68744d4804dSStefan Eßer /// the next place. This is what continues the stack unwinding. This basically
68844d4804dSStefan Eßer /// copies BC_SIG_UNLOCK into itself, but that is because its condition for
68944d4804dSStefan Eßer /// jumping is BC_SIG_EXC, not just that a signal happened.
69044d4804dSStefan Eßer #define BC_LONGJMP_CONT                            \
69144d4804dSStefan Eßer 	do {                                           \
69244d4804dSStefan Eßer 		BC_SIG_ASSERT_LOCKED;                      \
69344d4804dSStefan Eßer 		if (!vm.sig_pop) bc_vec_pop(&vm.jmp_bufs); \
69444d4804dSStefan Eßer 		vm.sig_lock = 0;                           \
69544d4804dSStefan Eßer 		if (BC_SIG_EXC) BC_JMP;                    \
69644d4804dSStefan Eßer 	} while (0)
69744d4804dSStefan Eßer 
69844d4804dSStefan Eßer /// Unsets a jump. It always assumes signals are locked. This basically just
69944d4804dSStefan Eßer /// pops a jmp_buf off of the stack of jmp_bufs, and since the jump mechanism
70044d4804dSStefan Eßer /// always jumps to the location at the top of the stack, this effectively
70144d4804dSStefan Eßer /// undoes a setjmp().
70244d4804dSStefan Eßer #define BC_UNSETJMP               \
70344d4804dSStefan Eßer 	do {                          \
70444d4804dSStefan Eßer 		BC_SIG_ASSERT_LOCKED;     \
70544d4804dSStefan Eßer 		bc_vec_pop(&vm.jmp_bufs); \
70644d4804dSStefan Eßer 	} while (0)
70744d4804dSStefan Eßer 
70844d4804dSStefan Eßer /// Stops a stack unwinding. Technically, a stack unwinding needs to be done
70944d4804dSStefan Eßer /// manually, but it will always be done unless certain flags are cleared. This
71044d4804dSStefan Eßer /// clears the flags.
71144d4804dSStefan Eßer #define BC_LONGJMP_STOP \
71244d4804dSStefan Eßer 	do {                \
71344d4804dSStefan Eßer 		vm.sig_pop = 0; \
71444d4804dSStefan Eßer 		vm.sig = 0;     \
71544d4804dSStefan Eßer 	} while (0)
71644d4804dSStefan Eßer 
71744d4804dSStefan Eßer // Various convenience macros for calling the bc's error handling routine.
71844d4804dSStefan Eßer #if BC_ENABLE_LIBRARY
71944d4804dSStefan Eßer 
72044d4804dSStefan Eßer /**
72144d4804dSStefan Eßer  * Call bc's error handling routine.
72244d4804dSStefan Eßer  * @param e    The error.
72344d4804dSStefan Eßer  * @param l    The line of the script that the error happened.
72444d4804dSStefan Eßer  * @param ...  Extra arguments for error messages as necessary.
72544d4804dSStefan Eßer  */
72644d4804dSStefan Eßer #define bc_error(e, l, ...) (bc_vm_handleError((e)))
72744d4804dSStefan Eßer 
72844d4804dSStefan Eßer /**
72944d4804dSStefan Eßer  * Call bc's error handling routine.
73044d4804dSStefan Eßer  * @param e  The error.
73144d4804dSStefan Eßer  */
73244d4804dSStefan Eßer #define bc_err(e) (bc_vm_handleError((e)))
73344d4804dSStefan Eßer 
73444d4804dSStefan Eßer /**
73544d4804dSStefan Eßer  * Call bc's error handling routine.
73644d4804dSStefan Eßer  * @param e  The error.
73744d4804dSStefan Eßer  */
73844d4804dSStefan Eßer #define bc_verr(e, ...) (bc_vm_handleError((e)))
73944d4804dSStefan Eßer 
74044d4804dSStefan Eßer #else // BC_ENABLE_LIBRARY
74144d4804dSStefan Eßer 
74244d4804dSStefan Eßer /**
74344d4804dSStefan Eßer  * Call bc's error handling routine.
74444d4804dSStefan Eßer  * @param e    The error.
74544d4804dSStefan Eßer  * @param l    The line of the script that the error happened.
74644d4804dSStefan Eßer  * @param ...  Extra arguments for error messages as necessary.
74744d4804dSStefan Eßer  */
74844d4804dSStefan Eßer #define bc_error(e, l, ...) (bc_vm_handleError((e), (l), __VA_ARGS__))
74944d4804dSStefan Eßer 
75044d4804dSStefan Eßer /**
75144d4804dSStefan Eßer  * Call bc's error handling routine.
75244d4804dSStefan Eßer  * @param e  The error.
75344d4804dSStefan Eßer  */
75444d4804dSStefan Eßer #define bc_err(e) (bc_vm_handleError((e), 0))
75544d4804dSStefan Eßer 
75644d4804dSStefan Eßer /**
75744d4804dSStefan Eßer  * Call bc's error handling routine.
75844d4804dSStefan Eßer  * @param e  The error.
75944d4804dSStefan Eßer  */
76044d4804dSStefan Eßer #define bc_verr(e, ...) (bc_vm_handleError((e), 0, __VA_ARGS__))
76144d4804dSStefan Eßer 
76244d4804dSStefan Eßer #endif // BC_ENABLE_LIBRARY
76344d4804dSStefan Eßer 
76444d4804dSStefan Eßer /**
76544d4804dSStefan Eßer  * Returns true if status @a s is an error, false otherwise.
76644d4804dSStefan Eßer  * @param s  The status to test.
76744d4804dSStefan Eßer  * @return   True if @a s is an error, false otherwise.
76844d4804dSStefan Eßer  */
76944d4804dSStefan Eßer #define BC_STATUS_IS_ERROR(s) \
77044d4804dSStefan Eßer 	((s) >= BC_STATUS_ERROR_MATH && (s) <= BC_STATUS_ERROR_FATAL)
77144d4804dSStefan Eßer 
77244d4804dSStefan Eßer // Convenience macros that can be placed at the beginning and exits of functions
77344d4804dSStefan Eßer // for easy marking of where functions are entered and exited.
77444d4804dSStefan Eßer #if BC_DEBUG_CODE
77544d4804dSStefan Eßer #define BC_FUNC_ENTER                                              \
77644d4804dSStefan Eßer 	do {                                                           \
77744d4804dSStefan Eßer 		size_t bc_func_enter_i;                                    \
77844d4804dSStefan Eßer 		for (bc_func_enter_i = 0; bc_func_enter_i < vm.func_depth; \
77944d4804dSStefan Eßer 		     ++bc_func_enter_i)                                    \
78044d4804dSStefan Eßer 		{                                                          \
78144d4804dSStefan Eßer 			bc_file_puts(&vm.ferr, bc_flush_none, "  ");           \
78244d4804dSStefan Eßer 		}                                                          \
78344d4804dSStefan Eßer 		vm.func_depth += 1;                                        \
78444d4804dSStefan Eßer 		bc_file_printf(&vm.ferr, "Entering %s\n", __func__);       \
78544d4804dSStefan Eßer 		bc_file_flush(&vm.ferr, bc_flush_none);                    \
78644d4804dSStefan Eßer 	} while (0);
78744d4804dSStefan Eßer 
78844d4804dSStefan Eßer #define BC_FUNC_EXIT                                               \
78944d4804dSStefan Eßer 	do {                                                           \
79044d4804dSStefan Eßer 		size_t bc_func_enter_i;                                    \
79144d4804dSStefan Eßer 		vm.func_depth -= 1;                                        \
79244d4804dSStefan Eßer 		for (bc_func_enter_i = 0; bc_func_enter_i < vm.func_depth; \
79344d4804dSStefan Eßer 		     ++bc_func_enter_i)                                    \
79444d4804dSStefan Eßer 		{                                                          \
79544d4804dSStefan Eßer 			bc_file_puts(&vm.ferr, bc_flush_none, "  ");           \
79644d4804dSStefan Eßer 		}                                                          \
79744d4804dSStefan Eßer 		bc_file_printf(&vm.ferr, "Leaving %s\n", __func__);        \
79844d4804dSStefan Eßer 		bc_file_flush(&vm.ferr, bc_flush_none);                    \
79944d4804dSStefan Eßer 	} while (0);
80044d4804dSStefan Eßer #else // BC_DEBUG_CODE
80144d4804dSStefan Eßer #define BC_FUNC_ENTER
80244d4804dSStefan Eßer #define BC_FUNC_EXIT
80344d4804dSStefan Eßer #endif // BC_DEBUG_CODE
80444d4804dSStefan Eßer 
805252884aeSStefan Eßer #endif // BC_STATUS_H
806