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