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