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