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 * Definitions for bc's VM. 33 * 34 */ 35 36 #ifndef BC_VM_H 37 #define BC_VM_H 38 39 #include <assert.h> 40 #include <stddef.h> 41 #include <limits.h> 42 43 #include <signal.h> 44 45 #if BC_ENABLE_NLS 46 47 # ifdef _WIN32 48 # error NLS is not supported on Windows. 49 # endif // _WIN32 50 51 #include <nl_types.h> 52 53 #endif // BC_ENABLE_NLS 54 55 #include <version.h> 56 #include <status.h> 57 #include <num.h> 58 #include <parse.h> 59 #include <program.h> 60 #include <history.h> 61 62 #if !BC_ENABLE_LIBRARY 63 #include <file.h> 64 #endif // !BC_ENABLE_LIBRARY 65 66 #if !BC_ENABLED && !DC_ENABLED 67 #error Must define BC_ENABLED, DC_ENABLED, or both 68 #endif 69 70 // CHAR_BIT must be at least 6. 71 #if CHAR_BIT < 6 72 #error CHAR_BIT must be at least 6. 73 #endif 74 75 #ifndef BC_ENABLE_NLS 76 #define BC_ENABLE_NLS (0) 77 #endif // BC_ENABLE_NLS 78 79 #ifndef MAINEXEC 80 #define MAINEXEC bc 81 #endif // MAINEXEC 82 83 #ifndef _WIN32 84 #ifndef EXECPREFIX 85 #define EXECPREFIX 86 #endif // EXECPREFIX 87 #else // _WIN32 88 #undef EXECPREFIX 89 #endif // _WIN32 90 91 #define GEN_STR(V) #V 92 #define GEN_STR2(V) GEN_STR(V) 93 94 #define BC_VERSION GEN_STR2(VERSION) 95 #define BC_MAINEXEC GEN_STR2(MAINEXEC) 96 #define BC_BUILD_TYPE GEN_STR2(BUILD_TYPE) 97 98 #ifndef _WIN32 99 #define BC_EXECPREFIX GEN_STR2(EXECPREFIX) 100 #else // _WIN32 101 #define BC_EXECPREFIX "" 102 #endif // _WIN32 103 104 #if !BC_ENABLE_LIBRARY 105 106 #if DC_ENABLED 107 #define DC_FLAG_X (UINTMAX_C(1)<<0) 108 #endif // DC_ENABLED 109 110 #if BC_ENABLED 111 #define BC_FLAG_W (UINTMAX_C(1)<<1) 112 #define BC_FLAG_S (UINTMAX_C(1)<<2) 113 #define BC_FLAG_L (UINTMAX_C(1)<<3) 114 #define BC_FLAG_G (UINTMAX_C(1)<<4) 115 #endif // BC_ENABLED 116 117 #define BC_FLAG_I (UINTMAX_C(1)<<5) 118 #define BC_FLAG_P (UINTMAX_C(1)<<6) 119 #define BC_FLAG_R (UINTMAX_C(1)<<7) 120 #define BC_FLAG_TTYIN (UINTMAX_C(1)<<8) 121 #define BC_FLAG_TTY (UINTMAX_C(1)<<9) 122 #define BC_TTYIN (vm.flags & BC_FLAG_TTYIN) 123 #define BC_TTY (vm.flags & BC_FLAG_TTY) 124 125 #if BC_ENABLED 126 127 #define BC_S (vm.flags & BC_FLAG_S) 128 #define BC_W (vm.flags & BC_FLAG_W) 129 #define BC_L (vm.flags & BC_FLAG_L) 130 #define BC_G (vm.flags & BC_FLAG_G) 131 132 #endif // BC_ENABLED 133 134 #if DC_ENABLED 135 #define DC_X (vm.flags & DC_FLAG_X) 136 #endif // DC_ENABLED 137 138 #define BC_I (vm.flags & BC_FLAG_I) 139 #define BC_P (vm.flags & BC_FLAG_P) 140 #define BC_R (vm.flags & BC_FLAG_R) 141 142 #if BC_ENABLED 143 144 #define BC_IS_POSIX (BC_S || BC_W) 145 146 #if DC_ENABLED 147 #define BC_IS_BC (vm.name[0] != 'd') 148 #define BC_IS_DC (vm.name[0] == 'd') 149 #else // DC_ENABLED 150 #define BC_IS_BC (1) 151 #define BC_IS_DC (0) 152 #endif // DC_ENABLED 153 154 #else // BC_ENABLED 155 #define BC_IS_POSIX (0) 156 #define BC_IS_BC (0) 157 #define BC_IS_DC (1) 158 #endif // BC_ENABLED 159 160 #if BC_ENABLED 161 #define BC_USE_PROMPT (!BC_P && BC_TTY && !BC_IS_POSIX) 162 #else // BC_ENABLED 163 #define BC_USE_PROMPT (!BC_P && BC_TTY) 164 #endif // BC_ENABLED 165 166 #endif // !BC_ENABLE_LIBRARY 167 168 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b)) 169 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b)) 170 171 #define BC_MAX_OBASE ((BcBigDig) (BC_BASE_POW)) 172 #define BC_MAX_DIM ((BcBigDig) (SIZE_MAX - 1)) 173 #define BC_MAX_SCALE ((BcBigDig) (BC_NUM_BIGDIG_MAX - 1)) 174 #define BC_MAX_STRING ((BcBigDig) (BC_NUM_BIGDIG_MAX - 1)) 175 #define BC_MAX_NAME BC_MAX_STRING 176 #define BC_MAX_NUM BC_MAX_SCALE 177 178 #if BC_ENABLE_EXTRA_MATH 179 #define BC_MAX_RAND ((BcBigDig) (((BcRand) 0) - 1)) 180 #endif // BC_ENABLE_EXTRA_MATH 181 182 #define BC_MAX_EXP ((ulong) (BC_NUM_BIGDIG_MAX)) 183 #define BC_MAX_VARS ((ulong) (SIZE_MAX - 1)) 184 185 #if BC_DEBUG_CODE 186 #define BC_VM_JMP bc_vm_jmp(__func__) 187 #else // BC_DEBUG_CODE 188 #define BC_VM_JMP bc_vm_jmp() 189 #endif // BC_DEBUG_CODE 190 191 #define BC_SIG_EXC \ 192 BC_UNLIKELY(vm.status != (sig_atomic_t) BC_STATUS_SUCCESS || vm.sig) 193 #define BC_NO_SIG_EXC \ 194 BC_LIKELY(vm.status == (sig_atomic_t) BC_STATUS_SUCCESS && !vm.sig) 195 196 #ifndef NDEBUG 197 #define BC_SIG_ASSERT_LOCKED do { assert(vm.sig_lock); } while (0) 198 #define BC_SIG_ASSERT_NOT_LOCKED do { assert(vm.sig_lock == 0); } while (0) 199 #else // NDEBUG 200 #define BC_SIG_ASSERT_LOCKED 201 #define BC_SIG_ASSERT_NOT_LOCKED 202 #endif // NDEBUG 203 204 #define BC_SIG_LOCK \ 205 do { \ 206 BC_SIG_ASSERT_NOT_LOCKED; \ 207 vm.sig_lock = 1; \ 208 } while (0) 209 210 #define BC_SIG_UNLOCK \ 211 do { \ 212 BC_SIG_ASSERT_LOCKED; \ 213 vm.sig_lock = 0; \ 214 if (BC_SIG_EXC) BC_VM_JMP; \ 215 } while (0) 216 217 #define BC_SIG_MAYLOCK \ 218 do { \ 219 vm.sig_lock = 1; \ 220 } while (0) 221 222 #define BC_SIG_MAYUNLOCK \ 223 do { \ 224 vm.sig_lock = 0; \ 225 if (BC_SIG_EXC) BC_VM_JMP; \ 226 } while (0) 227 228 #define BC_SIG_TRYLOCK(v) \ 229 do { \ 230 v = vm.sig_lock; \ 231 vm.sig_lock = 1; \ 232 } while (0) 233 234 #define BC_SIG_TRYUNLOCK(v) \ 235 do { \ 236 vm.sig_lock = (v); \ 237 if (!(v) && BC_SIG_EXC) BC_VM_JMP; \ 238 } while (0) 239 240 #define BC_SETJMP(l) \ 241 do { \ 242 sigjmp_buf sjb; \ 243 BC_SIG_LOCK; \ 244 if (sigsetjmp(sjb, 0)) { \ 245 assert(BC_SIG_EXC); \ 246 goto l; \ 247 } \ 248 bc_vec_push(&vm.jmp_bufs, &sjb); \ 249 BC_SIG_UNLOCK; \ 250 } while (0) 251 252 #define BC_SETJMP_LOCKED(l) \ 253 do { \ 254 sigjmp_buf sjb; \ 255 BC_SIG_ASSERT_LOCKED; \ 256 if (sigsetjmp(sjb, 0)) { \ 257 assert(BC_SIG_EXC); \ 258 goto l; \ 259 } \ 260 bc_vec_push(&vm.jmp_bufs, &sjb); \ 261 } while (0) 262 263 #define BC_LONGJMP_CONT \ 264 do { \ 265 BC_SIG_ASSERT_LOCKED; \ 266 if (!vm.sig_pop) bc_vec_pop(&vm.jmp_bufs); \ 267 BC_SIG_UNLOCK; \ 268 } while (0) 269 270 #define BC_UNSETJMP \ 271 do { \ 272 BC_SIG_ASSERT_LOCKED; \ 273 bc_vec_pop(&vm.jmp_bufs); \ 274 } while (0) 275 276 #define BC_LONGJMP_STOP \ 277 do { \ 278 vm.sig_pop = 0; \ 279 vm.sig = 0; \ 280 } while (0) 281 282 #define BC_VM_BUF_SIZE (1<<12) 283 #define BC_VM_STDOUT_BUF_SIZE (1<<11) 284 #define BC_VM_STDERR_BUF_SIZE (1<<10) 285 #define BC_VM_STDIN_BUF_SIZE (BC_VM_STDERR_BUF_SIZE - 1) 286 287 #define BC_VM_SAFE_RESULT(r) ((r)->t >= BC_RESULT_TEMP) 288 289 #if BC_ENABLE_LIBRARY 290 #define bc_vm_error(e, l, ...) (bc_vm_handleError((e))) 291 #define bc_vm_err(e) (bc_vm_handleError((e))) 292 #define bc_vm_verr(e, ...) (bc_vm_handleError((e))) 293 #else // BC_ENABLE_LIBRARY 294 #define bc_vm_error(e, l, ...) (bc_vm_handleError((e), (l), __VA_ARGS__)) 295 #define bc_vm_err(e) (bc_vm_handleError((e), 0)) 296 #define bc_vm_verr(e, ...) (bc_vm_handleError((e), 0, __VA_ARGS__)) 297 #endif // BC_ENABLE_LIBRARY 298 299 #define BC_STATUS_IS_ERROR(s) \ 300 ((s) >= BC_STATUS_ERROR_MATH && (s) <= BC_STATUS_ERROR_FATAL) 301 302 #define BC_VM_INVALID_CATALOG ((nl_catd) -1) 303 304 #if BC_DEBUG_CODE 305 #define BC_VM_FUNC_ENTER \ 306 do { \ 307 bc_file_printf(&vm.ferr, "Entering %s\n", __func__); \ 308 bc_file_flush(&vm.ferr); \ 309 } while (0); 310 311 #define BC_VM_FUNC_EXIT \ 312 do { \ 313 bc_file_printf(&vm.ferr, "Leaving %s\n", __func__); \ 314 bc_file_flush(&vm.ferr); \ 315 } while (0); 316 #else // BC_DEBUG_CODE 317 #define BC_VM_FUNC_ENTER 318 #define BC_VM_FUNC_EXIT 319 #endif // BC_DEBUG_CODE 320 321 typedef struct BcVm { 322 323 volatile sig_atomic_t status; 324 volatile sig_atomic_t sig_pop; 325 326 #if !BC_ENABLE_LIBRARY 327 BcParse prs; 328 BcProgram prog; 329 #endif // !BC_ENABLE_LIBRARY 330 331 BcVec jmp_bufs; 332 333 BcVec temps; 334 335 #if BC_ENABLE_LIBRARY 336 337 BcVec ctxts; 338 BcVec out; 339 340 BcRNG rng; 341 342 BclError err; 343 bool abrt; 344 345 unsigned int refs; 346 347 volatile sig_atomic_t running; 348 #endif // BC_ENABLE_LIBRARY 349 350 #if !BC_ENABLE_LIBRARY 351 const char* file; 352 353 const char *sigmsg; 354 #endif // !BC_ENABLE_LIBRARY 355 volatile sig_atomic_t sig_lock; 356 volatile sig_atomic_t sig; 357 #if !BC_ENABLE_LIBRARY 358 uchar siglen; 359 360 uchar read_ret; 361 uint16_t flags; 362 363 uint16_t nchars; 364 uint16_t line_len; 365 366 bool no_exit_exprs; 367 bool exit_exprs; 368 bool eof; 369 #endif // !BC_ENABLE_LIBRARY 370 371 BcBigDig maxes[BC_PROG_GLOBALS_LEN + BC_ENABLE_EXTRA_MATH]; 372 373 #if !BC_ENABLE_LIBRARY 374 BcVec files; 375 BcVec exprs; 376 377 const char *name; 378 const char *help; 379 380 #if BC_ENABLE_HISTORY 381 BcHistory history; 382 #endif // BC_ENABLE_HISTORY 383 384 BcLexNext next; 385 BcParseParse parse; 386 BcParseExpr expr; 387 388 const char *func_header; 389 390 const char *err_ids[BC_ERR_IDX_NELEMS + BC_ENABLED]; 391 const char *err_msgs[BC_ERR_NELEMS]; 392 393 const char *locale; 394 #endif // !BC_ENABLE_LIBRARY 395 396 BcBigDig last_base; 397 BcBigDig last_pow; 398 BcBigDig last_exp; 399 BcBigDig last_rem; 400 401 #if !BC_ENABLE_LIBRARY 402 char *env_args_buffer; 403 BcVec env_args; 404 #endif // !BC_ENABLE_LIBRARY 405 406 BcNum max; 407 BcNum max2; 408 BcDig max_num[BC_NUM_BIGDIG_LOG10]; 409 BcDig max2_num[BC_NUM_BIGDIG_LOG10]; 410 411 #if !BC_ENABLE_LIBRARY 412 BcFile fout; 413 BcFile ferr; 414 415 #if BC_ENABLE_NLS 416 nl_catd catalog; 417 #endif // BC_ENABLE_NLS 418 419 char *buf; 420 size_t buf_len; 421 #endif // !BC_ENABLE_LIBRARY 422 423 } BcVm; 424 425 void bc_vm_info(const char* const help); 426 void bc_vm_boot(int argc, char *argv[], const char *env_len, 427 const char* const env_args); 428 void bc_vm_init(void); 429 void bc_vm_shutdown(void); 430 void bc_vm_freeTemps(void); 431 432 #if !BC_ENABLE_HISTORY 433 #define bc_vm_putchar(c, t) bc_vm_putchar(c) 434 #endif // !BC_ENABLE_HISTORY 435 436 void bc_vm_printf(const char *fmt, ...); 437 void bc_vm_putchar(int c, BcFlushType type); 438 size_t bc_vm_arraySize(size_t n, size_t size); 439 size_t bc_vm_growSize(size_t a, size_t b); 440 void* bc_vm_malloc(size_t n); 441 void* bc_vm_realloc(void *ptr, size_t n); 442 char* bc_vm_strdup(const char *str); 443 char* bc_vm_getenv(const char* var); 444 void bc_vm_getenvFree(char* var); 445 446 #if BC_DEBUG_CODE 447 void bc_vm_jmp(const char *f); 448 #else // BC_DEBUG_CODE 449 void bc_vm_jmp(void); 450 #endif // BC_DEBUG_CODE 451 452 #if BC_ENABLE_LIBRARY 453 void bc_vm_handleError(BcErr e); 454 void bc_vm_fatalError(BcErr e); 455 void bc_vm_atexit(void); 456 #else // BC_ENABLE_LIBRARY 457 void bc_vm_handleError(BcErr e, size_t line, ...); 458 #if !BC_ENABLE_LIBRARY && !BC_ENABLE_MEMCHECK 459 BC_NORETURN 460 #endif // !BC_ENABLE_LIBRARY && !BC_ENABLE_MEMCHECK 461 void bc_vm_fatalError(BcErr e); 462 int bc_vm_atexit(int status); 463 #endif // BC_ENABLE_LIBRARY 464 465 extern const char bc_copyright[]; 466 extern const char* const bc_err_line; 467 extern const char* const bc_err_func_header; 468 extern const char *bc_errs[]; 469 extern const uchar bc_err_ids[]; 470 extern const char* const bc_err_msgs[]; 471 472 extern BcVm vm; 473 extern char output_bufs[BC_VM_BUF_SIZE]; 474 475 #endif // BC_VM_H 476