1 /* 2 * ***************************************************************************** 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 2018-2024 Gavin D. Howard and contributors. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are met: 10 * 11 * * Redistributions of source code must retain the above copyright notice, this 12 * list of conditions and the following disclaimer. 13 * 14 * * Redistributions in binary form must reproduce the above copyright notice, 15 * this list of conditions and the following disclaimer in the documentation 16 * and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 * 30 * ***************************************************************************** 31 * 32 * All bc status codes and cross-platform portability. 33 * 34 */ 35 36 #ifndef BC_STATUS_H 37 #define BC_STATUS_H 38 39 #ifdef _WIN32 40 #include <Windows.h> 41 #include <BaseTsd.h> 42 #include <stdio.h> 43 #include <io.h> 44 #endif // _WIN32 45 46 #include <stdint.h> 47 #include <sys/types.h> 48 49 // Windows has deprecated isatty() and the rest of these. Or doesn't have them. 50 // So these are just fixes for Windows. 51 #ifdef _WIN32 52 53 // This one is special. Windows did not like me defining an 54 // inline function that was not given a definition in a header 55 // file. This suppresses that by making inline functions non-inline. 56 #define inline 57 58 #define restrict __restrict 59 #define strdup _strdup 60 #define write(f, b, s) _write((f), (b), (unsigned int) (s)) 61 #define read(f, b, s) _read((f), (b), (unsigned int) (s)) 62 #define close _close 63 #define open(f, n, m) \ 64 _sopen_s((f), (n), (m) | _O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE) 65 #define sigjmp_buf jmp_buf 66 #define sigsetjmp(j, s) setjmp(j) 67 #define siglongjmp longjmp 68 #define isatty _isatty 69 #define STDIN_FILENO _fileno(stdin) 70 #define STDOUT_FILENO _fileno(stdout) 71 #define STDERR_FILENO _fileno(stderr) 72 #define S_ISDIR(m) ((m) & (_S_IFDIR)) 73 #define O_RDONLY _O_RDONLY 74 #define stat _stat 75 #define fstat _fstat 76 #define BC_FILE_SEP '\\' 77 78 #else // _WIN32 79 #define BC_FILE_SEP '/' 80 #endif // _WIN32 81 82 #ifndef BC_ENABLED 83 #define BC_ENABLED (1) 84 #endif // BC_ENABLED 85 86 #ifndef DC_ENABLED 87 #define DC_ENABLED (1) 88 #endif // DC_ENABLED 89 90 #ifndef BC_ENABLE_EXTRA_MATH 91 #define BC_ENABLE_EXTRA_MATH (1) 92 #endif // BC_ENABLE_EXTRA_MATH 93 94 #ifndef BC_ENABLE_LIBRARY 95 #define BC_ENABLE_LIBRARY (0) 96 #endif // BC_ENABLE_LIBRARY 97 98 #ifndef BC_ENABLE_HISTORY 99 #define BC_ENABLE_HISTORY (1) 100 #endif // BC_ENABLE_HISTORY 101 102 #ifndef BC_ENABLE_EDITLINE 103 #define BC_ENABLE_EDITLINE (0) 104 #endif // BC_ENABLE_EDITLINE 105 106 #ifndef BC_ENABLE_READLINE 107 #define BC_ENABLE_READLINE (0) 108 #endif // BC_ENABLE_READLINE 109 110 #ifndef BC_ENABLE_NLS 111 #define BC_ENABLE_NLS (0) 112 #endif // BC_ENABLE_NLS 113 114 #ifdef __OpenBSD__ 115 #if BC_ENABLE_READLINE 116 #error Cannot use readline on OpenBSD 117 #endif // BC_ENABLE_READLINE 118 #endif // __OpenBSD__ 119 120 #if BC_ENABLE_EDITLINE && BC_ENABLE_READLINE 121 #error Must enable only one of editline or readline, not both. 122 #endif // BC_ENABLE_EDITLINE && BC_ENABLE_READLINE 123 124 #if BC_ENABLE_EDITLINE || BC_ENABLE_READLINE 125 #define BC_ENABLE_LINE_LIB (1) 126 #else // BC_ENABLE_EDITLINE || BC_ENABLE_READLINE 127 #define BC_ENABLE_LINE_LIB (0) 128 #endif // BC_ENABLE_EDITLINE || BC_ENABLE_READLINE 129 130 // This is error checking for fuzz builds. 131 #if BC_ENABLE_AFL 132 #ifndef __AFL_HAVE_MANUAL_CONTROL 133 #error Must compile with afl-clang-fast or afl-clang-lto for fuzzing 134 #endif // __AFL_HAVE_MANUAL_CONTROL 135 #endif // BC_ENABLE_AFL 136 137 #ifndef BC_ENABLE_MEMCHECK 138 #define BC_ENABLE_MEMCHECK (0) 139 #endif // BC_ENABLE_MEMCHECK 140 141 /** 142 * Mark a variable as unused. 143 * @param e The variable to mark as unused. 144 */ 145 #define BC_UNUSED(e) ((void) (e)) 146 147 // If users want, they can define this to something like __builtin_expect(e, 1). 148 // It might give a performance improvement. 149 #ifndef BC_LIKELY 150 151 /** 152 * Mark a branch expression as likely. 153 * @param e The expression to mark as likely. 154 */ 155 #define BC_LIKELY(e) (e) 156 157 #endif // BC_LIKELY 158 159 // If users want, they can define this to something like __builtin_expect(e, 0). 160 // It might give a performance improvement. 161 #ifndef BC_UNLIKELY 162 163 /** 164 * Mark a branch expression as unlikely. 165 * @param e The expression to mark as unlikely. 166 */ 167 #define BC_UNLIKELY(e) (e) 168 169 #endif // BC_UNLIKELY 170 171 /** 172 * Mark a branch expression as an error, if true. 173 * @param e The expression to mark as an error, if true. 174 */ 175 #define BC_ERR(e) BC_UNLIKELY(e) 176 177 /** 178 * Mark a branch expression as not an error, if true. 179 * @param e The expression to mark as not an error, if true. 180 */ 181 #define BC_NO_ERR(s) BC_LIKELY(s) 182 183 // Disable extra debug code by default. 184 #ifndef BC_DEBUG_CODE 185 #define BC_DEBUG_CODE (0) 186 #endif // BC_DEBUG_CODE 187 188 #if defined(__clang__) 189 #define BC_CLANG (1) 190 #else // defined(__clang__) 191 #define BC_CLANG (0) 192 #endif // defined(__clang__) 193 194 #if defined(__GNUC__) && !BC_CLANG 195 #define BC_GCC (1) 196 #else // defined(__GNUC__) && !BC_CLANG 197 #define BC_GCC (0) 198 #endif // defined(__GNUC__) && !BC_CLANG 199 200 // We want to be able to use _Noreturn on C11 compilers. 201 #if __STDC_VERSION__ >= 201112L 202 203 #include <stdnoreturn.h> 204 #define BC_NORETURN _Noreturn 205 #define BC_C11 (1) 206 207 #else // __STDC_VERSION__ 208 209 #if BC_CLANG 210 #if __has_attribute(noreturn) 211 #define BC_NORETURN __attribute((noreturn)) 212 #else // __has_attribute(noreturn) 213 #define BC_NORETURN 214 #endif // __has_attribute(noreturn) 215 216 #else // BC_CLANG 217 218 #define BC_NORETURN 219 220 #endif // BC_CLANG 221 222 #define BC_MUST_RETURN 223 #define BC_C11 (0) 224 225 #endif // __STDC_VERSION__ 226 227 #define BC_HAS_UNREACHABLE (0) 228 #define BC_HAS_COMPUTED_GOTO (0) 229 230 // GCC and Clang complain if fallthroughs are not marked with their special 231 // attribute. Jerks. This creates a define for marking the fallthroughs that is 232 // nothing on other compilers. 233 #if BC_CLANG || BC_GCC 234 235 #if defined(__has_attribute) 236 237 #if __has_attribute(fallthrough) 238 #define BC_FALLTHROUGH __attribute__((fallthrough)); 239 #else // __has_attribute(fallthrough) 240 #define BC_FALLTHROUGH 241 #endif // __has_attribute(fallthrough) 242 243 #if BC_GCC 244 245 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) 246 #undef BC_HAS_UNREACHABLE 247 #define BC_HAS_UNREACHABLE (1) 248 #endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) 249 250 #else // BC_GCC 251 252 #if __clang_major__ >= 4 253 #undef BC_HAS_UNREACHABLE 254 #define BC_HAS_UNREACHABLE (1) 255 #endif // __clang_major__ >= 4 256 257 #endif // BC_GCC 258 259 #else // defined(__has_attribute) 260 #define BC_FALLTHROUGH 261 #endif // defined(__has_attribute) 262 #else // BC_CLANG || BC_GCC 263 #define BC_FALLTHROUGH 264 #endif // BC_CLANG || BC_GCC 265 266 #if BC_HAS_UNREACHABLE 267 268 #define BC_UNREACHABLE __builtin_unreachable(); 269 270 #else // BC_HAS_UNREACHABLE 271 272 #ifdef _WIN32 273 274 #define BC_UNREACHABLE __assume(0); 275 276 #else // _WIN32 277 278 #define BC_UNREACHABLE 279 280 #endif // _WIN32 281 282 #endif // BC_HAS_UNREACHABLE 283 284 #if BC_GCC 285 286 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) 287 288 #undef BC_HAS_COMPUTED_GOTO 289 #define BC_HAS_COMPUTED_GOTO (1) 290 291 #endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) 292 293 #endif // BC_GCC 294 295 #if BC_CLANG 296 297 #if __clang_major__ >= 4 298 299 #undef BC_HAS_COMPUTED_GOTO 300 #define BC_HAS_COMPUTED_GOTO (1) 301 302 #endif // __clang_major__ >= 4 303 304 #endif // BC_CLANG 305 306 #ifdef BC_NO_COMPUTED_GOTO 307 308 #undef BC_HAS_COMPUTED_GOTO 309 #define BC_HAS_COMPUTED_GOTO (0) 310 311 #endif // BC_NO_COMPUTED_GOTO 312 313 #if BC_GCC 314 #ifdef __OpenBSD__ 315 // The OpenBSD GCC doesn't like inline. 316 #define inline 317 #endif // __OpenBSD__ 318 #endif // BC_GCC 319 320 // Workarounds for AIX's POSIX incompatibility. 321 #ifndef SIZE_MAX 322 #define SIZE_MAX __SIZE_MAX__ 323 #endif // SIZE_MAX 324 #ifndef UINTMAX_C 325 #define UINTMAX_C __UINTMAX_C 326 #endif // UINTMAX_C 327 #ifndef UINT32_C 328 #define UINT32_C __UINT32_C 329 #endif // UINT32_C 330 #ifndef UINT_FAST32_MAX 331 #define UINT_FAST32_MAX __UINT_FAST32_MAX__ 332 #endif // UINT_FAST32_MAX 333 #ifndef UINT16_MAX 334 #define UINT16_MAX __UINT16_MAX__ 335 #endif // UINT16_MAX 336 #ifndef SIG_ATOMIC_MAX 337 #define SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__ 338 #endif // SIG_ATOMIC_MAX 339 340 // Yes, this has to be here. 341 #include <bcl.h> 342 343 // All of these set defaults for settings. 344 345 #if BC_ENABLED 346 347 #ifndef BC_DEFAULT_BANNER 348 #define BC_DEFAULT_BANNER (0) 349 #endif // BC_DEFAULT_BANNER 350 351 #endif // BC_ENABLED 352 353 #ifndef BC_DEFAULT_SIGINT_RESET 354 #define BC_DEFAULT_SIGINT_RESET (1) 355 #endif // BC_DEFAULT_SIGINT_RESET 356 357 #ifndef BC_DEFAULT_TTY_MODE 358 #define BC_DEFAULT_TTY_MODE (1) 359 #endif // BC_DEFAULT_TTY_MODE 360 361 #ifndef BC_DEFAULT_PROMPT 362 #define BC_DEFAULT_PROMPT BC_DEFAULT_TTY_MODE 363 #endif // BC_DEFAULT_PROMPT 364 365 #ifndef BC_DEFAULT_EXPR_EXIT 366 #define BC_DEFAULT_EXPR_EXIT (1) 367 #endif // BC_DEFAULT_EXPR_EXIT 368 369 #ifndef BC_DEFAULT_DIGIT_CLAMP 370 #define BC_DEFAULT_DIGIT_CLAMP (0) 371 #endif // BC_DEFAULT_DIGIT_CLAMP 372 373 // All of these set defaults for settings. 374 #ifndef DC_DEFAULT_SIGINT_RESET 375 #define DC_DEFAULT_SIGINT_RESET (1) 376 #endif // DC_DEFAULT_SIGINT_RESET 377 378 #ifndef DC_DEFAULT_TTY_MODE 379 #define DC_DEFAULT_TTY_MODE (0) 380 #endif // DC_DEFAULT_TTY_MODE 381 382 #ifndef DC_DEFAULT_HISTORY 383 #define DC_DEFAULT_HISTORY DC_DEFAULT_TTY_MODE 384 #endif // DC_DEFAULT_HISTORY 385 386 #ifndef DC_DEFAULT_PROMPT 387 #define DC_DEFAULT_PROMPT DC_DEFAULT_TTY_MODE 388 #endif // DC_DEFAULT_PROMPT 389 390 #ifndef DC_DEFAULT_EXPR_EXIT 391 #define DC_DEFAULT_EXPR_EXIT (1) 392 #endif // DC_DEFAULT_EXPR_EXIT 393 394 #ifndef DC_DEFAULT_DIGIT_CLAMP 395 #define DC_DEFAULT_DIGIT_CLAMP (0) 396 #endif // DC_DEFAULT_DIGIT_CLAMP 397 398 /// Statuses, which mark either which category of error happened, or some other 399 /// status that matters. 400 typedef enum BcStatus 401 { 402 /// Normal status. 403 BC_STATUS_SUCCESS = 0, 404 405 /// Math error. 406 BC_STATUS_ERROR_MATH, 407 408 /// Parse (and lex) error. 409 BC_STATUS_ERROR_PARSE, 410 411 /// Runtime error. 412 BC_STATUS_ERROR_EXEC, 413 414 /// Fatal error. 415 BC_STATUS_ERROR_FATAL, 416 417 /// EOF status. 418 BC_STATUS_EOF, 419 420 /// Quit status. This means that bc/dc is in the process of quitting. 421 BC_STATUS_QUIT, 422 423 } BcStatus; 424 425 /// Errors, which are more specific errors. 426 typedef enum BcErr 427 { 428 // Math errors. 429 430 /// Negative number used when not allowed. 431 BC_ERR_MATH_NEGATIVE, 432 433 /// Non-integer used when not allowed. 434 BC_ERR_MATH_NON_INTEGER, 435 436 /// Conversion to a hardware integer would overflow. 437 BC_ERR_MATH_OVERFLOW, 438 439 /// Divide by zero. 440 BC_ERR_MATH_DIVIDE_BY_ZERO, 441 442 // Fatal errors. 443 444 /// An allocation or reallocation failed. 445 BC_ERR_FATAL_ALLOC_ERR, 446 447 /// I/O failure. 448 BC_ERR_FATAL_IO_ERR, 449 450 /// File error, such as permissions or file does not exist. 451 BC_ERR_FATAL_FILE_ERR, 452 453 /// File is binary, not text, error. 454 BC_ERR_FATAL_BIN_FILE, 455 456 /// Attempted to read a directory as a file error. 457 BC_ERR_FATAL_PATH_DIR, 458 459 /// Invalid option error. 460 BC_ERR_FATAL_OPTION, 461 462 /// Option with required argument not given an argument. 463 BC_ERR_FATAL_OPTION_NO_ARG, 464 465 /// Option with no argument given an argument. 466 BC_ERR_FATAL_OPTION_ARG, 467 468 /// Option argument is invalid. 469 BC_ERR_FATAL_ARG, 470 471 // Runtime errors. 472 473 /// Invalid ibase value. 474 BC_ERR_EXEC_IBASE, 475 476 /// Invalid obase value. 477 BC_ERR_EXEC_OBASE, 478 479 /// Invalid scale value. 480 BC_ERR_EXEC_SCALE, 481 482 /// Invalid expression parsed by read(). 483 BC_ERR_EXEC_READ_EXPR, 484 485 /// read() used within an expression given to a read() call. 486 BC_ERR_EXEC_REC_READ, 487 488 /// Type error. 489 BC_ERR_EXEC_TYPE, 490 491 /// Stack has too few elements error. 492 BC_ERR_EXEC_STACK, 493 494 /// Register stack has too few elements error. 495 BC_ERR_EXEC_STACK_REGISTER, 496 497 /// Wrong number of arguments error. 498 BC_ERR_EXEC_PARAMS, 499 500 /// Undefined function error. 501 BC_ERR_EXEC_UNDEF_FUNC, 502 503 /// Void value used in an expression error. 504 BC_ERR_EXEC_VOID_VAL, 505 506 // Parse (and lex) errors. 507 508 /// EOF encountered when not expected error. 509 BC_ERR_PARSE_EOF, 510 511 /// Invalid character error. 512 BC_ERR_PARSE_CHAR, 513 514 /// Invalid string (no ending quote) error. 515 BC_ERR_PARSE_STRING, 516 517 /// Invalid comment (no end found) error. 518 BC_ERR_PARSE_COMMENT, 519 520 /// Invalid token encountered error. 521 BC_ERR_PARSE_TOKEN, 522 523 #if BC_ENABLED 524 525 /// Invalid expression error. 526 BC_ERR_PARSE_EXPR, 527 528 /// Expression is empty error. 529 BC_ERR_PARSE_EMPTY_EXPR, 530 531 /// Print statement is invalid error. 532 BC_ERR_PARSE_PRINT, 533 534 /// Function definition is invalid error. 535 BC_ERR_PARSE_FUNC, 536 537 /// Assignment is invalid error. 538 BC_ERR_PARSE_ASSIGN, 539 540 /// No auto identifiers given for an auto statement error. 541 BC_ERR_PARSE_NO_AUTO, 542 543 /// Duplicate local (parameter or auto) error. 544 BC_ERR_PARSE_DUP_LOCAL, 545 546 /// Invalid block (within braces) error. 547 BC_ERR_PARSE_BLOCK, 548 549 /// Invalid return statement for void functions. 550 BC_ERR_PARSE_RET_VOID, 551 552 /// Reference attached to a variable, not an array, error. 553 BC_ERR_PARSE_REF_VAR, 554 555 // POSIX-only errors. 556 557 /// Name length greater than 1 error. 558 BC_ERR_POSIX_NAME_LEN, 559 560 /// Non-POSIX comment used error. 561 BC_ERR_POSIX_COMMENT, 562 563 /// Non-POSIX keyword error. 564 BC_ERR_POSIX_KW, 565 566 /// Non-POSIX . (last) error. 567 BC_ERR_POSIX_DOT, 568 569 /// Non-POSIX return error. 570 BC_ERR_POSIX_RET, 571 572 /// Non-POSIX boolean operator used error. 573 BC_ERR_POSIX_BOOL, 574 575 /// POSIX relation operator used outside if, while, or for statements error. 576 BC_ERR_POSIX_REL_POS, 577 578 /// Multiple POSIX relation operators used in an if, while, or for statement 579 /// error. 580 BC_ERR_POSIX_MULTIREL, 581 582 /// Empty statements in POSIX for loop error. 583 BC_ERR_POSIX_FOR, 584 585 /// POSIX's grammar does not allow a function definition right after a 586 /// semicolon. 587 BC_ERR_POSIX_FUNC_AFTER_SEMICOLON, 588 589 /// Non-POSIX exponential (scientific or engineering) number used error. 590 BC_ERR_POSIX_EXP_NUM, 591 592 /// Non-POSIX array reference error. 593 BC_ERR_POSIX_REF, 594 595 /// Non-POSIX void error. 596 BC_ERR_POSIX_VOID, 597 598 /// Non-POSIX brace position used error. 599 BC_ERR_POSIX_BRACE, 600 601 /// String used in expression. 602 BC_ERR_POSIX_EXPR_STRING, 603 604 #endif // BC_ENABLED 605 606 // Number of elements. 607 BC_ERR_NELEMS, 608 609 #if BC_ENABLED 610 611 /// A marker for the start of POSIX errors. 612 BC_ERR_POSIX_START = BC_ERR_POSIX_NAME_LEN, 613 614 /// A marker for the end of POSIX errors. 615 BC_ERR_POSIX_END = BC_ERR_POSIX_EXPR_STRING, 616 617 #endif // BC_ENABLED 618 619 } BcErr; 620 621 // The indices of each category of error in bc_errs[], and used in bc_err_ids[] 622 // to associate actual errors with their categories. 623 624 /// Math error category. 625 #define BC_ERR_IDX_MATH (0) 626 627 /// Parse (and lex) error category. 628 #define BC_ERR_IDX_PARSE (1) 629 630 /// Runtime error category. 631 #define BC_ERR_IDX_EXEC (2) 632 633 /// Fatal error category. 634 #define BC_ERR_IDX_FATAL (3) 635 636 /// Number of categories. 637 #define BC_ERR_IDX_NELEMS (4) 638 639 // If bc is enabled, we add an extra category for POSIX warnings. 640 #if BC_ENABLED 641 642 /// POSIX warning category. 643 #define BC_ERR_IDX_WARN (BC_ERR_IDX_NELEMS) 644 645 #endif // BC_ENABLED 646 647 /** 648 * The mode bc is in. This is basically what input it is processing. 649 */ 650 typedef enum BcMode 651 { 652 /// Expressions mode. 653 BC_MODE_EXPRS, 654 655 /// File mode. 656 BC_MODE_FILE, 657 658 #if !BC_ENABLE_OSSFUZZ 659 660 /// stdin mode. 661 BC_MODE_STDIN, 662 663 #endif // !BC_ENABLE_OSSFUZZ 664 665 } BcMode; 666 667 /// Do a longjmp(). This is what to use when activating an "exception", i.e., a 668 /// longjmp(). With debug code, it will print the name of the function it jumped 669 /// from. 670 #if BC_DEBUG_CODE 671 #define BC_JMP bc_vm_jmp(__func__) 672 #else // BC_DEBUG_CODE 673 #define BC_JMP bc_vm_jmp() 674 #endif // BC_DEBUG_CODE 675 676 #if !BC_ENABLE_LIBRARY 677 678 /// Returns true if an exception is in flight, false otherwise. 679 #define BC_SIG_EXC(vm) \ 680 BC_UNLIKELY((vm)->status != (sig_atomic_t) BC_STATUS_SUCCESS || (vm)->sig) 681 682 /// Returns true if there is *no* exception in flight, false otherwise. 683 #define BC_NO_SIG_EXC(vm) \ 684 BC_LIKELY((vm)->status == (sig_atomic_t) BC_STATUS_SUCCESS && !(vm)->sig) 685 686 #ifndef _WIN32 687 #define BC_SIG_INTERRUPT(vm) \ 688 BC_UNLIKELY((vm)->sig != 0 && (vm)->sig != SIGWINCH) 689 #else // _WIN32 690 #define BC_SIG_INTERRUPT(vm) BC_UNLIKELY((vm)->sig != 0) 691 #endif // _WIN32 692 693 #if BC_DEBUG 694 695 /// Assert that signals are locked. There are non-async-signal-safe functions in 696 /// bc, and they *must* have signals locked. Other functions are expected to 697 /// *not* have signals locked, for reasons. So this is a pre-built assert 698 /// (no-op in non-debug mode) that check that signals are locked. 699 #define BC_SIG_ASSERT_LOCKED \ 700 do \ 701 { \ 702 assert(vm->sig_lock); \ 703 } \ 704 while (0) 705 706 /// Assert that signals are unlocked. There are non-async-signal-safe functions 707 /// in bc, and they *must* have signals locked. Other functions are expected to 708 /// *not* have signals locked, for reasons. So this is a pre-built assert 709 /// (no-op in non-debug mode) that check that signals are unlocked. 710 #define BC_SIG_ASSERT_NOT_LOCKED \ 711 do \ 712 { \ 713 assert(vm->sig_lock == 0); \ 714 } \ 715 while (0) 716 717 #else // BC_DEBUG 718 719 /// Assert that signals are locked. There are non-async-signal-safe functions in 720 /// bc, and they *must* have signals locked. Other functions are expected to 721 /// *not* have signals locked, for reasons. So this is a pre-built assert 722 /// (no-op in non-debug mode) that check that signals are locked. 723 #define BC_SIG_ASSERT_LOCKED 724 725 /// Assert that signals are unlocked. There are non-async-signal-safe functions 726 /// in bc, and they *must* have signals locked. Other functions are expected to 727 /// *not* have signals locked, for reasons. So this is a pre-built assert 728 /// (no-op in non-debug mode) that check that signals are unlocked. 729 #define BC_SIG_ASSERT_NOT_LOCKED 730 731 #endif // BC_DEBUG 732 733 /// Locks signals. 734 #define BC_SIG_LOCK \ 735 do \ 736 { \ 737 BC_SIG_ASSERT_NOT_LOCKED; \ 738 vm->sig_lock = 1; \ 739 } \ 740 while (0) 741 742 /// Unlocks signals. If a signal happened, then this will cause a jump. 743 #define BC_SIG_UNLOCK \ 744 do \ 745 { \ 746 BC_SIG_ASSERT_LOCKED; \ 747 vm->sig_lock = 0; \ 748 if (vm->sig) BC_JMP; \ 749 } \ 750 while (0) 751 752 /// Locks signals, regardless of if they are already locked. This is really only 753 /// used after labels that longjmp() goes to after the jump because the cleanup 754 /// code must have signals locked, and BC_LONGJMP_CONT will unlock signals if it 755 /// doesn't jump. 756 #define BC_SIG_MAYLOCK \ 757 do \ 758 { \ 759 vm->sig_lock = 1; \ 760 } \ 761 while (0) 762 763 /// Unlocks signals, regardless of if they were already unlocked. If a signal 764 /// happened, then this will cause a jump. 765 #define BC_SIG_MAYUNLOCK \ 766 do \ 767 { \ 768 vm->sig_lock = 0; \ 769 if (vm->sig) BC_JMP; \ 770 } \ 771 while (0) 772 773 /** 774 * Locks signals, but stores the old lock state, to be restored later by 775 * BC_SIG_TRYUNLOCK. 776 * @param v The variable to store the old lock state to. 777 */ 778 #define BC_SIG_TRYLOCK(v) \ 779 do \ 780 { \ 781 v = vm->sig_lock; \ 782 vm->sig_lock = 1; \ 783 } \ 784 while (0) 785 786 /** 787 * Restores the previous state of a signal lock, and if it is now unlocked, 788 * initiates an exception/jump. 789 * @param v The old lock state. 790 */ 791 #define BC_SIG_TRYUNLOCK(v) \ 792 do \ 793 { \ 794 vm->sig_lock = (v); \ 795 if (!(v) && vm->sig) BC_JMP; \ 796 } \ 797 while (0) 798 799 /// Stops a stack unwinding. Technically, a stack unwinding needs to be done 800 /// manually, but it will always be done unless certain flags are cleared. This 801 /// clears the flags. 802 #define BC_LONGJMP_STOP \ 803 do \ 804 { \ 805 vm->sig_pop = 0; \ 806 vm->sig = 0; \ 807 } \ 808 while (0) 809 810 /** 811 * Sets a jump like BC_SETJMP, but unlike BC_SETJMP, it assumes signals are 812 * locked and will just set the jump. This does *not* have a call to 813 * bc_vec_grow() because it is assumed that BC_SETJMP_LOCKED(l) is used *after* 814 * the initializations that need the setjmp(). 815 * param l The label to jump to on a longjmp(). 816 */ 817 #define BC_SETJMP_LOCKED(vm, l) \ 818 do \ 819 { \ 820 sigjmp_buf sjb; \ 821 BC_SIG_ASSERT_LOCKED; \ 822 if (sigsetjmp(sjb, 0)) \ 823 { \ 824 assert(BC_SIG_EXC(vm)); \ 825 goto l; \ 826 } \ 827 bc_vec_push(&vm->jmp_bufs, &sjb); \ 828 } \ 829 while (0) 830 831 /// Used after cleanup labels set by BC_SETJMP and BC_SETJMP_LOCKED to jump to 832 /// the next place. This is what continues the stack unwinding. This basically 833 /// copies BC_SIG_UNLOCK into itself, but that is because its condition for 834 /// jumping is BC_SIG_EXC, not just that a signal happened. 835 #define BC_LONGJMP_CONT(vm) \ 836 do \ 837 { \ 838 BC_SIG_ASSERT_LOCKED; \ 839 if (!vm->sig_pop) bc_vec_pop(&vm->jmp_bufs); \ 840 vm->sig_lock = 0; \ 841 if (BC_SIG_EXC(vm)) BC_JMP; \ 842 } \ 843 while (0) 844 845 #else // !BC_ENABLE_LIBRARY 846 847 #define BC_SIG_LOCK 848 #define BC_SIG_UNLOCK 849 #define BC_SIG_MAYLOCK 850 #define BC_SIG_TRYLOCK(lock) 851 #define BC_SIG_TRYUNLOCK(lock) 852 #define BC_SIG_ASSERT_LOCKED 853 854 /// Returns true if an exception is in flight, false otherwise. 855 #define BC_SIG_EXC(vm) \ 856 BC_UNLIKELY(vm->status != (sig_atomic_t) BC_STATUS_SUCCESS) 857 858 /// Returns true if there is *no* exception in flight, false otherwise. 859 #define BC_NO_SIG_EXC(vm) \ 860 BC_LIKELY(vm->status == (sig_atomic_t) BC_STATUS_SUCCESS) 861 862 /// Used after cleanup labels set by BC_SETJMP and BC_SETJMP_LOCKED to jump to 863 /// the next place. This is what continues the stack unwinding. This basically 864 /// copies BC_SIG_UNLOCK into itself, but that is because its condition for 865 /// jumping is BC_SIG_EXC, not just that a signal happened. 866 #define BC_LONGJMP_CONT(vm) \ 867 do \ 868 { \ 869 bc_vec_pop(&vm->jmp_bufs); \ 870 if (BC_SIG_EXC(vm)) BC_JMP; \ 871 } \ 872 while (0) 873 874 #endif // !BC_ENABLE_LIBRARY 875 876 /** 877 * Sets a jump, and sets it up as well so that if a longjmp() happens, bc will 878 * immediately goto a label where some cleanup code is. This one assumes that 879 * signals are not locked and will lock them, set the jump, and unlock them. 880 * Setting the jump also includes pushing the jmp_buf onto the jmp_buf stack. 881 * This grows the jmp_bufs vector first to prevent a fatal error from happening 882 * after the setjmp(). This is done because BC_SETJMP(l) is assumed to be used 883 * *before* the actual initialization calls that need the setjmp(). 884 * param l The label to jump to on a longjmp(). 885 */ 886 #define BC_SETJMP(vm, l) \ 887 do \ 888 { \ 889 sigjmp_buf sjb; \ 890 BC_SIG_LOCK; \ 891 bc_vec_grow(&vm->jmp_bufs, 1); \ 892 if (sigsetjmp(sjb, 0)) \ 893 { \ 894 assert(BC_SIG_EXC(vm)); \ 895 goto l; \ 896 } \ 897 bc_vec_push(&vm->jmp_bufs, &sjb); \ 898 BC_SIG_UNLOCK; \ 899 } \ 900 while (0) 901 902 /// Unsets a jump. It always assumes signals are locked. This basically just 903 /// pops a jmp_buf off of the stack of jmp_bufs, and since the jump mechanism 904 /// always jumps to the location at the top of the stack, this effectively 905 /// undoes a setjmp(). 906 #define BC_UNSETJMP(vm) \ 907 do \ 908 { \ 909 BC_SIG_ASSERT_LOCKED; \ 910 bc_vec_pop(&vm->jmp_bufs); \ 911 } \ 912 while (0) 913 914 #if BC_ENABLE_LIBRARY 915 916 #define BC_SETJMP_LOCKED(vm, l) BC_SETJMP(vm, l) 917 918 // Various convenience macros for calling the bc's error handling routine. 919 920 /** 921 * Call bc's error handling routine. 922 * @param e The error. 923 * @param l The line of the script that the error happened. 924 * @param ... Extra arguments for error messages as necessary. 925 */ 926 #define bc_error(e, l, ...) (bc_vm_handleError((e))) 927 928 /** 929 * Call bc's error handling routine. 930 * @param e The error. 931 */ 932 #define bc_err(e) (bc_vm_handleError((e))) 933 934 /** 935 * Call bc's error handling routine. 936 * @param e The error. 937 */ 938 #define bc_verr(e, ...) (bc_vm_handleError((e))) 939 940 #else // BC_ENABLE_LIBRARY 941 942 // Various convenience macros for calling the bc's error handling routine. 943 944 /** 945 * Call bc's error handling routine. 946 * @param e The error. 947 * @param l The line of the script that the error happened. 948 * @param ... Extra arguments for error messages as necessary. 949 */ 950 #if BC_DEBUG 951 #define bc_error(e, l, ...) \ 952 (bc_vm_handleError((e), __FILE__, __LINE__, (l), __VA_ARGS__)) 953 #else // BC_DEBUG 954 #define bc_error(e, l, ...) (bc_vm_handleError((e), (l), __VA_ARGS__)) 955 #endif // BC_DEBUG 956 957 /** 958 * Call bc's error handling routine. 959 * @param e The error. 960 */ 961 #if BC_DEBUG 962 #define bc_err(e) (bc_vm_handleError((e), __FILE__, __LINE__, 0)) 963 #else // BC_DEBUG 964 #define bc_err(e) (bc_vm_handleError((e), 0)) 965 #endif // BC_DEBUG 966 967 /** 968 * Call bc's error handling routine. 969 * @param e The error. 970 */ 971 #if BC_DEBUG 972 #define bc_verr(e, ...) \ 973 (bc_vm_handleError((e), __FILE__, __LINE__, 0, __VA_ARGS__)) 974 #else // BC_DEBUG 975 #define bc_verr(e, ...) (bc_vm_handleError((e), 0, __VA_ARGS__)) 976 #endif // BC_DEBUG 977 978 #endif // BC_ENABLE_LIBRARY 979 980 /** 981 * Returns true if status @a s is an error, false otherwise. 982 * @param s The status to test. 983 * @return True if @a s is an error, false otherwise. 984 */ 985 #define BC_STATUS_IS_ERROR(s) \ 986 ((s) >= BC_STATUS_ERROR_MATH && (s) <= BC_STATUS_ERROR_FATAL) 987 988 // Convenience macros that can be placed at the beginning and exits of functions 989 // for easy marking of where functions are entered and exited. 990 #if BC_DEBUG_CODE 991 #define BC_FUNC_ENTER \ 992 do \ 993 { \ 994 size_t bc_func_enter_i; \ 995 for (bc_func_enter_i = 0; bc_func_enter_i < vm->func_depth; \ 996 ++bc_func_enter_i) \ 997 { \ 998 bc_file_puts(&vm->ferr, bc_flush_none, " "); \ 999 } \ 1000 vm->func_depth += 1; \ 1001 bc_file_printf(&vm->ferr, "Entering %s\n", __func__); \ 1002 bc_file_flush(&vm->ferr, bc_flush_none); \ 1003 } \ 1004 while (0); 1005 1006 #define BC_FUNC_EXIT \ 1007 do \ 1008 { \ 1009 size_t bc_func_enter_i; \ 1010 vm->func_depth -= 1; \ 1011 for (bc_func_enter_i = 0; bc_func_enter_i < vm->func_depth; \ 1012 ++bc_func_enter_i) \ 1013 { \ 1014 bc_file_puts(&vm->ferr, bc_flush_none, " "); \ 1015 } \ 1016 bc_file_printf(&vm->ferr, "Leaving %s\n", __func__); \ 1017 bc_file_flush(&vm->ferr, bc_flush_none); \ 1018 } \ 1019 while (0); 1020 #else // BC_DEBUG_CODE 1021 #define BC_FUNC_ENTER 1022 #define BC_FUNC_EXIT 1023 #endif // BC_DEBUG_CODE 1024 1025 #endif // BC_STATUS_H 1026