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