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