]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bc/include/status.h
usr.bin/gh-bc, contrib/bc: update to version 5.0.0
[FreeBSD/FreeBSD.git] / contrib / bc / include / status.h
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__ >= 201100L
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 // 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
275
276 #ifndef DC_DEFAULT_TTY_MODE
277 #define DC_DEFAULT_TTY_MODE (0)
278 #endif // DC_DEFAULT_TTY_MODE
279
280 #ifndef DC_DEFAULT_HISTORY
281 #define DC_DEFAULT_HISTORY DC_DEFAULT_TTY_MODE
282 #endif // DC_DEFAULT_HISTORY
283
284 #ifndef DC_DEFAULT_PROMPT
285 #define DC_DEFAULT_PROMPT DC_DEFAULT_TTY_MODE
286 #endif // DC_DEFAULT_PROMPT
287
288 /// Statuses, which mark either which category of error happened, or some other
289 /// status that matters.
290 typedef enum BcStatus {
291
292         /// Normal status.
293         BC_STATUS_SUCCESS = 0,
294
295         /// Math error.
296         BC_STATUS_ERROR_MATH,
297
298         /// Parse (and lex) error.
299         BC_STATUS_ERROR_PARSE,
300
301         /// Runtime error.
302         BC_STATUS_ERROR_EXEC,
303
304         /// Fatal error.
305         BC_STATUS_ERROR_FATAL,
306
307         /// EOF status.
308         BC_STATUS_EOF,
309
310         /// Quit status. This means that bc/dc is in the process of quitting.
311         BC_STATUS_QUIT,
312
313 } BcStatus;
314
315 /// Errors, which are more specific errors.
316 typedef enum BcErr {
317
318         // Math errors.
319
320         /// Negative number used when not allowed.
321         BC_ERR_MATH_NEGATIVE,
322
323         /// Non-integer used when not allowed.
324         BC_ERR_MATH_NON_INTEGER,
325
326         /// Conversion to a hardware integer would overflow.
327         BC_ERR_MATH_OVERFLOW,
328
329         /// Divide by zero.
330         BC_ERR_MATH_DIVIDE_BY_ZERO,
331
332         // Fatal errors.
333
334         /// An allocation or reallocation failed.
335         BC_ERR_FATAL_ALLOC_ERR,
336
337         /// I/O failure.
338         BC_ERR_FATAL_IO_ERR,
339
340         /// File error, such as permissions or file does not exist.
341         BC_ERR_FATAL_FILE_ERR,
342
343         /// File is binary, not text, error.
344         BC_ERR_FATAL_BIN_FILE,
345
346         /// Attempted to read a directory as a file error.
347         BC_ERR_FATAL_PATH_DIR,
348
349         /// Invalid option error.
350         BC_ERR_FATAL_OPTION,
351
352         /// Option with required argument not given an argument.
353         BC_ERR_FATAL_OPTION_NO_ARG,
354
355         /// Option with no argument given an argument.
356         BC_ERR_FATAL_OPTION_ARG,
357
358         /// Option argument is invalid.
359         BC_ERR_FATAL_ARG,
360
361         // Runtime errors.
362
363         /// Invalid ibase value.
364         BC_ERR_EXEC_IBASE,
365
366         /// Invalid obase value.
367         BC_ERR_EXEC_OBASE,
368
369         /// Invalid scale value.
370         BC_ERR_EXEC_SCALE,
371
372         /// Invalid expression parsed by read().
373         BC_ERR_EXEC_READ_EXPR,
374
375         /// read() used within an expression given to a read() call.
376         BC_ERR_EXEC_REC_READ,
377
378         /// Type error.
379         BC_ERR_EXEC_TYPE,
380
381         /// Stack has too few elements error.
382         BC_ERR_EXEC_STACK,
383
384         /// Register stack has too few elements error.
385         BC_ERR_EXEC_STACK_REGISTER,
386
387         /// Wrong number of arguments error.
388         BC_ERR_EXEC_PARAMS,
389
390         /// Undefined function error.
391         BC_ERR_EXEC_UNDEF_FUNC,
392
393         /// Void value used in an expression error.
394         BC_ERR_EXEC_VOID_VAL,
395
396         // Parse (and lex errors).
397
398         /// EOF encountered when not expected error.
399         BC_ERR_PARSE_EOF,
400
401         /// Invalid character error.
402         BC_ERR_PARSE_CHAR,
403
404         /// Invalid string (no ending quote) error.
405         BC_ERR_PARSE_STRING,
406
407         /// Invalid comment (no end found) error.
408         BC_ERR_PARSE_COMMENT,
409
410         /// Invalid token encountered error.
411         BC_ERR_PARSE_TOKEN,
412
413 #if BC_ENABLED
414
415         /// Invalid expression error.
416         BC_ERR_PARSE_EXPR,
417
418         /// Expression is empty error.
419         BC_ERR_PARSE_EMPTY_EXPR,
420
421         /// Print statement is invalid error.
422         BC_ERR_PARSE_PRINT,
423
424         /// Function definition is invalid error.
425         BC_ERR_PARSE_FUNC,
426
427         /// Assignment is invalid error.
428         BC_ERR_PARSE_ASSIGN,
429
430         /// No auto identifiers given for an auto statement error.
431         BC_ERR_PARSE_NO_AUTO,
432
433         /// Duplicate local (parameter or auto) error.
434         BC_ERR_PARSE_DUP_LOCAL,
435
436         /// Invalid block (within braces) error.
437         BC_ERR_PARSE_BLOCK,
438
439         /// Invalid return statement for void functions.
440         BC_ERR_PARSE_RET_VOID,
441
442         /// Reference attached to a variable, not an array, error.
443         BC_ERR_PARSE_REF_VAR,
444
445         // POSIX-only errors.
446
447         /// Name length greater than 1 error.
448         BC_ERR_POSIX_NAME_LEN,
449
450         /// Non-POSIX comment used error.
451         BC_ERR_POSIX_COMMENT,
452
453         /// Non-POSIX keyword error.
454         BC_ERR_POSIX_KW,
455
456         /// Non-POSIX . (last) error.
457         BC_ERR_POSIX_DOT,
458
459         /// Non-POSIX return error.
460         BC_ERR_POSIX_RET,
461
462         /// Non-POSIX boolean operator used error.
463         BC_ERR_POSIX_BOOL,
464
465         /// POSIX relation operator used outside if, while, or for statements error.
466         BC_ERR_POSIX_REL_POS,
467
468         /// Multiple POSIX relation operators used in an if, while, or for statement
469         /// error.
470         BC_ERR_POSIX_MULTIREL,
471
472         /// Empty statements in POSIX for loop error.
473         BC_ERR_POSIX_FOR,
474
475         /// Non-POSIX exponential (scientific or engineering) number used error.
476         BC_ERR_POSIX_EXP_NUM,
477
478         /// Non-POSIX array reference error.
479         BC_ERR_POSIX_REF,
480
481         /// Non-POSIX void error.
482         BC_ERR_POSIX_VOID,
483
484         /// Non-POSIX brace position used error.
485         BC_ERR_POSIX_BRACE,
486
487         /// String used in expression.
488         BC_ERR_POSIX_EXPR_STRING,
489
490 #endif // BC_ENABLED
491
492         // Number of elements.
493         BC_ERR_NELEMS,
494
495 #if BC_ENABLED
496
497         /// A marker for the start of POSIX errors.
498         BC_ERR_POSIX_START = BC_ERR_POSIX_NAME_LEN,
499
500         /// A marker for the end of POSIX errors.
501         BC_ERR_POSIX_END = BC_ERR_POSIX_EXPR_STRING,
502
503 #endif // BC_ENABLED
504
505 } BcErr;
506
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.
509
510 /// Math error category.
511 #define BC_ERR_IDX_MATH (0)
512
513 /// Parse (and lex) error category.
514 #define BC_ERR_IDX_PARSE (1)
515
516 /// Runtime error category.
517 #define BC_ERR_IDX_EXEC (2)
518
519 /// Fatal error category.
520 #define BC_ERR_IDX_FATAL (3)
521
522 /// Number of categories.
523 #define BC_ERR_IDX_NELEMS (4)
524
525 // If bc is enabled, we add an extra category for POSIX warnings.
526 #if BC_ENABLED
527
528 /// POSIX warning category.
529 #define BC_ERR_IDX_WARN (BC_ERR_IDX_NELEMS)
530
531 #endif // BC_ENABLED
532
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
535 /// from.
536 #if BC_DEBUG_CODE
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
541
542 /// Returns true if an exception is in flight, false otherwise.
543 #define BC_SIG_EXC \
544         BC_UNLIKELY(vm.status != (sig_atomic_t) BC_STATUS_SUCCESS || vm.sig)
545
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)
549
550 #ifndef NDEBUG
551
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)
557
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)
563
564 #else // NDEBUG
565
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
571
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
577
578 #endif // NDEBUG
579
580 /// Locks signals.
581 #define BC_SIG_LOCK               \
582         do {                          \
583                 BC_SIG_ASSERT_NOT_LOCKED; \
584                 vm.sig_lock = 1;          \
585         } while (0)
586
587 /// Unlocks signals. If a signal happened, then this will cause a jump.
588 #define BC_SIG_UNLOCK         \
589         do {                      \
590                 BC_SIG_ASSERT_LOCKED; \
591                 vm.sig_lock = 0;      \
592                 if (vm.sig) BC_JMP;   \
593         } while (0)
594
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
598 /// doesn't jump.
599 #define BC_SIG_MAYLOCK   \
600         do {                 \
601                 vm.sig_lock = 1; \
602         } while (0)
603
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    \
607         do {                    \
608                 vm.sig_lock = 0;    \
609                 if (vm.sig) BC_JMP; \
610         } while (0)
611
612 /*
613  * Locks signals, but stores the old lock state, to be restored later by
614  * BC_SIG_TRYUNLOCK.
615  * @param v  The variable to store the old lock state to.
616  */
617 #define BC_SIG_TRYLOCK(v) \
618         do {                  \
619                 v = vm.sig_lock;  \
620                 vm.sig_lock = 1;  \
621         } while (0)
622
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.
626  */
627 #define BC_SIG_TRYUNLOCK(v)         \
628         do {                            \
629                 vm.sig_lock = (v);          \
630                 if (!(v) && vm.sig) BC_JMP; \
631         } while (0)
632
633 /**
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().
642  */
643 #define BC_SETJMP(l)                     \
644         do {                                 \
645                 sigjmp_buf sjb;                  \
646                 BC_SIG_LOCK;                     \
647                 bc_vec_grow(&vm.jmp_bufs, 1);    \
648                 if (sigsetjmp(sjb, 0)) {         \
649                         assert(BC_SIG_EXC);          \
650                         goto l;                      \
651                 }                                \
652                 bc_vec_push(&vm.jmp_bufs, &sjb); \
653                 BC_SIG_UNLOCK;                   \
654         } while (0)
655
656 /**
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().
662  */
663 #define BC_SETJMP_LOCKED(l)              \
664         do {                                 \
665                 sigjmp_buf sjb;                  \
666                 BC_SIG_ASSERT_LOCKED;            \
667                 if (sigsetjmp(sjb, 0)) {         \
668                         assert(BC_SIG_EXC);          \
669                         goto l;                      \
670                 }                                \
671                 bc_vec_push(&vm.jmp_bufs, &sjb); \
672         } while (0)
673
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                            \
679         do {                                           \
680                 BC_SIG_ASSERT_LOCKED;                      \
681                 if (!vm.sig_pop) bc_vec_pop(&vm.jmp_bufs); \
682                 vm.sig_lock = 0;                           \
683                 if (BC_SIG_EXC) BC_JMP;                    \
684         } while (0)
685
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               \
691         do {                          \
692                 BC_SIG_ASSERT_LOCKED;     \
693                 bc_vec_pop(&vm.jmp_bufs); \
694         } while (0)
695
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 \
700         do {                \
701                 vm.sig_pop = 0; \
702                 vm.sig = 0;     \
703         } while (0)
704
705 // Various convenience macros for calling the bc's error handling routine.
706 #if BC_ENABLE_LIBRARY
707
708 /**
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.
713  */
714 #define bc_error(e, l, ...) (bc_vm_handleError((e)))
715
716 /**
717  * Call bc's error handling routine.
718  * @param e  The error.
719  */
720 #define bc_err(e) (bc_vm_handleError((e)))
721
722 /**
723  * Call bc's error handling routine.
724  * @param e  The error.
725  */
726 #define bc_verr(e, ...) (bc_vm_handleError((e)))
727
728 #else // BC_ENABLE_LIBRARY
729
730 /**
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.
735  */
736 #define bc_error(e, l, ...) (bc_vm_handleError((e), (l), __VA_ARGS__))
737
738 /**
739  * Call bc's error handling routine.
740  * @param e  The error.
741  */
742 #define bc_err(e) (bc_vm_handleError((e), 0))
743
744 /**
745  * Call bc's error handling routine.
746  * @param e  The error.
747  */
748 #define bc_verr(e, ...) (bc_vm_handleError((e), 0, __VA_ARGS__))
749
750 #endif // BC_ENABLE_LIBRARY
751
752 /**
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.
756  */
757 #define BC_STATUS_IS_ERROR(s) \
758         ((s) >= BC_STATUS_ERROR_MATH && (s) <= BC_STATUS_ERROR_FATAL)
759
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.
762 #if BC_DEBUG_CODE
763 #define BC_FUNC_ENTER                                              \
764         do {                                                           \
765                 size_t bc_func_enter_i;                                    \
766                 for (bc_func_enter_i = 0; bc_func_enter_i < vm.func_depth; \
767                      ++bc_func_enter_i)                                    \
768                 {                                                          \
769                         bc_file_puts(&vm.ferr, bc_flush_none, "  ");           \
770                 }                                                          \
771                 vm.func_depth += 1;                                        \
772                 bc_file_printf(&vm.ferr, "Entering %s\n", __func__);       \
773                 bc_file_flush(&vm.ferr, bc_flush_none);                    \
774         } while (0);
775
776 #define BC_FUNC_EXIT                                               \
777         do {                                                           \
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; \
781                      ++bc_func_enter_i)                                    \
782                 {                                                          \
783                         bc_file_puts(&vm.ferr, bc_flush_none, "  ");           \
784                 }                                                          \
785                 bc_file_printf(&vm.ferr, "Leaving %s\n", __func__);        \
786                 bc_file_flush(&vm.ferr, bc_flush_none);                    \
787         } while (0);
788 #else // BC_DEBUG_CODE
789 #define BC_FUNC_ENTER
790 #define BC_FUNC_EXIT
791 #endif // BC_DEBUG_CODE
792
793 #endif // BC_STATUS_H