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