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