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