xref: /freebsd/contrib/bc/include/status.h (revision cab6a39d7b343596a5823e65c0f7b426551ec22d)
1 /*
2  * *****************************************************************************
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  *
6  * Copyright (c) 2018-2021 Gavin D. Howard and contributors.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * * Redistributions of source code must retain the above copyright notice, this
12  *   list of conditions and the following disclaimer.
13  *
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.
17  *
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.
29  *
30  * *****************************************************************************
31  *
32  * All bc status codes and cross-platform portability.
33  *
34  */
35 
36 #ifndef BC_STATUS_H
37 #define BC_STATUS_H
38 
39 #include <stdint.h>
40 
41 // This is used by configure.sh to test for OpenBSD.
42 #ifdef BC_TEST_OPENBSD
43 #ifdef __OpenBSD__
44 #error On OpenBSD without _BSD_SOURCE
45 #endif // __OpenBSD__
46 #endif // BC_TEST_OPENBSD
47 
48 #ifndef BC_ENABLED
49 #define BC_ENABLED (1)
50 #endif // BC_ENABLED
51 
52 #ifndef DC_ENABLED
53 #define DC_ENABLED (1)
54 #endif // DC_ENABLED
55 
56 // This is error checking for fuzz builds.
57 #if BC_ENABLE_AFL
58 #ifndef __AFL_HAVE_MANUAL_CONTROL
59 #error Must compile with afl-clang-fast or afl-clang-lto for fuzzing
60 #endif // __AFL_HAVE_MANUAL_CONTROL
61 #endif // BC_ENABLE_AFL
62 
63 #ifndef BC_ENABLE_MEMCHECK
64 #define BC_ENABLE_MEMCHECK (0)
65 #endif // BC_ENABLE_MEMCHECK
66 
67 /**
68  * Mark a variable as unused.
69  * @param e  The variable to mark as unused.
70  */
71 #define BC_UNUSED(e) ((void) (e))
72 
73 // If users want, they can define this to something like __builtin_expect(e, 1).
74 // It might give a performance improvement.
75 #ifndef BC_LIKELY
76 
77 /**
78  * Mark a branch expression as likely.
79  * @param e  The expression to mark as likely.
80  */
81 #define BC_LIKELY(e) (e)
82 
83 #endif // BC_LIKELY
84 
85 // If users want, they can define this to something like __builtin_expect(e, 0).
86 // It might give a performance improvement.
87 #ifndef BC_UNLIKELY
88 
89 /**
90  * Mark a branch expression as unlikely.
91  * @param e  The expression to mark as unlikely.
92  */
93 #define BC_UNLIKELY(e) (e)
94 
95 #endif // BC_UNLIKELY
96 
97 /**
98  * Mark a branch expression as an error, if true.
99  * @param e  The expression to mark as an error, if true.
100  */
101 #define BC_ERR(e) BC_UNLIKELY(e)
102 
103 /**
104  * Mark a branch expression as not an error, if true.
105  * @param e  The expression to mark as not an error, if true.
106  */
107 #define BC_NO_ERR(s) BC_LIKELY(s)
108 
109 // Disable extra debug code by default.
110 #ifndef BC_DEBUG_CODE
111 #define BC_DEBUG_CODE (0)
112 #endif // BC_DEBUG_CODE
113 
114 // We want to be able to use _Noreturn on C11 compilers.
115 #if __STDC_VERSION__ >= 201100L
116 
117 #include <stdnoreturn.h>
118 #define BC_NORETURN _Noreturn
119 #define BC_C11 (1)
120 
121 #else // __STDC_VERSION__
122 
123 #define BC_NORETURN
124 #define BC_MUST_RETURN
125 #define BC_C11 (0)
126 
127 #endif // __STDC_VERSION__
128 
129 #define BC_HAS_UNREACHABLE (0)
130 #define BC_HAS_COMPUTED_GOTO (0)
131 
132 // GCC and Clang complain if fallthroughs are not marked with their special
133 // attribute. Jerks. This creates a define for marking the fallthroughs that is
134 // nothing on other compilers.
135 #if defined(__clang__) || defined(__GNUC__)
136 
137 #if defined(__has_attribute)
138 
139 #if __has_attribute(fallthrough)
140 #define BC_FALLTHROUGH __attribute__((fallthrough));
141 #else // __has_attribute(fallthrough)
142 #define BC_FALLTHROUGH
143 #endif // __has_attribute(fallthrough)
144 
145 #ifdef __GNUC__
146 
147 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
148 #undef BC_HAS_UNREACHABLE
149 #define BC_HAS_UNREACHABLE (1)
150 #endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
151 
152 #else // __GNUC__
153 
154 #if __clang_major__ >= 4
155 #undef BC_HAS_UNREACHABLE
156 #define BC_HAS_UNREACHABLE (1)
157 #endif // __clang_major__ >= 4
158 
159 #endif // __GNUC__
160 
161 #else // defined(__has_attribute)
162 #define BC_FALLTHROUGH
163 #endif // defined(__has_attribute)
164 #else // defined(__clang__) || defined(__GNUC__)
165 #define BC_FALLTHROUGH
166 #endif // defined(__clang__) || defined(__GNUC__)
167 
168 #if BC_HAS_UNREACHABLE
169 
170 #define BC_UNREACHABLE __builtin_unreachable();
171 
172 #else // BC_HAS_UNREACHABLE
173 
174 #ifdef _WIN32
175 
176 #define BC_UNREACHABLE __assume(0);
177 
178 #else // _WIN32
179 
180 #define BC_UNREACHABLE
181 
182 #endif // _WIN32
183 
184 #endif // BC_HAS_UNREACHABLE
185 
186 #ifdef __GNUC__
187 
188 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
189 
190 #undef BC_HAS_COMPUTED_GOTO
191 #define BC_HAS_COMPUTED_GOTO (1)
192 
193 #endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
194 
195 #endif // __GNUC__
196 
197 #ifdef __clang__
198 
199 #if __clang_major__ >= 4
200 
201 #undef BC_HAS_COMPUTED_GOTO
202 #define BC_HAS_COMPUTED_GOTO (1)
203 
204 #endif // __clang_major__ >= 4
205 
206 #endif // __GNUC__
207 
208 #ifdef BC_NO_COMPUTED_GOTO
209 
210 #undef BC_HAS_COMPUTED_GOTO
211 #define BC_HAS_COMPUTED_GOTO (0)
212 
213 #endif // BC_NO_COMPUTED_GOTO
214 
215 #ifdef __GNUC__
216 #ifdef __OpenBSD__
217 // The OpenBSD GCC doesn't like inline.
218 #define inline
219 #endif // __OpenBSD__
220 #endif // __GNUC__
221 
222 // Workarounds for AIX's POSIX incompatibility.
223 #ifndef SIZE_MAX
224 #define SIZE_MAX __SIZE_MAX__
225 #endif // SIZE_MAX
226 #ifndef UINTMAX_C
227 #define UINTMAX_C __UINTMAX_C
228 #endif // UINTMAX_C
229 #ifndef UINT32_C
230 #define UINT32_C __UINT32_C
231 #endif // UINT32_C
232 #ifndef UINT_FAST32_MAX
233 #define UINT_FAST32_MAX __UINT_FAST32_MAX__
234 #endif // UINT_FAST32_MAX
235 #ifndef UINT16_MAX
236 #define UINT16_MAX __UINT16_MAX__
237 #endif // UINT16_MAX
238 #ifndef SIG_ATOMIC_MAX
239 #define SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__
240 #endif // SIG_ATOMIC_MAX
241 
242 // Yes, this has to be here.
243 #include <bcl.h>
244 
245 // All of these set defaults for settings.
246 
247 #if BC_ENABLED
248 
249 #ifndef BC_DEFAULT_BANNER
250 #define BC_DEFAULT_BANNER (0)
251 #endif // BC_DEFAULT_BANNER
252 
253 #endif // BC_ENABLED
254 
255 #ifndef BC_DEFAULT_SIGINT_RESET
256 #define BC_DEFAULT_SIGINT_RESET (1)
257 #endif // BC_DEFAULT_SIGINT_RESET
258 
259 #ifndef BC_DEFAULT_TTY_MODE
260 #define BC_DEFAULT_TTY_MODE (1)
261 #endif // BC_DEFAULT_TTY_MODE
262 
263 #ifndef BC_DEFAULT_PROMPT
264 #define BC_DEFAULT_PROMPT BC_DEFAULT_TTY_MODE
265 #endif // BC_DEFAULT_PROMPT
266 
267 // All of these set defaults for settings.
268 #ifndef DC_DEFAULT_SIGINT_RESET
269 #define DC_DEFAULT_SIGINT_RESET (1)
270 #endif // DC_DEFAULT_SIGINT_RESET
271 
272 #ifndef DC_DEFAULT_TTY_MODE
273 #define DC_DEFAULT_TTY_MODE (0)
274 #endif // DC_DEFAULT_TTY_MODE
275 
276 #ifndef DC_DEFAULT_HISTORY
277 #define DC_DEFAULT_HISTORY DC_DEFAULT_TTY_MODE
278 #endif // DC_DEFAULT_HISTORY
279 
280 #ifndef DC_DEFAULT_PROMPT
281 #define DC_DEFAULT_PROMPT DC_DEFAULT_TTY_MODE
282 #endif // DC_DEFAULT_PROMPT
283 
284 /// Statuses, which mark either which category of error happened, or some other
285 /// status that matters.
286 typedef enum BcStatus {
287 
288 	/// Normal status.
289 	BC_STATUS_SUCCESS = 0,
290 
291 	/// Math error.
292 	BC_STATUS_ERROR_MATH,
293 
294 	/// Parse (and lex) error.
295 	BC_STATUS_ERROR_PARSE,
296 
297 	/// Runtime error.
298 	BC_STATUS_ERROR_EXEC,
299 
300 	/// Fatal error.
301 	BC_STATUS_ERROR_FATAL,
302 
303 	/// EOF status.
304 	BC_STATUS_EOF,
305 
306 	/// Quit status. This means that bc/dc is in the process of quitting.
307 	BC_STATUS_QUIT,
308 
309 } BcStatus;
310 
311 /// Errors, which are more specific errors.
312 typedef enum BcErr {
313 
314 	// Math errors.
315 
316 	/// Negative number used when not allowed.
317 	BC_ERR_MATH_NEGATIVE,
318 
319 	/// Non-integer used when not allowed.
320 	BC_ERR_MATH_NON_INTEGER,
321 
322 	/// Conversion to a hardware integer would overflow.
323 	BC_ERR_MATH_OVERFLOW,
324 
325 	/// Divide by zero.
326 	BC_ERR_MATH_DIVIDE_BY_ZERO,
327 
328 	// Fatal errors.
329 
330 	/// An allocation or reallocation failed.
331 	BC_ERR_FATAL_ALLOC_ERR,
332 
333 	/// I/O failure.
334 	BC_ERR_FATAL_IO_ERR,
335 
336 	/// File error, such as permissions or file does not exist.
337 	BC_ERR_FATAL_FILE_ERR,
338 
339 	/// File is binary, not text, error.
340 	BC_ERR_FATAL_BIN_FILE,
341 
342 	/// Attempted to read a directory as a file error.
343 	BC_ERR_FATAL_PATH_DIR,
344 
345 	/// Invalid option error.
346 	BC_ERR_FATAL_OPTION,
347 
348 	/// Option with required argument not given an argument.
349 	BC_ERR_FATAL_OPTION_NO_ARG,
350 
351 	/// Option with no argument given an argument.
352 	BC_ERR_FATAL_OPTION_ARG,
353 
354 	/// Option argument is invalid.
355 	BC_ERR_FATAL_ARG,
356 
357 	// Runtime errors.
358 
359 	/// Invalid ibase value.
360 	BC_ERR_EXEC_IBASE,
361 
362 	/// Invalid obase value.
363 	BC_ERR_EXEC_OBASE,
364 
365 	/// Invalid scale value.
366 	BC_ERR_EXEC_SCALE,
367 
368 	/// Invalid expression parsed by read().
369 	BC_ERR_EXEC_READ_EXPR,
370 
371 	/// read() used within an expression given to a read() call.
372 	BC_ERR_EXEC_REC_READ,
373 
374 	/// Type error.
375 	BC_ERR_EXEC_TYPE,
376 
377 	/// Stack has too few elements error.
378 	BC_ERR_EXEC_STACK,
379 
380 	/// Register stack has too few elements error.
381 	BC_ERR_EXEC_STACK_REGISTER,
382 
383 	/// Wrong number of arguments error.
384 	BC_ERR_EXEC_PARAMS,
385 
386 	/// Undefined function error.
387 	BC_ERR_EXEC_UNDEF_FUNC,
388 
389 	/// Void value used in an expression error.
390 	BC_ERR_EXEC_VOID_VAL,
391 
392 	// Parse (and lex errors).
393 
394 	/// EOF encountered when not expected error.
395 	BC_ERR_PARSE_EOF,
396 
397 	/// Invalid character error.
398 	BC_ERR_PARSE_CHAR,
399 
400 	/// Invalid string (no ending quote) error.
401 	BC_ERR_PARSE_STRING,
402 
403 	/// Invalid comment (no end found) error.
404 	BC_ERR_PARSE_COMMENT,
405 
406 	/// Invalid token encountered error.
407 	BC_ERR_PARSE_TOKEN,
408 
409 #if BC_ENABLED
410 
411 	/// Invalid expression error.
412 	BC_ERR_PARSE_EXPR,
413 
414 	/// Expression is empty error.
415 	BC_ERR_PARSE_EMPTY_EXPR,
416 
417 	/// Print statement is invalid error.
418 	BC_ERR_PARSE_PRINT,
419 
420 	/// Function definition is invalid error.
421 	BC_ERR_PARSE_FUNC,
422 
423 	/// Assignment is invalid error.
424 	BC_ERR_PARSE_ASSIGN,
425 
426 	/// No auto identifiers given for an auto statement error.
427 	BC_ERR_PARSE_NO_AUTO,
428 
429 	/// Duplicate local (parameter or auto) error.
430 	BC_ERR_PARSE_DUP_LOCAL,
431 
432 	/// Invalid block (within braces) error.
433 	BC_ERR_PARSE_BLOCK,
434 
435 	/// Invalid return statement for void functions.
436 	BC_ERR_PARSE_RET_VOID,
437 
438 	/// Reference attached to a variable, not an array, error.
439 	BC_ERR_PARSE_REF_VAR,
440 
441 	// POSIX-only errors.
442 
443 	/// Name length greater than 1 error.
444 	BC_ERR_POSIX_NAME_LEN,
445 
446 	/// Non-POSIX comment used error.
447 	BC_ERR_POSIX_COMMENT,
448 
449 	/// Non-POSIX keyword error.
450 	BC_ERR_POSIX_KW,
451 
452 	/// Non-POSIX . (last) error.
453 	BC_ERR_POSIX_DOT,
454 
455 	/// Non-POSIX return error.
456 	BC_ERR_POSIX_RET,
457 
458 	/// Non-POSIX boolean operator used error.
459 	BC_ERR_POSIX_BOOL,
460 
461 	/// POSIX relation operator used outside if, while, or for statements error.
462 	BC_ERR_POSIX_REL_POS,
463 
464 	/// Multiple POSIX relation operators used in an if, while, or for statement
465 	/// error.
466 	BC_ERR_POSIX_MULTIREL,
467 
468 	/// Empty statements in POSIX for loop error.
469 	BC_ERR_POSIX_FOR,
470 
471 	/// Non-POSIX exponential (scientific or engineering) number used error.
472 	BC_ERR_POSIX_EXP_NUM,
473 
474 	/// Non-POSIX array reference error.
475 	BC_ERR_POSIX_REF,
476 
477 	/// Non-POSIX void error.
478 	BC_ERR_POSIX_VOID,
479 
480 	/// Non-POSIX brace position used error.
481 	BC_ERR_POSIX_BRACE,
482 
483 	/// String used in expression.
484 	BC_ERR_POSIX_EXPR_STRING,
485 
486 #endif // BC_ENABLED
487 
488 	// Number of elements.
489 	BC_ERR_NELEMS,
490 
491 #if BC_ENABLED
492 
493 	/// A marker for the start of POSIX errors.
494 	BC_ERR_POSIX_START = BC_ERR_POSIX_NAME_LEN,
495 
496 	/// A marker for the end of POSIX errors.
497 	BC_ERR_POSIX_END = BC_ERR_POSIX_EXPR_STRING,
498 
499 #endif // BC_ENABLED
500 
501 } BcErr;
502 
503 // The indices of each category of error in bc_errs[], and used in bc_err_ids[]
504 // to associate actual errors with their categories.
505 
506 /// Math error category.
507 #define BC_ERR_IDX_MATH (0)
508 
509 /// Parse (and lex) error category.
510 #define BC_ERR_IDX_PARSE (1)
511 
512 /// Runtime error category.
513 #define BC_ERR_IDX_EXEC (2)
514 
515 /// Fatal error category.
516 #define BC_ERR_IDX_FATAL (3)
517 
518 /// Number of categories.
519 #define BC_ERR_IDX_NELEMS (4)
520 
521 // If bc is enabled, we add an extra category for POSIX warnings.
522 #if BC_ENABLED
523 
524 /// POSIX warning category.
525 #define BC_ERR_IDX_WARN (BC_ERR_IDX_NELEMS)
526 
527 #endif // BC_ENABLED
528 
529 /// Do a longjmp(). This is what to use when activating an "exception", i.e., a
530 /// longjmp(). With debug code, it will print the name of the function it jumped
531 /// from.
532 #if BC_DEBUG_CODE
533 #define BC_JMP bc_vm_jmp(__func__)
534 #else // BC_DEBUG_CODE
535 #define BC_JMP bc_vm_jmp()
536 #endif // BC_DEBUG_CODE
537 
538 /// Returns true if an exception is in flight, false otherwise.
539 #define BC_SIG_EXC \
540 	BC_UNLIKELY(vm.status != (sig_atomic_t) BC_STATUS_SUCCESS || vm.sig)
541 
542 /// Returns true if there is *no* exception in flight, false otherwise.
543 #define BC_NO_SIG_EXC \
544 	BC_LIKELY(vm.status == (sig_atomic_t) BC_STATUS_SUCCESS && !vm.sig)
545 
546 #ifndef NDEBUG
547 
548 /// Assert that signals are locked. There are non-async-signal-safe functions in
549 /// bc, and they *must* have signals locked. Other functions are expected to
550 /// *not* have signals locked, for reasons. So this is a pre-built assert
551 /// (no-op in non-debug mode) that check that signals are locked.
552 #define BC_SIG_ASSERT_LOCKED do { assert(vm.sig_lock); } while (0)
553 
554 /// Assert that signals are unlocked. There are non-async-signal-safe functions
555 /// in bc, and they *must* have signals locked. Other functions are expected to
556 /// *not* have signals locked, for reasons. So this is a pre-built assert
557 /// (no-op in non-debug mode) that check that signals are unlocked.
558 #define BC_SIG_ASSERT_NOT_LOCKED do { assert(vm.sig_lock == 0); } while (0)
559 
560 #else // NDEBUG
561 
562 /// Assert that signals are locked. There are non-async-signal-safe functions in
563 /// bc, and they *must* have signals locked. Other functions are expected to
564 /// *not* have signals locked, for reasons. So this is a pre-built assert
565 /// (no-op in non-debug mode) that check that signals are locked.
566 #define BC_SIG_ASSERT_LOCKED
567 
568 /// Assert that signals are unlocked. There are non-async-signal-safe functions
569 /// in bc, and they *must* have signals locked. Other functions are expected to
570 /// *not* have signals locked, for reasons. So this is a pre-built assert
571 /// (no-op in non-debug mode) that check that signals are unlocked.
572 #define BC_SIG_ASSERT_NOT_LOCKED
573 
574 #endif // NDEBUG
575 
576 /// Locks signals.
577 #define BC_SIG_LOCK               \
578 	do {                          \
579 		BC_SIG_ASSERT_NOT_LOCKED; \
580 		vm.sig_lock = 1;          \
581 	} while (0)
582 
583 /// Unlocks signals. If a signal happened, then this will cause a jump.
584 #define BC_SIG_UNLOCK         \
585 	do {                      \
586 		BC_SIG_ASSERT_LOCKED; \
587 		vm.sig_lock = 0;      \
588 		if (vm.sig) BC_JMP;   \
589 	} while (0)
590 
591 /// Locks signals, regardless of if they are already locked. This is really only
592 /// used after labels that longjmp() goes to after the jump because the cleanup
593 /// code must have signals locked, and BC_LONGJMP_CONT will unlock signals if it
594 /// doesn't jump.
595 #define BC_SIG_MAYLOCK   \
596 	do {                 \
597 		vm.sig_lock = 1; \
598 	} while (0)
599 
600 /// Unlocks signals, regardless of if they were already unlocked. If a signal
601 /// happened, then this will cause a jump.
602 #define BC_SIG_MAYUNLOCK    \
603 	do {                    \
604 		vm.sig_lock = 0;    \
605 		if (vm.sig) BC_JMP; \
606 	} while (0)
607 
608 /*
609  * Locks signals, but stores the old lock state, to be restored later by
610  * BC_SIG_TRYUNLOCK.
611  * @param v  The variable to store the old lock state to.
612  */
613 #define BC_SIG_TRYLOCK(v) \
614 	do {                  \
615 		v = vm.sig_lock;  \
616 		vm.sig_lock = 1;  \
617 	} while (0)
618 
619 /* Restores the previous state of a signal lock, and if it is now unlocked,
620  * initiates an exception/jump.
621  * @param v  The old lock state.
622  */
623 #define BC_SIG_TRYUNLOCK(v)         \
624 	do {                            \
625 		vm.sig_lock = (v);          \
626 		if (!(v) && vm.sig) BC_JMP; \
627 	} while (0)
628 
629 /**
630  * Sets a jump, and sets it up as well so that if a longjmp() happens, bc will
631  * immediately goto a label where some cleanup code is. This one assumes that
632  * signals are not locked and will lock them, set the jump, and unlock them.
633  * Setting the jump also includes pushing the jmp_buf onto the jmp_buf stack.
634  * This grows the jmp_bufs vector first to prevent a fatal error from happening
635  * after the setjmp(). This is done because BC_SETJMP(l) is assumed to be used
636  * *before* the actual initialization calls that need the setjmp().
637  * param l  The label to jump to on a longjmp().
638  */
639 #define BC_SETJMP(l)                     \
640 	do {                                 \
641 		sigjmp_buf sjb;                  \
642 		BC_SIG_LOCK;                     \
643 		bc_vec_grow(&vm.jmp_bufs, 1);    \
644 		if (sigsetjmp(sjb, 0)) {         \
645 			assert(BC_SIG_EXC);          \
646 			goto l;                      \
647 		}                                \
648 		bc_vec_push(&vm.jmp_bufs, &sjb); \
649 		BC_SIG_UNLOCK;                   \
650 	} while (0)
651 
652 /**
653  * Sets a jump like BC_SETJMP, but unlike BC_SETJMP, it assumes signals are
654  * locked and will just set the jump. This does *not* have a call to
655  * bc_vec_grow() because it is assumed that BC_SETJMP_LOCKED(l) is used *after*
656  * the initializations that need the setjmp().
657  * param l  The label to jump to on a longjmp().
658  */
659 #define BC_SETJMP_LOCKED(l)              \
660 	do {                                 \
661 		sigjmp_buf sjb;                  \
662 		BC_SIG_ASSERT_LOCKED;            \
663 		if (sigsetjmp(sjb, 0)) {         \
664 			assert(BC_SIG_EXC);          \
665 			goto l;                      \
666 		}                                \
667 		bc_vec_push(&vm.jmp_bufs, &sjb); \
668 	} while (0)
669 
670 /// Used after cleanup labels set by BC_SETJMP and BC_SETJMP_LOCKED to jump to
671 /// the next place. This is what continues the stack unwinding. This basically
672 /// copies BC_SIG_UNLOCK into itself, but that is because its condition for
673 /// jumping is BC_SIG_EXC, not just that a signal happened.
674 #define BC_LONGJMP_CONT                            \
675 	do {                                           \
676 		BC_SIG_ASSERT_LOCKED;                      \
677 		if (!vm.sig_pop) bc_vec_pop(&vm.jmp_bufs); \
678 		vm.sig_lock = 0;                           \
679 		if (BC_SIG_EXC) BC_JMP;                    \
680 	} while (0)
681 
682 /// Unsets a jump. It always assumes signals are locked. This basically just
683 /// pops a jmp_buf off of the stack of jmp_bufs, and since the jump mechanism
684 /// always jumps to the location at the top of the stack, this effectively
685 /// undoes a setjmp().
686 #define BC_UNSETJMP               \
687 	do {                          \
688 		BC_SIG_ASSERT_LOCKED;     \
689 		bc_vec_pop(&vm.jmp_bufs); \
690 	} while (0)
691 
692 /// Stops a stack unwinding. Technically, a stack unwinding needs to be done
693 /// manually, but it will always be done unless certain flags are cleared. This
694 /// clears the flags.
695 #define BC_LONGJMP_STOP \
696 	do {                \
697 		vm.sig_pop = 0; \
698 		vm.sig = 0;     \
699 	} while (0)
700 
701 // Various convenience macros for calling the bc's error handling routine.
702 #if BC_ENABLE_LIBRARY
703 
704 /**
705  * Call bc's error handling routine.
706  * @param e    The error.
707  * @param l    The line of the script that the error happened.
708  * @param ...  Extra arguments for error messages as necessary.
709  */
710 #define bc_error(e, l, ...) (bc_vm_handleError((e)))
711 
712 /**
713  * Call bc's error handling routine.
714  * @param e  The error.
715  */
716 #define bc_err(e) (bc_vm_handleError((e)))
717 
718 /**
719  * Call bc's error handling routine.
720  * @param e  The error.
721  */
722 #define bc_verr(e, ...) (bc_vm_handleError((e)))
723 
724 #else // BC_ENABLE_LIBRARY
725 
726 /**
727  * Call bc's error handling routine.
728  * @param e    The error.
729  * @param l    The line of the script that the error happened.
730  * @param ...  Extra arguments for error messages as necessary.
731  */
732 #define bc_error(e, l, ...) (bc_vm_handleError((e), (l), __VA_ARGS__))
733 
734 /**
735  * Call bc's error handling routine.
736  * @param e  The error.
737  */
738 #define bc_err(e) (bc_vm_handleError((e), 0))
739 
740 /**
741  * Call bc's error handling routine.
742  * @param e  The error.
743  */
744 #define bc_verr(e, ...) (bc_vm_handleError((e), 0, __VA_ARGS__))
745 
746 #endif // BC_ENABLE_LIBRARY
747 
748 /**
749  * Returns true if status @a s is an error, false otherwise.
750  * @param s  The status to test.
751  * @return   True if @a s is an error, false otherwise.
752  */
753 #define BC_STATUS_IS_ERROR(s) \
754 	((s) >= BC_STATUS_ERROR_MATH && (s) <= BC_STATUS_ERROR_FATAL)
755 
756 // Convenience macros that can be placed at the beginning and exits of functions
757 // for easy marking of where functions are entered and exited.
758 #if BC_DEBUG_CODE
759 #define BC_FUNC_ENTER                                              \
760 	do {                                                           \
761 		size_t bc_func_enter_i;                                    \
762 		for (bc_func_enter_i = 0; bc_func_enter_i < vm.func_depth; \
763 		     ++bc_func_enter_i)                                    \
764 		{                                                          \
765 			bc_file_puts(&vm.ferr, bc_flush_none, "  ");           \
766 		}                                                          \
767 		vm.func_depth += 1;                                        \
768 		bc_file_printf(&vm.ferr, "Entering %s\n", __func__);       \
769 		bc_file_flush(&vm.ferr, bc_flush_none);                    \
770 	} while (0);
771 
772 #define BC_FUNC_EXIT                                               \
773 	do {                                                           \
774 		size_t bc_func_enter_i;                                    \
775 		vm.func_depth -= 1;                                        \
776 		for (bc_func_enter_i = 0; bc_func_enter_i < vm.func_depth; \
777 		     ++bc_func_enter_i)                                    \
778 		{                                                          \
779 			bc_file_puts(&vm.ferr, bc_flush_none, "  ");           \
780 		}                                                          \
781 		bc_file_printf(&vm.ferr, "Leaving %s\n", __func__);        \
782 		bc_file_flush(&vm.ferr, bc_flush_none);                    \
783 	} while (0);
784 #else // BC_DEBUG_CODE
785 #define BC_FUNC_ENTER
786 #define BC_FUNC_EXIT
787 #endif // BC_DEBUG_CODE
788 
789 #endif // BC_STATUS_H
790