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