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