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