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