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