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