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