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