2 * *****************************************************************************
4 * SPDX-License-Identifier: BSD-2-Clause
6 * Copyright (c) 2018-2021 Gavin D. Howard and contributors.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
11 * * Redistributions of source code must retain the above copyright notice, this
12 * list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
30 * *****************************************************************************
32 * All bc status codes and cross-platform portability.
41 // This is used by configure.sh to test for OpenBSD.
42 #ifdef BC_TEST_OPENBSD
44 #error On OpenBSD without _BSD_SOURCE
46 #endif // BC_TEST_OPENBSD
49 #define BC_ENABLED (1)
53 #define DC_ENABLED (1)
56 #ifndef BC_ENABLE_LIBRARY
57 #define BC_ENABLE_LIBRARY (0)
58 #endif // BC_ENABLE_LIBRARY
60 // This is error checking for fuzz builds.
62 #ifndef __AFL_HAVE_MANUAL_CONTROL
63 #error Must compile with afl-clang-fast or afl-clang-lto for fuzzing
64 #endif // __AFL_HAVE_MANUAL_CONTROL
65 #endif // BC_ENABLE_AFL
67 #ifndef BC_ENABLE_MEMCHECK
68 #define BC_ENABLE_MEMCHECK (0)
69 #endif // BC_ENABLE_MEMCHECK
72 * Mark a variable as unused.
73 * @param e The variable to mark as unused.
75 #define BC_UNUSED(e) ((void) (e))
77 // If users want, they can define this to something like __builtin_expect(e, 1).
78 // It might give a performance improvement.
82 * Mark a branch expression as likely.
83 * @param e The expression to mark as likely.
85 #define BC_LIKELY(e) (e)
89 // If users want, they can define this to something like __builtin_expect(e, 0).
90 // It might give a performance improvement.
94 * Mark a branch expression as unlikely.
95 * @param e The expression to mark as unlikely.
97 #define BC_UNLIKELY(e) (e)
102 * Mark a branch expression as an error, if true.
103 * @param e The expression to mark as an error, if true.
105 #define BC_ERR(e) BC_UNLIKELY(e)
108 * Mark a branch expression as not an error, if true.
109 * @param e The expression to mark as not an error, if true.
111 #define BC_NO_ERR(s) BC_LIKELY(s)
113 // Disable extra debug code by default.
114 #ifndef BC_DEBUG_CODE
115 #define BC_DEBUG_CODE (0)
116 #endif // BC_DEBUG_CODE
118 // We want to be able to use _Noreturn on C11 compilers.
119 #if __STDC_VERSION__ >= 201100L
121 #include <stdnoreturn.h>
122 #define BC_NORETURN _Noreturn
125 #else // __STDC_VERSION__
128 #define BC_MUST_RETURN
131 #endif // __STDC_VERSION__
133 #define BC_HAS_UNREACHABLE (0)
134 #define BC_HAS_COMPUTED_GOTO (0)
136 // GCC and Clang complain if fallthroughs are not marked with their special
137 // attribute. Jerks. This creates a define for marking the fallthroughs that is
138 // nothing on other compilers.
139 #if defined(__clang__) || defined(__GNUC__)
141 #if defined(__has_attribute)
143 #if __has_attribute(fallthrough)
144 #define BC_FALLTHROUGH __attribute__((fallthrough));
145 #else // __has_attribute(fallthrough)
146 #define BC_FALLTHROUGH
147 #endif // __has_attribute(fallthrough)
151 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
152 #undef BC_HAS_UNREACHABLE
153 #define BC_HAS_UNREACHABLE (1)
154 #endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
158 #if __clang_major__ >= 4
159 #undef BC_HAS_UNREACHABLE
160 #define BC_HAS_UNREACHABLE (1)
161 #endif // __clang_major__ >= 4
165 #else // defined(__has_attribute)
166 #define BC_FALLTHROUGH
167 #endif // defined(__has_attribute)
168 #else // defined(__clang__) || defined(__GNUC__)
169 #define BC_FALLTHROUGH
170 #endif // defined(__clang__) || defined(__GNUC__)
172 #if BC_HAS_UNREACHABLE
174 #define BC_UNREACHABLE __builtin_unreachable();
176 #else // BC_HAS_UNREACHABLE
180 #define BC_UNREACHABLE __assume(0);
184 #define BC_UNREACHABLE
188 #endif // BC_HAS_UNREACHABLE
192 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
194 #undef BC_HAS_COMPUTED_GOTO
195 #define BC_HAS_COMPUTED_GOTO (1)
197 #endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
203 #if __clang_major__ >= 4
205 #undef BC_HAS_COMPUTED_GOTO
206 #define BC_HAS_COMPUTED_GOTO (1)
208 #endif // __clang_major__ >= 4
212 #ifdef BC_NO_COMPUTED_GOTO
214 #undef BC_HAS_COMPUTED_GOTO
215 #define BC_HAS_COMPUTED_GOTO (0)
217 #endif // BC_NO_COMPUTED_GOTO
221 // The OpenBSD GCC doesn't like inline.
223 #endif // __OpenBSD__
226 // Workarounds for AIX's POSIX incompatibility.
228 #define SIZE_MAX __SIZE_MAX__
231 #define UINTMAX_C __UINTMAX_C
234 #define UINT32_C __UINT32_C
236 #ifndef UINT_FAST32_MAX
237 #define UINT_FAST32_MAX __UINT_FAST32_MAX__
238 #endif // UINT_FAST32_MAX
240 #define UINT16_MAX __UINT16_MAX__
242 #ifndef SIG_ATOMIC_MAX
243 #define SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__
244 #endif // SIG_ATOMIC_MAX
246 // Yes, this has to be here.
249 // All of these set defaults for settings.
253 #ifndef BC_DEFAULT_BANNER
254 #define BC_DEFAULT_BANNER (0)
255 #endif // BC_DEFAULT_BANNER
259 #ifndef BC_DEFAULT_SIGINT_RESET
260 #define BC_DEFAULT_SIGINT_RESET (1)
261 #endif // BC_DEFAULT_SIGINT_RESET
263 #ifndef BC_DEFAULT_TTY_MODE
264 #define BC_DEFAULT_TTY_MODE (1)
265 #endif // BC_DEFAULT_TTY_MODE
267 #ifndef BC_DEFAULT_PROMPT
268 #define BC_DEFAULT_PROMPT BC_DEFAULT_TTY_MODE
269 #endif // BC_DEFAULT_PROMPT
271 // All of these set defaults for settings.
272 #ifndef DC_DEFAULT_SIGINT_RESET
273 #define DC_DEFAULT_SIGINT_RESET (1)
274 #endif // DC_DEFAULT_SIGINT_RESET
276 #ifndef DC_DEFAULT_TTY_MODE
277 #define DC_DEFAULT_TTY_MODE (0)
278 #endif // DC_DEFAULT_TTY_MODE
280 #ifndef DC_DEFAULT_HISTORY
281 #define DC_DEFAULT_HISTORY DC_DEFAULT_TTY_MODE
282 #endif // DC_DEFAULT_HISTORY
284 #ifndef DC_DEFAULT_PROMPT
285 #define DC_DEFAULT_PROMPT DC_DEFAULT_TTY_MODE
286 #endif // DC_DEFAULT_PROMPT
288 /// Statuses, which mark either which category of error happened, or some other
289 /// status that matters.
290 typedef enum BcStatus {
293 BC_STATUS_SUCCESS = 0,
296 BC_STATUS_ERROR_MATH,
298 /// Parse (and lex) error.
299 BC_STATUS_ERROR_PARSE,
302 BC_STATUS_ERROR_EXEC,
305 BC_STATUS_ERROR_FATAL,
310 /// Quit status. This means that bc/dc is in the process of quitting.
315 /// Errors, which are more specific errors.
320 /// Negative number used when not allowed.
321 BC_ERR_MATH_NEGATIVE,
323 /// Non-integer used when not allowed.
324 BC_ERR_MATH_NON_INTEGER,
326 /// Conversion to a hardware integer would overflow.
327 BC_ERR_MATH_OVERFLOW,
330 BC_ERR_MATH_DIVIDE_BY_ZERO,
334 /// An allocation or reallocation failed.
335 BC_ERR_FATAL_ALLOC_ERR,
340 /// File error, such as permissions or file does not exist.
341 BC_ERR_FATAL_FILE_ERR,
343 /// File is binary, not text, error.
344 BC_ERR_FATAL_BIN_FILE,
346 /// Attempted to read a directory as a file error.
347 BC_ERR_FATAL_PATH_DIR,
349 /// Invalid option error.
352 /// Option with required argument not given an argument.
353 BC_ERR_FATAL_OPTION_NO_ARG,
355 /// Option with no argument given an argument.
356 BC_ERR_FATAL_OPTION_ARG,
358 /// Option argument is invalid.
363 /// Invalid ibase value.
366 /// Invalid obase value.
369 /// Invalid scale value.
372 /// Invalid expression parsed by read().
373 BC_ERR_EXEC_READ_EXPR,
375 /// read() used within an expression given to a read() call.
376 BC_ERR_EXEC_REC_READ,
381 /// Stack has too few elements error.
384 /// Register stack has too few elements error.
385 BC_ERR_EXEC_STACK_REGISTER,
387 /// Wrong number of arguments error.
390 /// Undefined function error.
391 BC_ERR_EXEC_UNDEF_FUNC,
393 /// Void value used in an expression error.
394 BC_ERR_EXEC_VOID_VAL,
396 // Parse (and lex errors).
398 /// EOF encountered when not expected error.
401 /// Invalid character error.
404 /// Invalid string (no ending quote) error.
407 /// Invalid comment (no end found) error.
408 BC_ERR_PARSE_COMMENT,
410 /// Invalid token encountered error.
415 /// Invalid expression error.
418 /// Expression is empty error.
419 BC_ERR_PARSE_EMPTY_EXPR,
421 /// Print statement is invalid error.
424 /// Function definition is invalid error.
427 /// Assignment is invalid error.
430 /// No auto identifiers given for an auto statement error.
431 BC_ERR_PARSE_NO_AUTO,
433 /// Duplicate local (parameter or auto) error.
434 BC_ERR_PARSE_DUP_LOCAL,
436 /// Invalid block (within braces) error.
439 /// Invalid return statement for void functions.
440 BC_ERR_PARSE_RET_VOID,
442 /// Reference attached to a variable, not an array, error.
443 BC_ERR_PARSE_REF_VAR,
445 // POSIX-only errors.
447 /// Name length greater than 1 error.
448 BC_ERR_POSIX_NAME_LEN,
450 /// Non-POSIX comment used error.
451 BC_ERR_POSIX_COMMENT,
453 /// Non-POSIX keyword error.
456 /// Non-POSIX . (last) error.
459 /// Non-POSIX return error.
462 /// Non-POSIX boolean operator used error.
465 /// POSIX relation operator used outside if, while, or for statements error.
466 BC_ERR_POSIX_REL_POS,
468 /// Multiple POSIX relation operators used in an if, while, or for statement
470 BC_ERR_POSIX_MULTIREL,
472 /// Empty statements in POSIX for loop error.
475 /// Non-POSIX exponential (scientific or engineering) number used error.
476 BC_ERR_POSIX_EXP_NUM,
478 /// Non-POSIX array reference error.
481 /// Non-POSIX void error.
484 /// Non-POSIX brace position used error.
487 /// String used in expression.
488 BC_ERR_POSIX_EXPR_STRING,
492 // Number of elements.
497 /// A marker for the start of POSIX errors.
498 BC_ERR_POSIX_START = BC_ERR_POSIX_NAME_LEN,
500 /// A marker for the end of POSIX errors.
501 BC_ERR_POSIX_END = BC_ERR_POSIX_EXPR_STRING,
507 // The indices of each category of error in bc_errs[], and used in bc_err_ids[]
508 // to associate actual errors with their categories.
510 /// Math error category.
511 #define BC_ERR_IDX_MATH (0)
513 /// Parse (and lex) error category.
514 #define BC_ERR_IDX_PARSE (1)
516 /// Runtime error category.
517 #define BC_ERR_IDX_EXEC (2)
519 /// Fatal error category.
520 #define BC_ERR_IDX_FATAL (3)
522 /// Number of categories.
523 #define BC_ERR_IDX_NELEMS (4)
525 // If bc is enabled, we add an extra category for POSIX warnings.
528 /// POSIX warning category.
529 #define BC_ERR_IDX_WARN (BC_ERR_IDX_NELEMS)
533 /// Do a longjmp(). This is what to use when activating an "exception", i.e., a
534 /// longjmp(). With debug code, it will print the name of the function it jumped
537 #define BC_JMP bc_vm_jmp(__func__)
538 #else // BC_DEBUG_CODE
539 #define BC_JMP bc_vm_jmp()
540 #endif // BC_DEBUG_CODE
542 /// Returns true if an exception is in flight, false otherwise.
544 BC_UNLIKELY(vm.status != (sig_atomic_t) BC_STATUS_SUCCESS || vm.sig)
546 /// Returns true if there is *no* exception in flight, false otherwise.
547 #define BC_NO_SIG_EXC \
548 BC_LIKELY(vm.status == (sig_atomic_t) BC_STATUS_SUCCESS && !vm.sig)
552 /// Assert that signals are locked. There are non-async-signal-safe functions in
553 /// bc, and they *must* have signals locked. Other functions are expected to
554 /// *not* have signals locked, for reasons. So this is a pre-built assert
555 /// (no-op in non-debug mode) that check that signals are locked.
556 #define BC_SIG_ASSERT_LOCKED do { assert(vm.sig_lock); } while (0)
558 /// Assert that signals are unlocked. There are non-async-signal-safe functions
559 /// in bc, and they *must* have signals locked. Other functions are expected to
560 /// *not* have signals locked, for reasons. So this is a pre-built assert
561 /// (no-op in non-debug mode) that check that signals are unlocked.
562 #define BC_SIG_ASSERT_NOT_LOCKED do { assert(vm.sig_lock == 0); } while (0)
566 /// Assert that signals are locked. There are non-async-signal-safe functions in
567 /// bc, and they *must* have signals locked. Other functions are expected to
568 /// *not* have signals locked, for reasons. So this is a pre-built assert
569 /// (no-op in non-debug mode) that check that signals are locked.
570 #define BC_SIG_ASSERT_LOCKED
572 /// Assert that signals are unlocked. There are non-async-signal-safe functions
573 /// in bc, and they *must* have signals locked. Other functions are expected to
574 /// *not* have signals locked, for reasons. So this is a pre-built assert
575 /// (no-op in non-debug mode) that check that signals are unlocked.
576 #define BC_SIG_ASSERT_NOT_LOCKED
581 #define BC_SIG_LOCK \
583 BC_SIG_ASSERT_NOT_LOCKED; \
587 /// Unlocks signals. If a signal happened, then this will cause a jump.
588 #define BC_SIG_UNLOCK \
590 BC_SIG_ASSERT_LOCKED; \
592 if (vm.sig) BC_JMP; \
595 /// Locks signals, regardless of if they are already locked. This is really only
596 /// used after labels that longjmp() goes to after the jump because the cleanup
597 /// code must have signals locked, and BC_LONGJMP_CONT will unlock signals if it
599 #define BC_SIG_MAYLOCK \
604 /// Unlocks signals, regardless of if they were already unlocked. If a signal
605 /// happened, then this will cause a jump.
606 #define BC_SIG_MAYUNLOCK \
609 if (vm.sig) BC_JMP; \
613 * Locks signals, but stores the old lock state, to be restored later by
615 * @param v The variable to store the old lock state to.
617 #define BC_SIG_TRYLOCK(v) \
623 /* Restores the previous state of a signal lock, and if it is now unlocked,
624 * initiates an exception/jump.
625 * @param v The old lock state.
627 #define BC_SIG_TRYUNLOCK(v) \
630 if (!(v) && vm.sig) BC_JMP; \
634 * Sets a jump, and sets it up as well so that if a longjmp() happens, bc will
635 * immediately goto a label where some cleanup code is. This one assumes that
636 * signals are not locked and will lock them, set the jump, and unlock them.
637 * Setting the jump also includes pushing the jmp_buf onto the jmp_buf stack.
638 * This grows the jmp_bufs vector first to prevent a fatal error from happening
639 * after the setjmp(). This is done because BC_SETJMP(l) is assumed to be used
640 * *before* the actual initialization calls that need the setjmp().
641 * param l The label to jump to on a longjmp().
643 #define BC_SETJMP(l) \
647 bc_vec_grow(&vm.jmp_bufs, 1); \
648 if (sigsetjmp(sjb, 0)) { \
649 assert(BC_SIG_EXC); \
652 bc_vec_push(&vm.jmp_bufs, &sjb); \
657 * Sets a jump like BC_SETJMP, but unlike BC_SETJMP, it assumes signals are
658 * locked and will just set the jump. This does *not* have a call to
659 * bc_vec_grow() because it is assumed that BC_SETJMP_LOCKED(l) is used *after*
660 * the initializations that need the setjmp().
661 * param l The label to jump to on a longjmp().
663 #define BC_SETJMP_LOCKED(l) \
666 BC_SIG_ASSERT_LOCKED; \
667 if (sigsetjmp(sjb, 0)) { \
668 assert(BC_SIG_EXC); \
671 bc_vec_push(&vm.jmp_bufs, &sjb); \
674 /// Used after cleanup labels set by BC_SETJMP and BC_SETJMP_LOCKED to jump to
675 /// the next place. This is what continues the stack unwinding. This basically
676 /// copies BC_SIG_UNLOCK into itself, but that is because its condition for
677 /// jumping is BC_SIG_EXC, not just that a signal happened.
678 #define BC_LONGJMP_CONT \
680 BC_SIG_ASSERT_LOCKED; \
681 if (!vm.sig_pop) bc_vec_pop(&vm.jmp_bufs); \
683 if (BC_SIG_EXC) BC_JMP; \
686 /// Unsets a jump. It always assumes signals are locked. This basically just
687 /// pops a jmp_buf off of the stack of jmp_bufs, and since the jump mechanism
688 /// always jumps to the location at the top of the stack, this effectively
689 /// undoes a setjmp().
690 #define BC_UNSETJMP \
692 BC_SIG_ASSERT_LOCKED; \
693 bc_vec_pop(&vm.jmp_bufs); \
696 /// Stops a stack unwinding. Technically, a stack unwinding needs to be done
697 /// manually, but it will always be done unless certain flags are cleared. This
698 /// clears the flags.
699 #define BC_LONGJMP_STOP \
705 // Various convenience macros for calling the bc's error handling routine.
706 #if BC_ENABLE_LIBRARY
709 * Call bc's error handling routine.
710 * @param e The error.
711 * @param l The line of the script that the error happened.
712 * @param ... Extra arguments for error messages as necessary.
714 #define bc_error(e, l, ...) (bc_vm_handleError((e)))
717 * Call bc's error handling routine.
718 * @param e The error.
720 #define bc_err(e) (bc_vm_handleError((e)))
723 * Call bc's error handling routine.
724 * @param e The error.
726 #define bc_verr(e, ...) (bc_vm_handleError((e)))
728 #else // BC_ENABLE_LIBRARY
731 * Call bc's error handling routine.
732 * @param e The error.
733 * @param l The line of the script that the error happened.
734 * @param ... Extra arguments for error messages as necessary.
736 #define bc_error(e, l, ...) (bc_vm_handleError((e), (l), __VA_ARGS__))
739 * Call bc's error handling routine.
740 * @param e The error.
742 #define bc_err(e) (bc_vm_handleError((e), 0))
745 * Call bc's error handling routine.
746 * @param e The error.
748 #define bc_verr(e, ...) (bc_vm_handleError((e), 0, __VA_ARGS__))
750 #endif // BC_ENABLE_LIBRARY
753 * Returns true if status @a s is an error, false otherwise.
754 * @param s The status to test.
755 * @return True if @a s is an error, false otherwise.
757 #define BC_STATUS_IS_ERROR(s) \
758 ((s) >= BC_STATUS_ERROR_MATH && (s) <= BC_STATUS_ERROR_FATAL)
760 // Convenience macros that can be placed at the beginning and exits of functions
761 // for easy marking of where functions are entered and exited.
763 #define BC_FUNC_ENTER \
765 size_t bc_func_enter_i; \
766 for (bc_func_enter_i = 0; bc_func_enter_i < vm.func_depth; \
769 bc_file_puts(&vm.ferr, bc_flush_none, " "); \
771 vm.func_depth += 1; \
772 bc_file_printf(&vm.ferr, "Entering %s\n", __func__); \
773 bc_file_flush(&vm.ferr, bc_flush_none); \
776 #define BC_FUNC_EXIT \
778 size_t bc_func_enter_i; \
779 vm.func_depth -= 1; \
780 for (bc_func_enter_i = 0; bc_func_enter_i < vm.func_depth; \
783 bc_file_puts(&vm.ferr, bc_flush_none, " "); \
785 bc_file_printf(&vm.ferr, "Leaving %s\n", __func__); \
786 bc_file_flush(&vm.ferr, bc_flush_none); \
788 #else // BC_DEBUG_CODE
789 #define BC_FUNC_ENTER
791 #endif // BC_DEBUG_CODE
793 #endif // BC_STATUS_H