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__ >= 201112L 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 #ifndef BC_DEFAULT_EXPR_EXIT 272 #define BC_DEFAULT_EXPR_EXIT (1) 273 #endif // BC_DEFAULT_EXPR_EXIT 274 275 // All of these set defaults for settings. 276 #ifndef DC_DEFAULT_SIGINT_RESET 277 #define DC_DEFAULT_SIGINT_RESET (1) 278 #endif // DC_DEFAULT_SIGINT_RESET 279 280 #ifndef DC_DEFAULT_TTY_MODE 281 #define DC_DEFAULT_TTY_MODE (0) 282 #endif // DC_DEFAULT_TTY_MODE 283 284 #ifndef DC_DEFAULT_HISTORY 285 #define DC_DEFAULT_HISTORY DC_DEFAULT_TTY_MODE 286 #endif // DC_DEFAULT_HISTORY 287 288 #ifndef DC_DEFAULT_PROMPT 289 #define DC_DEFAULT_PROMPT DC_DEFAULT_TTY_MODE 290 #endif // DC_DEFAULT_PROMPT 291 292 #ifndef DC_DEFAULT_EXPR_EXIT 293 #define DC_DEFAULT_EXPR_EXIT (1) 294 #endif // DC_DEFAULT_EXPR_EXIT 295 296 /// Statuses, which mark either which category of error happened, or some other 297 /// status that matters. 298 typedef enum BcStatus { 299 300 /// Normal status. 301 BC_STATUS_SUCCESS = 0, 302 303 /// Math error. 304 BC_STATUS_ERROR_MATH, 305 306 /// Parse (and lex) error. 307 BC_STATUS_ERROR_PARSE, 308 309 /// Runtime error. 310 BC_STATUS_ERROR_EXEC, 311 312 /// Fatal error. 313 BC_STATUS_ERROR_FATAL, 314 315 /// EOF status. 316 BC_STATUS_EOF, 317 318 /// Quit status. This means that bc/dc is in the process of quitting. 319 BC_STATUS_QUIT, 320 321 } BcStatus; 322 323 /// Errors, which are more specific errors. 324 typedef enum BcErr { 325 326 // Math errors. 327 328 /// Negative number used when not allowed. 329 BC_ERR_MATH_NEGATIVE, 330 331 /// Non-integer used when not allowed. 332 BC_ERR_MATH_NON_INTEGER, 333 334 /// Conversion to a hardware integer would overflow. 335 BC_ERR_MATH_OVERFLOW, 336 337 /// Divide by zero. 338 BC_ERR_MATH_DIVIDE_BY_ZERO, 339 340 // Fatal errors. 341 342 /// An allocation or reallocation failed. 343 BC_ERR_FATAL_ALLOC_ERR, 344 345 /// I/O failure. 346 BC_ERR_FATAL_IO_ERR, 347 348 /// File error, such as permissions or file does not exist. 349 BC_ERR_FATAL_FILE_ERR, 350 351 /// File is binary, not text, error. 352 BC_ERR_FATAL_BIN_FILE, 353 354 /// Attempted to read a directory as a file error. 355 BC_ERR_FATAL_PATH_DIR, 356 357 /// Invalid option error. 358 BC_ERR_FATAL_OPTION, 359 360 /// Option with required argument not given an argument. 361 BC_ERR_FATAL_OPTION_NO_ARG, 362 363 /// Option with no argument given an argument. 364 BC_ERR_FATAL_OPTION_ARG, 365 366 /// Option argument is invalid. 367 BC_ERR_FATAL_ARG, 368 369 // Runtime errors. 370 371 /// Invalid ibase value. 372 BC_ERR_EXEC_IBASE, 373 374 /// Invalid obase value. 375 BC_ERR_EXEC_OBASE, 376 377 /// Invalid scale value. 378 BC_ERR_EXEC_SCALE, 379 380 /// Invalid expression parsed by read(). 381 BC_ERR_EXEC_READ_EXPR, 382 383 /// read() used within an expression given to a read() call. 384 BC_ERR_EXEC_REC_READ, 385 386 /// Type error. 387 BC_ERR_EXEC_TYPE, 388 389 /// Stack has too few elements error. 390 BC_ERR_EXEC_STACK, 391 392 /// Register stack has too few elements error. 393 BC_ERR_EXEC_STACK_REGISTER, 394 395 /// Wrong number of arguments error. 396 BC_ERR_EXEC_PARAMS, 397 398 /// Undefined function error. 399 BC_ERR_EXEC_UNDEF_FUNC, 400 401 /// Void value used in an expression error. 402 BC_ERR_EXEC_VOID_VAL, 403 404 // Parse (and lex) errors. 405 406 /// EOF encountered when not expected error. 407 BC_ERR_PARSE_EOF, 408 409 /// Invalid character error. 410 BC_ERR_PARSE_CHAR, 411 412 /// Invalid string (no ending quote) error. 413 BC_ERR_PARSE_STRING, 414 415 /// Invalid comment (no end found) error. 416 BC_ERR_PARSE_COMMENT, 417 418 /// Invalid token encountered error. 419 BC_ERR_PARSE_TOKEN, 420 421 #if BC_ENABLED 422 423 /// Invalid expression error. 424 BC_ERR_PARSE_EXPR, 425 426 /// Expression is empty error. 427 BC_ERR_PARSE_EMPTY_EXPR, 428 429 /// Print statement is invalid error. 430 BC_ERR_PARSE_PRINT, 431 432 /// Function definition is invalid error. 433 BC_ERR_PARSE_FUNC, 434 435 /// Assignment is invalid error. 436 BC_ERR_PARSE_ASSIGN, 437 438 /// No auto identifiers given for an auto statement error. 439 BC_ERR_PARSE_NO_AUTO, 440 441 /// Duplicate local (parameter or auto) error. 442 BC_ERR_PARSE_DUP_LOCAL, 443 444 /// Invalid block (within braces) error. 445 BC_ERR_PARSE_BLOCK, 446 447 /// Invalid return statement for void functions. 448 BC_ERR_PARSE_RET_VOID, 449 450 /// Reference attached to a variable, not an array, error. 451 BC_ERR_PARSE_REF_VAR, 452 453 // POSIX-only errors. 454 455 /// Name length greater than 1 error. 456 BC_ERR_POSIX_NAME_LEN, 457 458 /// Non-POSIX comment used error. 459 BC_ERR_POSIX_COMMENT, 460 461 /// Non-POSIX keyword error. 462 BC_ERR_POSIX_KW, 463 464 /// Non-POSIX . (last) error. 465 BC_ERR_POSIX_DOT, 466 467 /// Non-POSIX return error. 468 BC_ERR_POSIX_RET, 469 470 /// Non-POSIX boolean operator used error. 471 BC_ERR_POSIX_BOOL, 472 473 /// POSIX relation operator used outside if, while, or for statements error. 474 BC_ERR_POSIX_REL_POS, 475 476 /// Multiple POSIX relation operators used in an if, while, or for statement 477 /// error. 478 BC_ERR_POSIX_MULTIREL, 479 480 /// Empty statements in POSIX for loop error. 481 BC_ERR_POSIX_FOR, 482 483 /// POSIX's grammar does not allow a function definition right after a 484 /// semicolon. 485 BC_ERR_POSIX_FUNC_AFTER_SEMICOLON, 486 487 /// Non-POSIX exponential (scientific or engineering) number used error. 488 BC_ERR_POSIX_EXP_NUM, 489 490 /// Non-POSIX array reference error. 491 BC_ERR_POSIX_REF, 492 493 /// Non-POSIX void error. 494 BC_ERR_POSIX_VOID, 495 496 /// Non-POSIX brace position used error. 497 BC_ERR_POSIX_BRACE, 498 499 /// String used in expression. 500 BC_ERR_POSIX_EXPR_STRING, 501 502 #endif // BC_ENABLED 503 504 // Number of elements. 505 BC_ERR_NELEMS, 506 507 #if BC_ENABLED 508 509 /// A marker for the start of POSIX errors. 510 BC_ERR_POSIX_START = BC_ERR_POSIX_NAME_LEN, 511 512 /// A marker for the end of POSIX errors. 513 BC_ERR_POSIX_END = BC_ERR_POSIX_EXPR_STRING, 514 515 #endif // BC_ENABLED 516 517 } BcErr; 518 519 // The indices of each category of error in bc_errs[], and used in bc_err_ids[] 520 // to associate actual errors with their categories. 521 522 /// Math error category. 523 #define BC_ERR_IDX_MATH (0) 524 525 /// Parse (and lex) error category. 526 #define BC_ERR_IDX_PARSE (1) 527 528 /// Runtime error category. 529 #define BC_ERR_IDX_EXEC (2) 530 531 /// Fatal error category. 532 #define BC_ERR_IDX_FATAL (3) 533 534 /// Number of categories. 535 #define BC_ERR_IDX_NELEMS (4) 536 537 // If bc is enabled, we add an extra category for POSIX warnings. 538 #if BC_ENABLED 539 540 /// POSIX warning category. 541 #define BC_ERR_IDX_WARN (BC_ERR_IDX_NELEMS) 542 543 #endif // BC_ENABLED 544 545 /// Do a longjmp(). This is what to use when activating an "exception", i.e., a 546 /// longjmp(). With debug code, it will print the name of the function it jumped 547 /// from. 548 #if BC_DEBUG_CODE 549 #define BC_JMP bc_vm_jmp(__func__) 550 #else // BC_DEBUG_CODE 551 #define BC_JMP bc_vm_jmp() 552 #endif // BC_DEBUG_CODE 553 554 /// Returns true if an exception is in flight, false otherwise. 555 #define BC_SIG_EXC \ 556 BC_UNLIKELY(vm.status != (sig_atomic_t) BC_STATUS_SUCCESS || vm.sig) 557 558 /// Returns true if there is *no* exception in flight, false otherwise. 559 #define BC_NO_SIG_EXC \ 560 BC_LIKELY(vm.status == (sig_atomic_t) BC_STATUS_SUCCESS && !vm.sig) 561 562 #ifndef NDEBUG 563 564 /// Assert that signals are locked. There are non-async-signal-safe functions in 565 /// bc, and they *must* have signals locked. Other functions are expected to 566 /// *not* have signals locked, for reasons. So this is a pre-built assert 567 /// (no-op in non-debug mode) that check that signals are locked. 568 #define BC_SIG_ASSERT_LOCKED do { assert(vm.sig_lock); } while (0) 569 570 /// Assert that signals are unlocked. There are non-async-signal-safe functions 571 /// in bc, and they *must* have signals locked. Other functions are expected to 572 /// *not* have signals locked, for reasons. So this is a pre-built assert 573 /// (no-op in non-debug mode) that check that signals are unlocked. 574 #define BC_SIG_ASSERT_NOT_LOCKED do { assert(vm.sig_lock == 0); } while (0) 575 576 #else // NDEBUG 577 578 /// Assert that signals are locked. There are non-async-signal-safe functions in 579 /// bc, and they *must* have signals locked. Other functions are expected to 580 /// *not* have signals locked, for reasons. So this is a pre-built assert 581 /// (no-op in non-debug mode) that check that signals are locked. 582 #define BC_SIG_ASSERT_LOCKED 583 584 /// Assert that signals are unlocked. There are non-async-signal-safe functions 585 /// in bc, and they *must* have signals locked. Other functions are expected to 586 /// *not* have signals locked, for reasons. So this is a pre-built assert 587 /// (no-op in non-debug mode) that check that signals are unlocked. 588 #define BC_SIG_ASSERT_NOT_LOCKED 589 590 #endif // NDEBUG 591 592 /// Locks signals. 593 #define BC_SIG_LOCK \ 594 do { \ 595 BC_SIG_ASSERT_NOT_LOCKED; \ 596 vm.sig_lock = 1; \ 597 } while (0) 598 599 /// Unlocks signals. If a signal happened, then this will cause a jump. 600 #define BC_SIG_UNLOCK \ 601 do { \ 602 BC_SIG_ASSERT_LOCKED; \ 603 vm.sig_lock = 0; \ 604 if (vm.sig) BC_JMP; \ 605 } while (0) 606 607 /// Locks signals, regardless of if they are already locked. This is really only 608 /// used after labels that longjmp() goes to after the jump because the cleanup 609 /// code must have signals locked, and BC_LONGJMP_CONT will unlock signals if it 610 /// doesn't jump. 611 #define BC_SIG_MAYLOCK \ 612 do { \ 613 vm.sig_lock = 1; \ 614 } while (0) 615 616 /// Unlocks signals, regardless of if they were already unlocked. If a signal 617 /// happened, then this will cause a jump. 618 #define BC_SIG_MAYUNLOCK \ 619 do { \ 620 vm.sig_lock = 0; \ 621 if (vm.sig) BC_JMP; \ 622 } while (0) 623 624 /* 625 * Locks signals, but stores the old lock state, to be restored later by 626 * BC_SIG_TRYUNLOCK. 627 * @param v The variable to store the old lock state to. 628 */ 629 #define BC_SIG_TRYLOCK(v) \ 630 do { \ 631 v = vm.sig_lock; \ 632 vm.sig_lock = 1; \ 633 } while (0) 634 635 /* Restores the previous state of a signal lock, and if it is now unlocked, 636 * initiates an exception/jump. 637 * @param v The old lock state. 638 */ 639 #define BC_SIG_TRYUNLOCK(v) \ 640 do { \ 641 vm.sig_lock = (v); \ 642 if (!(v) && vm.sig) BC_JMP; \ 643 } while (0) 644 645 /** 646 * Sets a jump, and sets it up as well so that if a longjmp() happens, bc will 647 * immediately goto a label where some cleanup code is. This one assumes that 648 * signals are not locked and will lock them, set the jump, and unlock them. 649 * Setting the jump also includes pushing the jmp_buf onto the jmp_buf stack. 650 * This grows the jmp_bufs vector first to prevent a fatal error from happening 651 * after the setjmp(). This is done because BC_SETJMP(l) is assumed to be used 652 * *before* the actual initialization calls that need the setjmp(). 653 * param l The label to jump to on a longjmp(). 654 */ 655 #define BC_SETJMP(l) \ 656 do { \ 657 sigjmp_buf sjb; \ 658 BC_SIG_LOCK; \ 659 bc_vec_grow(&vm.jmp_bufs, 1); \ 660 if (sigsetjmp(sjb, 0)) { \ 661 assert(BC_SIG_EXC); \ 662 goto l; \ 663 } \ 664 bc_vec_push(&vm.jmp_bufs, &sjb); \ 665 BC_SIG_UNLOCK; \ 666 } while (0) 667 668 /** 669 * Sets a jump like BC_SETJMP, but unlike BC_SETJMP, it assumes signals are 670 * locked and will just set the jump. This does *not* have a call to 671 * bc_vec_grow() because it is assumed that BC_SETJMP_LOCKED(l) is used *after* 672 * the initializations that need the setjmp(). 673 * param l The label to jump to on a longjmp(). 674 */ 675 #define BC_SETJMP_LOCKED(l) \ 676 do { \ 677 sigjmp_buf sjb; \ 678 BC_SIG_ASSERT_LOCKED; \ 679 if (sigsetjmp(sjb, 0)) { \ 680 assert(BC_SIG_EXC); \ 681 goto l; \ 682 } \ 683 bc_vec_push(&vm.jmp_bufs, &sjb); \ 684 } while (0) 685 686 /// Used after cleanup labels set by BC_SETJMP and BC_SETJMP_LOCKED to jump to 687 /// the next place. This is what continues the stack unwinding. This basically 688 /// copies BC_SIG_UNLOCK into itself, but that is because its condition for 689 /// jumping is BC_SIG_EXC, not just that a signal happened. 690 #define BC_LONGJMP_CONT \ 691 do { \ 692 BC_SIG_ASSERT_LOCKED; \ 693 if (!vm.sig_pop) bc_vec_pop(&vm.jmp_bufs); \ 694 vm.sig_lock = 0; \ 695 if (BC_SIG_EXC) BC_JMP; \ 696 } while (0) 697 698 /// Unsets a jump. It always assumes signals are locked. This basically just 699 /// pops a jmp_buf off of the stack of jmp_bufs, and since the jump mechanism 700 /// always jumps to the location at the top of the stack, this effectively 701 /// undoes a setjmp(). 702 #define BC_UNSETJMP \ 703 do { \ 704 BC_SIG_ASSERT_LOCKED; \ 705 bc_vec_pop(&vm.jmp_bufs); \ 706 } while (0) 707 708 /// Stops a stack unwinding. Technically, a stack unwinding needs to be done 709 /// manually, but it will always be done unless certain flags are cleared. This 710 /// clears the flags. 711 #define BC_LONGJMP_STOP \ 712 do { \ 713 vm.sig_pop = 0; \ 714 vm.sig = 0; \ 715 } while (0) 716 717 // Various convenience macros for calling the bc's error handling routine. 718 #if BC_ENABLE_LIBRARY 719 720 /** 721 * Call bc's error handling routine. 722 * @param e The error. 723 * @param l The line of the script that the error happened. 724 * @param ... Extra arguments for error messages as necessary. 725 */ 726 #define bc_error(e, l, ...) (bc_vm_handleError((e))) 727 728 /** 729 * Call bc's error handling routine. 730 * @param e The error. 731 */ 732 #define bc_err(e) (bc_vm_handleError((e))) 733 734 /** 735 * Call bc's error handling routine. 736 * @param e The error. 737 */ 738 #define bc_verr(e, ...) (bc_vm_handleError((e))) 739 740 #else // BC_ENABLE_LIBRARY 741 742 /** 743 * Call bc's error handling routine. 744 * @param e The error. 745 * @param l The line of the script that the error happened. 746 * @param ... Extra arguments for error messages as necessary. 747 */ 748 #define bc_error(e, l, ...) (bc_vm_handleError((e), (l), __VA_ARGS__)) 749 750 /** 751 * Call bc's error handling routine. 752 * @param e The error. 753 */ 754 #define bc_err(e) (bc_vm_handleError((e), 0)) 755 756 /** 757 * Call bc's error handling routine. 758 * @param e The error. 759 */ 760 #define bc_verr(e, ...) (bc_vm_handleError((e), 0, __VA_ARGS__)) 761 762 #endif // BC_ENABLE_LIBRARY 763 764 /** 765 * Returns true if status @a s is an error, false otherwise. 766 * @param s The status to test. 767 * @return True if @a s is an error, false otherwise. 768 */ 769 #define BC_STATUS_IS_ERROR(s) \ 770 ((s) >= BC_STATUS_ERROR_MATH && (s) <= BC_STATUS_ERROR_FATAL) 771 772 // Convenience macros that can be placed at the beginning and exits of functions 773 // for easy marking of where functions are entered and exited. 774 #if BC_DEBUG_CODE 775 #define BC_FUNC_ENTER \ 776 do { \ 777 size_t bc_func_enter_i; \ 778 for (bc_func_enter_i = 0; bc_func_enter_i < vm.func_depth; \ 779 ++bc_func_enter_i) \ 780 { \ 781 bc_file_puts(&vm.ferr, bc_flush_none, " "); \ 782 } \ 783 vm.func_depth += 1; \ 784 bc_file_printf(&vm.ferr, "Entering %s\n", __func__); \ 785 bc_file_flush(&vm.ferr, bc_flush_none); \ 786 } while (0); 787 788 #define BC_FUNC_EXIT \ 789 do { \ 790 size_t bc_func_enter_i; \ 791 vm.func_depth -= 1; \ 792 for (bc_func_enter_i = 0; bc_func_enter_i < vm.func_depth; \ 793 ++bc_func_enter_i) \ 794 { \ 795 bc_file_puts(&vm.ferr, bc_flush_none, " "); \ 796 } \ 797 bc_file_printf(&vm.ferr, "Leaving %s\n", __func__); \ 798 bc_file_flush(&vm.ferr, bc_flush_none); \ 799 } while (0); 800 #else // BC_DEBUG_CODE 801 #define BC_FUNC_ENTER 802 #define BC_FUNC_EXIT 803 #endif // BC_DEBUG_CODE 804 805 #endif // BC_STATUS_H 806