1252884aeSStefan Eßer /* 2252884aeSStefan Eßer * ***************************************************************************** 3252884aeSStefan Eßer * 43aa99676SStefan Eßer * SPDX-License-Identifier: BSD-2-Clause 5252884aeSStefan Eßer * 6*10328f8bSStefan Eßer * Copyright (c) 2018-2021 Gavin D. Howard and contributors. 7252884aeSStefan Eßer * 8252884aeSStefan Eßer * Redistribution and use in source and binary forms, with or without 9252884aeSStefan Eßer * modification, are permitted provided that the following conditions are met: 10252884aeSStefan Eßer * 11252884aeSStefan Eßer * * Redistributions of source code must retain the above copyright notice, this 12252884aeSStefan Eßer * list of conditions and the following disclaimer. 13252884aeSStefan Eßer * 14252884aeSStefan Eßer * * Redistributions in binary form must reproduce the above copyright notice, 15252884aeSStefan Eßer * this list of conditions and the following disclaimer in the documentation 16252884aeSStefan Eßer * and/or other materials provided with the distribution. 17252884aeSStefan Eßer * 18252884aeSStefan Eßer * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19252884aeSStefan Eßer * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20252884aeSStefan Eßer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21252884aeSStefan Eßer * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22252884aeSStefan Eßer * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23252884aeSStefan Eßer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24252884aeSStefan Eßer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25252884aeSStefan Eßer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26252884aeSStefan Eßer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27252884aeSStefan Eßer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28252884aeSStefan Eßer * POSSIBILITY OF SUCH DAMAGE. 29252884aeSStefan Eßer * 30252884aeSStefan Eßer * ***************************************************************************** 31252884aeSStefan Eßer * 32252884aeSStefan Eßer * Code common to all of bc and dc. 33252884aeSStefan Eßer * 34252884aeSStefan Eßer */ 35252884aeSStefan Eßer 36252884aeSStefan Eßer #include <assert.h> 37252884aeSStefan Eßer #include <ctype.h> 38252884aeSStefan Eßer #include <errno.h> 39252884aeSStefan Eßer #include <stdarg.h> 40252884aeSStefan Eßer #include <string.h> 41252884aeSStefan Eßer 42252884aeSStefan Eßer #include <signal.h> 43252884aeSStefan Eßer 44252884aeSStefan Eßer #include <setjmp.h> 45252884aeSStefan Eßer 46252884aeSStefan Eßer #ifndef _WIN32 47252884aeSStefan Eßer 48252884aeSStefan Eßer #include <sys/types.h> 49252884aeSStefan Eßer #include <unistd.h> 50252884aeSStefan Eßer 51252884aeSStefan Eßer #else // _WIN32 52252884aeSStefan Eßer 53252884aeSStefan Eßer #define WIN32_LEAN_AND_MEAN 54252884aeSStefan Eßer #include <windows.h> 55252884aeSStefan Eßer #include <io.h> 56252884aeSStefan Eßer 57252884aeSStefan Eßer #endif // _WIN32 58252884aeSStefan Eßer 59252884aeSStefan Eßer #include <vector.h> 60252884aeSStefan Eßer #include <args.h> 61252884aeSStefan Eßer #include <vm.h> 62252884aeSStefan Eßer #include <read.h> 63252884aeSStefan Eßer #include <bc.h> 64252884aeSStefan Eßer 6550696a6eSStefan Eßer char output_bufs[BC_VM_BUF_SIZE]; 6650696a6eSStefan Eßer BcVm vm; 6750696a6eSStefan Eßer 68252884aeSStefan Eßer #if BC_DEBUG_CODE 69252884aeSStefan Eßer BC_NORETURN void bc_vm_jmp(const char* f) { 70252884aeSStefan Eßer #else // BC_DEBUG_CODE 71252884aeSStefan Eßer BC_NORETURN void bc_vm_jmp(void) { 72252884aeSStefan Eßer #endif 73252884aeSStefan Eßer 743aa99676SStefan Eßer assert(BC_SIG_EXC); 75252884aeSStefan Eßer 76252884aeSStefan Eßer BC_SIG_MAYLOCK; 77252884aeSStefan Eßer 78252884aeSStefan Eßer #if BC_DEBUG_CODE 79252884aeSStefan Eßer bc_file_puts(&vm.ferr, "Longjmp: "); 80252884aeSStefan Eßer bc_file_puts(&vm.ferr, f); 81252884aeSStefan Eßer bc_file_putchar(&vm.ferr, '\n'); 82252884aeSStefan Eßer bc_file_flush(&vm.ferr); 83252884aeSStefan Eßer #endif // BC_DEBUG_CODE 84252884aeSStefan Eßer 85252884aeSStefan Eßer #ifndef NDEBUG 86252884aeSStefan Eßer assert(vm.jmp_bufs.len - (size_t) vm.sig_pop); 87252884aeSStefan Eßer #endif // NDEBUG 88252884aeSStefan Eßer 8950696a6eSStefan Eßer if (vm.jmp_bufs.len == 0) abort(); 90252884aeSStefan Eßer if (vm.sig_pop) bc_vec_pop(&vm.jmp_bufs); 91252884aeSStefan Eßer else vm.sig_pop = 1; 92252884aeSStefan Eßer 93252884aeSStefan Eßer siglongjmp(*((sigjmp_buf*) bc_vec_top(&vm.jmp_bufs)), 1); 94252884aeSStefan Eßer } 95252884aeSStefan Eßer 9650696a6eSStefan Eßer #if !BC_ENABLE_LIBRARY 97252884aeSStefan Eßer static void bc_vm_sig(int sig) { 98252884aeSStefan Eßer 99252884aeSStefan Eßer // There is already a signal in flight. 100252884aeSStefan Eßer if (vm.status == (sig_atomic_t) BC_STATUS_QUIT || vm.sig) { 101252884aeSStefan Eßer if (!BC_TTY || sig != SIGINT) vm.status = BC_STATUS_QUIT; 102252884aeSStefan Eßer return; 103252884aeSStefan Eßer } 104252884aeSStefan Eßer 105252884aeSStefan Eßer if (BC_TTY && sig == SIGINT) { 106252884aeSStefan Eßer 107252884aeSStefan Eßer int err = errno; 108252884aeSStefan Eßer 109252884aeSStefan Eßer if (write(STDOUT_FILENO, vm.sigmsg, vm.siglen) != (ssize_t) vm.siglen) 110252884aeSStefan Eßer vm.status = BC_STATUS_ERROR_FATAL; 111252884aeSStefan Eßer else vm.sig = 1; 112252884aeSStefan Eßer 113252884aeSStefan Eßer errno = err; 114252884aeSStefan Eßer } 115252884aeSStefan Eßer else vm.status = BC_STATUS_QUIT; 116252884aeSStefan Eßer 117252884aeSStefan Eßer assert(vm.jmp_bufs.len); 118252884aeSStefan Eßer 119252884aeSStefan Eßer if (!vm.sig_lock) BC_VM_JMP; 120252884aeSStefan Eßer } 121252884aeSStefan Eßer 122252884aeSStefan Eßer void bc_vm_info(const char* const help) { 123252884aeSStefan Eßer 124252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 125252884aeSStefan Eßer 126252884aeSStefan Eßer bc_file_puts(&vm.fout, vm.name); 127252884aeSStefan Eßer bc_file_putchar(&vm.fout, ' '); 128252884aeSStefan Eßer bc_file_puts(&vm.fout, BC_VERSION); 129252884aeSStefan Eßer bc_file_putchar(&vm.fout, '\n'); 130252884aeSStefan Eßer bc_file_puts(&vm.fout, bc_copyright); 131252884aeSStefan Eßer 132252884aeSStefan Eßer if (help) { 133252884aeSStefan Eßer bc_file_putchar(&vm.fout, '\n'); 134252884aeSStefan Eßer bc_file_printf(&vm.fout, help, vm.name, vm.name); 135252884aeSStefan Eßer } 136252884aeSStefan Eßer 137252884aeSStefan Eßer bc_file_flush(&vm.fout); 138252884aeSStefan Eßer } 13950696a6eSStefan Eßer #endif // !BC_ENABLE_LIBRARY 140252884aeSStefan Eßer 141*10328f8bSStefan Eßer #if !BC_ENABLE_LIBRARY && !BC_ENABLE_MEMCHECK 142*10328f8bSStefan Eßer BC_NORETURN 143*10328f8bSStefan Eßer #endif // !BC_ENABLE_LIBRARY && !BC_ENABLE_MEMCHECK 144*10328f8bSStefan Eßer void bc_vm_fatalError(BcErr e) { 145*10328f8bSStefan Eßer bc_vm_err(e); 146*10328f8bSStefan Eßer #if !BC_ENABLE_LIBRARY && !BC_ENABLE_MEMCHECK 147*10328f8bSStefan Eßer abort(); 148*10328f8bSStefan Eßer #endif // !BC_ENABLE_LIBRARY && !BC_ENABLE_MEMCHECK 149*10328f8bSStefan Eßer } 150*10328f8bSStefan Eßer 15150696a6eSStefan Eßer #if BC_ENABLE_LIBRARY 15250696a6eSStefan Eßer void bc_vm_handleError(BcErr e) { 15350696a6eSStefan Eßer 15450696a6eSStefan Eßer assert(e < BC_ERR_NELEMS); 15550696a6eSStefan Eßer assert(!vm.sig_pop); 15650696a6eSStefan Eßer 15750696a6eSStefan Eßer BC_SIG_LOCK; 15850696a6eSStefan Eßer 15950696a6eSStefan Eßer if (e <= BC_ERR_MATH_DIVIDE_BY_ZERO) { 16050696a6eSStefan Eßer vm.err = (BclError) (e - BC_ERR_MATH_NEGATIVE + 16150696a6eSStefan Eßer BCL_ERROR_MATH_NEGATIVE); 16250696a6eSStefan Eßer } 16350696a6eSStefan Eßer else if (vm.abrt) abort(); 16450696a6eSStefan Eßer else if (e == BC_ERR_FATAL_ALLOC_ERR) vm.err = BCL_ERROR_FATAL_ALLOC_ERR; 16550696a6eSStefan Eßer else vm.err = BCL_ERROR_FATAL_UNKNOWN_ERR; 16650696a6eSStefan Eßer 16750696a6eSStefan Eßer BC_VM_JMP; 16850696a6eSStefan Eßer } 16950696a6eSStefan Eßer #else // BC_ENABLE_LIBRARY 17050696a6eSStefan Eßer void bc_vm_handleError(BcErr e, size_t line, ...) { 171252884aeSStefan Eßer 172252884aeSStefan Eßer BcStatus s; 173252884aeSStefan Eßer va_list args; 174252884aeSStefan Eßer uchar id = bc_err_ids[e]; 175252884aeSStefan Eßer const char* err_type = vm.err_ids[id]; 176252884aeSStefan Eßer sig_atomic_t lock; 177252884aeSStefan Eßer 17850696a6eSStefan Eßer assert(e < BC_ERR_NELEMS); 179252884aeSStefan Eßer assert(!vm.sig_pop); 180252884aeSStefan Eßer 181252884aeSStefan Eßer #if BC_ENABLED 18250696a6eSStefan Eßer if (!BC_S && e >= BC_ERR_POSIX_START) { 183252884aeSStefan Eßer if (BC_W) { 184252884aeSStefan Eßer // Make sure to not return an error. 185252884aeSStefan Eßer id = UCHAR_MAX; 186252884aeSStefan Eßer err_type = vm.err_ids[BC_ERR_IDX_WARN]; 187252884aeSStefan Eßer } 188252884aeSStefan Eßer else return; 189252884aeSStefan Eßer } 190252884aeSStefan Eßer #endif // BC_ENABLED 191252884aeSStefan Eßer 192252884aeSStefan Eßer BC_SIG_TRYLOCK(lock); 193252884aeSStefan Eßer 194252884aeSStefan Eßer // Make sure all of stdout is written first. 195252884aeSStefan Eßer s = bc_file_flushErr(&vm.fout); 196252884aeSStefan Eßer 197252884aeSStefan Eßer if (BC_ERR(s == BC_STATUS_ERROR_FATAL)) { 198252884aeSStefan Eßer vm.status = (sig_atomic_t) s; 199252884aeSStefan Eßer BC_VM_JMP; 200252884aeSStefan Eßer } 201252884aeSStefan Eßer 202252884aeSStefan Eßer va_start(args, line); 203252884aeSStefan Eßer bc_file_putchar(&vm.ferr, '\n'); 204252884aeSStefan Eßer bc_file_puts(&vm.ferr, err_type); 205252884aeSStefan Eßer bc_file_putchar(&vm.ferr, ' '); 206252884aeSStefan Eßer bc_file_vprintf(&vm.ferr, vm.err_msgs[e], args); 207252884aeSStefan Eßer va_end(args); 208252884aeSStefan Eßer 209252884aeSStefan Eßer if (BC_NO_ERR(vm.file)) { 210252884aeSStefan Eßer 211252884aeSStefan Eßer // This is the condition for parsing vs runtime. 212252884aeSStefan Eßer // If line is not 0, it is parsing. 213252884aeSStefan Eßer if (line) { 214252884aeSStefan Eßer bc_file_puts(&vm.ferr, "\n "); 215252884aeSStefan Eßer bc_file_puts(&vm.ferr, vm.file); 216252884aeSStefan Eßer bc_file_printf(&vm.ferr, bc_err_line, line); 217252884aeSStefan Eßer } 218252884aeSStefan Eßer else { 219252884aeSStefan Eßer 220252884aeSStefan Eßer BcInstPtr *ip = bc_vec_item_rev(&vm.prog.stack, 0); 221252884aeSStefan Eßer BcFunc *f = bc_vec_item(&vm.prog.fns, ip->func); 222252884aeSStefan Eßer 223252884aeSStefan Eßer bc_file_puts(&vm.ferr, "\n "); 224252884aeSStefan Eßer bc_file_puts(&vm.ferr, vm.func_header); 225252884aeSStefan Eßer bc_file_putchar(&vm.ferr, ' '); 226252884aeSStefan Eßer bc_file_puts(&vm.ferr, f->name); 227252884aeSStefan Eßer 2283aa99676SStefan Eßer #if BC_ENABLED 229252884aeSStefan Eßer if (BC_IS_BC && ip->func != BC_PROG_MAIN && 230252884aeSStefan Eßer ip->func != BC_PROG_READ) 231252884aeSStefan Eßer { 232252884aeSStefan Eßer bc_file_puts(&vm.ferr, "()"); 233252884aeSStefan Eßer } 2343aa99676SStefan Eßer #endif // BC_ENABLED 235252884aeSStefan Eßer } 236252884aeSStefan Eßer } 237252884aeSStefan Eßer 238252884aeSStefan Eßer bc_file_puts(&vm.ferr, "\n\n"); 239252884aeSStefan Eßer 240252884aeSStefan Eßer s = bc_file_flushErr(&vm.ferr); 241252884aeSStefan Eßer 242*10328f8bSStefan Eßer #if !BC_ENABLE_MEMCHECK 243*10328f8bSStefan Eßer // Because this function is called by a BC_NORETURN function when fatal 244*10328f8bSStefan Eßer // errors happen, we need to make sure to exit on fatal errors. This will 245*10328f8bSStefan Eßer // be faster anyway. This function *cannot jump when a fatal error occurs!* 246*10328f8bSStefan Eßer if (BC_ERR(id == BC_ERR_IDX_FATAL || s == BC_STATUS_ERROR_FATAL)) 247*10328f8bSStefan Eßer exit(bc_vm_atexit((int) BC_STATUS_ERROR_FATAL)); 248*10328f8bSStefan Eßer #else // !BC_ENABLE_MEMCHECK 249*10328f8bSStefan Eßer if (BC_ERR(s == BC_STATUS_ERROR_FATAL)) vm.status = (sig_atomic_t) s; 250*10328f8bSStefan Eßer else 251*10328f8bSStefan Eßer #endif // !BC_ENABLE_MEMCHECK 252*10328f8bSStefan Eßer { 253*10328f8bSStefan Eßer vm.status = (sig_atomic_t) (uchar) (id + 1); 254*10328f8bSStefan Eßer } 255252884aeSStefan Eßer 256252884aeSStefan Eßer if (BC_ERR(vm.status)) BC_VM_JMP; 257252884aeSStefan Eßer 258252884aeSStefan Eßer BC_SIG_TRYUNLOCK(lock); 259252884aeSStefan Eßer } 260252884aeSStefan Eßer 261252884aeSStefan Eßer static void bc_vm_envArgs(const char* const env_args_name) { 262252884aeSStefan Eßer 263252884aeSStefan Eßer char *env_args = getenv(env_args_name), *buf, *start; 264252884aeSStefan Eßer char instr = '\0'; 265252884aeSStefan Eßer 266252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 267252884aeSStefan Eßer 268252884aeSStefan Eßer if (env_args == NULL) return; 269252884aeSStefan Eßer 270252884aeSStefan Eßer start = buf = vm.env_args_buffer = bc_vm_strdup(env_args); 271252884aeSStefan Eßer 272252884aeSStefan Eßer assert(buf != NULL); 273252884aeSStefan Eßer 274252884aeSStefan Eßer bc_vec_init(&vm.env_args, sizeof(char*), NULL); 275252884aeSStefan Eßer bc_vec_push(&vm.env_args, &env_args_name); 276252884aeSStefan Eßer 277252884aeSStefan Eßer while (*buf) { 278252884aeSStefan Eßer 279252884aeSStefan Eßer if (!isspace(*buf)) { 280252884aeSStefan Eßer 281252884aeSStefan Eßer if (*buf == '"' || *buf == '\'') { 282252884aeSStefan Eßer 283252884aeSStefan Eßer instr = *buf; 284252884aeSStefan Eßer buf += 1; 285252884aeSStefan Eßer 286252884aeSStefan Eßer if (*buf == instr) { 287252884aeSStefan Eßer instr = '\0'; 288252884aeSStefan Eßer buf += 1; 289252884aeSStefan Eßer continue; 290252884aeSStefan Eßer } 291252884aeSStefan Eßer } 292252884aeSStefan Eßer 293252884aeSStefan Eßer bc_vec_push(&vm.env_args, &buf); 294252884aeSStefan Eßer 295252884aeSStefan Eßer while (*buf && ((!instr && !isspace(*buf)) || 296252884aeSStefan Eßer (instr && *buf != instr))) 297252884aeSStefan Eßer { 298252884aeSStefan Eßer buf += 1; 299252884aeSStefan Eßer } 300252884aeSStefan Eßer 301252884aeSStefan Eßer if (*buf) { 302252884aeSStefan Eßer 303252884aeSStefan Eßer if (instr) instr = '\0'; 304252884aeSStefan Eßer 305252884aeSStefan Eßer *buf = '\0'; 306252884aeSStefan Eßer buf += 1; 307252884aeSStefan Eßer start = buf; 308252884aeSStefan Eßer } 30950696a6eSStefan Eßer else if (instr) bc_vm_error(BC_ERR_FATAL_OPTION, 0, start); 310252884aeSStefan Eßer } 311252884aeSStefan Eßer else buf += 1; 312252884aeSStefan Eßer } 313252884aeSStefan Eßer 314252884aeSStefan Eßer // Make sure to push a NULL pointer at the end. 315252884aeSStefan Eßer buf = NULL; 316252884aeSStefan Eßer bc_vec_push(&vm.env_args, &buf); 317252884aeSStefan Eßer 318252884aeSStefan Eßer bc_args((int) vm.env_args.len - 1, bc_vec_item(&vm.env_args, 0)); 319252884aeSStefan Eßer } 320252884aeSStefan Eßer 321252884aeSStefan Eßer static size_t bc_vm_envLen(const char *var) { 322252884aeSStefan Eßer 323252884aeSStefan Eßer char *lenv = getenv(var); 324252884aeSStefan Eßer size_t i, len = BC_NUM_PRINT_WIDTH; 325252884aeSStefan Eßer int num; 326252884aeSStefan Eßer 327252884aeSStefan Eßer if (lenv == NULL) return len; 328252884aeSStefan Eßer 329252884aeSStefan Eßer len = strlen(lenv); 330252884aeSStefan Eßer 331252884aeSStefan Eßer for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]); 332252884aeSStefan Eßer 333252884aeSStefan Eßer if (num) { 334252884aeSStefan Eßer len = (size_t) atoi(lenv) - 1; 335252884aeSStefan Eßer if (len < 2 || len >= UINT16_MAX) len = BC_NUM_PRINT_WIDTH; 336252884aeSStefan Eßer } 337252884aeSStefan Eßer else len = BC_NUM_PRINT_WIDTH; 338252884aeSStefan Eßer 339252884aeSStefan Eßer return len; 340252884aeSStefan Eßer } 34150696a6eSStefan Eßer #endif // BC_ENABLE_LIBRARY 342252884aeSStefan Eßer 343252884aeSStefan Eßer void bc_vm_shutdown(void) { 344252884aeSStefan Eßer 345252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 346252884aeSStefan Eßer 347252884aeSStefan Eßer #if BC_ENABLE_NLS 348252884aeSStefan Eßer if (vm.catalog != BC_VM_INVALID_CATALOG) catclose(vm.catalog); 349252884aeSStefan Eßer #endif // BC_ENABLE_NLS 350252884aeSStefan Eßer 351252884aeSStefan Eßer #if BC_ENABLE_HISTORY 352252884aeSStefan Eßer // This must always run to ensure that the terminal is back to normal. 353252884aeSStefan Eßer if (BC_TTY) bc_history_free(&vm.history); 354252884aeSStefan Eßer #endif // BC_ENABLE_HISTORY 355252884aeSStefan Eßer 356252884aeSStefan Eßer #ifndef NDEBUG 35750696a6eSStefan Eßer #if !BC_ENABLE_LIBRARY 358252884aeSStefan Eßer bc_vec_free(&vm.env_args); 359252884aeSStefan Eßer free(vm.env_args_buffer); 360252884aeSStefan Eßer bc_vec_free(&vm.files); 361252884aeSStefan Eßer bc_vec_free(&vm.exprs); 362252884aeSStefan Eßer 363252884aeSStefan Eßer bc_program_free(&vm.prog); 364252884aeSStefan Eßer bc_parse_free(&vm.prs); 36550696a6eSStefan Eßer #endif // !BC_ENABLE_LIBRARY 366252884aeSStefan Eßer 36750696a6eSStefan Eßer bc_vm_freeTemps(); 368252884aeSStefan Eßer bc_vec_free(&vm.temps); 369252884aeSStefan Eßer #endif // NDEBUG 370252884aeSStefan Eßer 37150696a6eSStefan Eßer #if !BC_ENABLE_LIBRARY 372252884aeSStefan Eßer bc_file_free(&vm.fout); 373252884aeSStefan Eßer bc_file_free(&vm.ferr); 37450696a6eSStefan Eßer #endif // !BC_ENABLE_LIBRARY 375252884aeSStefan Eßer } 376252884aeSStefan Eßer 37750696a6eSStefan Eßer #if !defined(NDEBUG) || BC_ENABLE_LIBRARY 37850696a6eSStefan Eßer void bc_vm_freeTemps(void) { 37950696a6eSStefan Eßer 38050696a6eSStefan Eßer size_t i; 38150696a6eSStefan Eßer 38250696a6eSStefan Eßer for (i = 0; i < vm.temps.len; ++i) { 38350696a6eSStefan Eßer free(((BcNum*) bc_vec_item(&vm.temps, i))->num); 38450696a6eSStefan Eßer } 38550696a6eSStefan Eßer } 38650696a6eSStefan Eßer #endif // !defined(NDEBUG) || BC_ENABLE_LIBRARY 38750696a6eSStefan Eßer 3883aa99676SStefan Eßer inline size_t bc_vm_arraySize(size_t n, size_t size) { 389252884aeSStefan Eßer size_t res = n * size; 390252884aeSStefan Eßer if (BC_ERR(res >= SIZE_MAX || (n != 0 && res / n != size))) 391*10328f8bSStefan Eßer bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR); 392252884aeSStefan Eßer return res; 393252884aeSStefan Eßer } 394252884aeSStefan Eßer 3953aa99676SStefan Eßer inline size_t bc_vm_growSize(size_t a, size_t b) { 396252884aeSStefan Eßer size_t res = a + b; 397252884aeSStefan Eßer if (BC_ERR(res >= SIZE_MAX || res < a || res < b)) 398*10328f8bSStefan Eßer bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR); 399252884aeSStefan Eßer return res; 400252884aeSStefan Eßer } 401252884aeSStefan Eßer 402252884aeSStefan Eßer void* bc_vm_malloc(size_t n) { 403252884aeSStefan Eßer 404252884aeSStefan Eßer void* ptr; 405252884aeSStefan Eßer 406252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 407252884aeSStefan Eßer 408252884aeSStefan Eßer ptr = malloc(n); 409252884aeSStefan Eßer 410*10328f8bSStefan Eßer if (BC_ERR(ptr == NULL)) bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR); 411252884aeSStefan Eßer 412252884aeSStefan Eßer return ptr; 413252884aeSStefan Eßer } 414252884aeSStefan Eßer 415252884aeSStefan Eßer void* bc_vm_realloc(void *ptr, size_t n) { 416252884aeSStefan Eßer 417252884aeSStefan Eßer void* temp; 418252884aeSStefan Eßer 419252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 420252884aeSStefan Eßer 421252884aeSStefan Eßer temp = realloc(ptr, n); 422252884aeSStefan Eßer 423*10328f8bSStefan Eßer if (BC_ERR(temp == NULL)) bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR); 424252884aeSStefan Eßer 425252884aeSStefan Eßer return temp; 426252884aeSStefan Eßer } 427252884aeSStefan Eßer 428252884aeSStefan Eßer char* bc_vm_strdup(const char *str) { 429252884aeSStefan Eßer 430252884aeSStefan Eßer char *s; 431252884aeSStefan Eßer 432252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 433252884aeSStefan Eßer 434252884aeSStefan Eßer s = strdup(str); 435252884aeSStefan Eßer 436*10328f8bSStefan Eßer if (BC_ERR(s == NULL)) bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR); 437252884aeSStefan Eßer 438252884aeSStefan Eßer return s; 439252884aeSStefan Eßer } 440252884aeSStefan Eßer 44150696a6eSStefan Eßer #if !BC_ENABLE_LIBRARY 442252884aeSStefan Eßer void bc_vm_printf(const char *fmt, ...) { 443252884aeSStefan Eßer 444252884aeSStefan Eßer va_list args; 445252884aeSStefan Eßer 446252884aeSStefan Eßer BC_SIG_LOCK; 447252884aeSStefan Eßer 448252884aeSStefan Eßer va_start(args, fmt); 449252884aeSStefan Eßer bc_file_vprintf(&vm.fout, fmt, args); 450252884aeSStefan Eßer va_end(args); 451252884aeSStefan Eßer 452252884aeSStefan Eßer vm.nchars = 0; 453252884aeSStefan Eßer 454252884aeSStefan Eßer BC_SIG_UNLOCK; 455252884aeSStefan Eßer } 45650696a6eSStefan Eßer #endif // !BC_ENABLE_LIBRARY 457252884aeSStefan Eßer 458252884aeSStefan Eßer void bc_vm_putchar(int c) { 45950696a6eSStefan Eßer #if BC_ENABLE_LIBRARY 46050696a6eSStefan Eßer bc_vec_pushByte(&vm.out, (uchar) c); 46150696a6eSStefan Eßer #else // BC_ENABLE_LIBRARY 462252884aeSStefan Eßer bc_file_putchar(&vm.fout, (uchar) c); 463252884aeSStefan Eßer vm.nchars = (c == '\n' ? 0 : vm.nchars + 1); 46450696a6eSStefan Eßer #endif // BC_ENABLE_LIBRARY 465252884aeSStefan Eßer } 466252884aeSStefan Eßer 46750696a6eSStefan Eßer #if !BC_ENABLE_LIBRARY 468252884aeSStefan Eßer static void bc_vm_clean(void) { 469252884aeSStefan Eßer 4703aa99676SStefan Eßer BcVec *fns = &vm.prog.fns; 471252884aeSStefan Eßer BcFunc *f = bc_vec_item(fns, BC_PROG_MAIN); 4723aa99676SStefan Eßer BcInstPtr *ip = bc_vec_item(&vm.prog.stack, 0); 4733aa99676SStefan Eßer bool good = ((vm.status && vm.status != BC_STATUS_QUIT) || vm.sig); 474252884aeSStefan Eßer 475252884aeSStefan Eßer if (good) bc_program_reset(&vm.prog); 476252884aeSStefan Eßer 477252884aeSStefan Eßer #if BC_ENABLED 478252884aeSStefan Eßer if (good && BC_IS_BC) good = !BC_PARSE_NO_EXEC(&vm.prs); 479252884aeSStefan Eßer #endif // BC_ENABLED 480252884aeSStefan Eßer 481252884aeSStefan Eßer #if DC_ENABLED 4823aa99676SStefan Eßer if (BC_IS_DC) { 483252884aeSStefan Eßer 484252884aeSStefan Eßer size_t i; 485252884aeSStefan Eßer 4863aa99676SStefan Eßer good = true; 487252884aeSStefan Eßer 4883aa99676SStefan Eßer for (i = 0; good && i < vm.prog.results.len; ++i) { 4893aa99676SStefan Eßer BcResult *r = (BcResult*) bc_vec_item(&vm.prog.results, i); 4903aa99676SStefan Eßer good = BC_VM_SAFE_RESULT(r); 491252884aeSStefan Eßer } 492252884aeSStefan Eßer } 493252884aeSStefan Eßer #endif // DC_ENABLED 494252884aeSStefan Eßer 495252884aeSStefan Eßer // If this condition is true, we can get rid of strings, 496252884aeSStefan Eßer // constants, and code. This is an idea from busybox. 4973aa99676SStefan Eßer if (good && vm.prog.stack.len == 1 && ip->idx == f->code.len) { 4983aa99676SStefan Eßer 499252884aeSStefan Eßer #if BC_ENABLED 500252884aeSStefan Eßer if (BC_IS_BC) { 501*10328f8bSStefan Eßer bc_vec_popAll(&f->labels); 502*10328f8bSStefan Eßer bc_vec_popAll(&f->strs); 503*10328f8bSStefan Eßer bc_vec_popAll(&f->consts); 504252884aeSStefan Eßer } 505252884aeSStefan Eßer #endif // BC_ENABLED 5063aa99676SStefan Eßer 5073aa99676SStefan Eßer #if DC_ENABLED 5083aa99676SStefan Eßer // Note to self: you cannot delete strings and functions. Deal with it. 509*10328f8bSStefan Eßer if (BC_IS_DC) bc_vec_popAll(vm.prog.consts); 5103aa99676SStefan Eßer #endif // DC_ENABLED 5113aa99676SStefan Eßer 512*10328f8bSStefan Eßer bc_vec_popAll(&f->code); 5133aa99676SStefan Eßer 514252884aeSStefan Eßer ip->idx = 0; 515252884aeSStefan Eßer } 516252884aeSStefan Eßer } 517252884aeSStefan Eßer 5185d934bc0SStefan Eßer static void bc_vm_process(const char *text) { 519252884aeSStefan Eßer 520252884aeSStefan Eßer bc_parse_text(&vm.prs, text); 521252884aeSStefan Eßer 522252884aeSStefan Eßer do { 523252884aeSStefan Eßer 524252884aeSStefan Eßer #if BC_ENABLED 525252884aeSStefan Eßer if (vm.prs.l.t == BC_LEX_KW_DEFINE) vm.parse(&vm.prs); 526252884aeSStefan Eßer #endif // BC_ENABLED 527252884aeSStefan Eßer 528252884aeSStefan Eßer while (BC_PARSE_CAN_PARSE(vm.prs)) vm.parse(&vm.prs); 529252884aeSStefan Eßer 530119656bcSStefan Eßer if(BC_IS_DC || !BC_PARSE_NO_EXEC(&vm.prs)) bc_program_exec(&vm.prog); 5313aa99676SStefan Eßer 5323aa99676SStefan Eßer assert(BC_IS_DC || vm.prog.results.len == 0); 5333aa99676SStefan Eßer 534252884aeSStefan Eßer if (BC_I) bc_file_flush(&vm.fout); 535252884aeSStefan Eßer 536252884aeSStefan Eßer } while (vm.prs.l.t != BC_LEX_EOF); 537252884aeSStefan Eßer } 538252884aeSStefan Eßer 5395d934bc0SStefan Eßer #if BC_ENABLED 5405d934bc0SStefan Eßer static void bc_vm_endif(void) { 5415d934bc0SStefan Eßer 5425d934bc0SStefan Eßer size_t i; 5435d934bc0SStefan Eßer bool good; 5445d934bc0SStefan Eßer 5455d934bc0SStefan Eßer if (BC_NO_ERR(!BC_PARSE_NO_EXEC(&vm.prs))) return; 5465d934bc0SStefan Eßer 5475d934bc0SStefan Eßer good = true; 5485d934bc0SStefan Eßer 5495d934bc0SStefan Eßer for (i = 0; good && i < vm.prs.flags.len; ++i) { 5505d934bc0SStefan Eßer uint16_t flag = *((uint16_t*) bc_vec_item(&vm.prs.flags, i)); 5515d934bc0SStefan Eßer good = ((flag & BC_PARSE_FLAG_BRACE) != BC_PARSE_FLAG_BRACE); 5525d934bc0SStefan Eßer } 5535d934bc0SStefan Eßer 5545d934bc0SStefan Eßer if (good) { 5555d934bc0SStefan Eßer while (BC_PARSE_IF_END(&vm.prs)) bc_vm_process("else {}"); 5565d934bc0SStefan Eßer } 55750696a6eSStefan Eßer else bc_parse_err(&vm.prs, BC_ERR_PARSE_BLOCK); 5585d934bc0SStefan Eßer } 5595d934bc0SStefan Eßer #endif // BC_ENABLED 5605d934bc0SStefan Eßer 561252884aeSStefan Eßer static void bc_vm_file(const char *file) { 562252884aeSStefan Eßer 563252884aeSStefan Eßer char *data = NULL; 564252884aeSStefan Eßer 565252884aeSStefan Eßer assert(!vm.sig_pop); 566252884aeSStefan Eßer 567252884aeSStefan Eßer bc_lex_file(&vm.prs.l, file); 568252884aeSStefan Eßer 569252884aeSStefan Eßer BC_SIG_LOCK; 570252884aeSStefan Eßer 571252884aeSStefan Eßer bc_read_file(file, &data); 572252884aeSStefan Eßer 573252884aeSStefan Eßer BC_SETJMP_LOCKED(err); 574252884aeSStefan Eßer 575252884aeSStefan Eßer BC_SIG_UNLOCK; 576252884aeSStefan Eßer 5775d934bc0SStefan Eßer bc_vm_process(data); 578252884aeSStefan Eßer 579252884aeSStefan Eßer #if BC_ENABLED 5805d934bc0SStefan Eßer if (BC_IS_BC) bc_vm_endif(); 581252884aeSStefan Eßer #endif // BC_ENABLED 582252884aeSStefan Eßer 583252884aeSStefan Eßer err: 584252884aeSStefan Eßer BC_SIG_MAYLOCK; 585252884aeSStefan Eßer 586252884aeSStefan Eßer free(data); 587252884aeSStefan Eßer bc_vm_clean(); 588252884aeSStefan Eßer 589252884aeSStefan Eßer // bc_program_reset(), called by bc_vm_clean(), resets the status. 590252884aeSStefan Eßer // We want it to clear the sig_pop variable in case it was set. 591252884aeSStefan Eßer if (vm.status == (sig_atomic_t) BC_STATUS_SUCCESS) BC_LONGJMP_STOP; 592252884aeSStefan Eßer 593252884aeSStefan Eßer BC_LONGJMP_CONT; 594252884aeSStefan Eßer } 595252884aeSStefan Eßer 596252884aeSStefan Eßer static void bc_vm_stdin(void) { 597252884aeSStefan Eßer 598252884aeSStefan Eßer BcStatus s; 599252884aeSStefan Eßer BcVec buf, buffer; 600252884aeSStefan Eßer size_t string = 0; 601252884aeSStefan Eßer bool comment = false, hash = false; 602252884aeSStefan Eßer 603252884aeSStefan Eßer bc_lex_file(&vm.prs.l, bc_program_stdin_name); 604252884aeSStefan Eßer 605252884aeSStefan Eßer BC_SIG_LOCK; 606252884aeSStefan Eßer bc_vec_init(&buffer, sizeof(uchar), NULL); 607252884aeSStefan Eßer bc_vec_init(&buf, sizeof(uchar), NULL); 608252884aeSStefan Eßer bc_vec_pushByte(&buffer, '\0'); 609252884aeSStefan Eßer BC_SETJMP_LOCKED(err); 610252884aeSStefan Eßer BC_SIG_UNLOCK; 611252884aeSStefan Eßer 612252884aeSStefan Eßer restart: 613252884aeSStefan Eßer 614252884aeSStefan Eßer // This loop is complex because the vm tries not to send any lines that end 615252884aeSStefan Eßer // with a backslash to the parser. The reason for that is because the parser 616252884aeSStefan Eßer // treats a backslash+newline combo as whitespace, per the bc spec. In that 617252884aeSStefan Eßer // case, and for strings and comments, the parser will expect more stuff. 618252884aeSStefan Eßer while ((!(s = bc_read_line(&buf, ">>> ")) || 619252884aeSStefan Eßer (vm.eof = (s == BC_STATUS_EOF))) && buf.len > 1) 620252884aeSStefan Eßer { 621252884aeSStefan Eßer char c2, *str = buf.v; 622252884aeSStefan Eßer size_t i, len = buf.len - 1; 623252884aeSStefan Eßer 624252884aeSStefan Eßer for (i = 0; i < len; ++i) { 625252884aeSStefan Eßer 626252884aeSStefan Eßer bool notend = len > i + 1; 627252884aeSStefan Eßer uchar c = (uchar) str[i]; 628252884aeSStefan Eßer 629252884aeSStefan Eßer hash = (!comment && !string && ((hash && c != '\n') || 630252884aeSStefan Eßer (!hash && c == '#'))); 631252884aeSStefan Eßer 632252884aeSStefan Eßer if (!hash && !comment && (i - 1 > len || str[i - 1] != '\\')) { 633252884aeSStefan Eßer if (BC_IS_BC) string ^= (c == '"'); 634252884aeSStefan Eßer else if (c == ']') string -= 1; 635252884aeSStefan Eßer else if (c == '[') string += 1; 636252884aeSStefan Eßer } 637252884aeSStefan Eßer 638252884aeSStefan Eßer if (BC_IS_BC && !hash && !string && notend) { 639252884aeSStefan Eßer 640252884aeSStefan Eßer c2 = str[i + 1]; 641252884aeSStefan Eßer 642252884aeSStefan Eßer if (c == '/' && !comment && c2 == '*') { 643252884aeSStefan Eßer comment = true; 644252884aeSStefan Eßer i += 1; 645252884aeSStefan Eßer } 646252884aeSStefan Eßer else if (c == '*' && comment && c2 == '/') { 647252884aeSStefan Eßer comment = false; 648252884aeSStefan Eßer i += 1; 649252884aeSStefan Eßer } 650252884aeSStefan Eßer } 651252884aeSStefan Eßer } 652252884aeSStefan Eßer 653252884aeSStefan Eßer bc_vec_concat(&buffer, buf.v); 654252884aeSStefan Eßer 655252884aeSStefan Eßer if (string || comment) continue; 656252884aeSStefan Eßer if (len >= 2 && str[len - 2] == '\\' && str[len - 1] == '\n') continue; 657252884aeSStefan Eßer #if BC_ENABLE_HISTORY 658252884aeSStefan Eßer if (vm.history.stdin_has_data) continue; 659252884aeSStefan Eßer #endif // BC_ENABLE_HISTORY 660252884aeSStefan Eßer 6615d934bc0SStefan Eßer bc_vm_process(buffer.v); 662252884aeSStefan Eßer bc_vec_empty(&buffer); 663252884aeSStefan Eßer 664252884aeSStefan Eßer if (vm.eof) break; 6653aa99676SStefan Eßer else bc_vm_clean(); 666252884aeSStefan Eßer } 667252884aeSStefan Eßer 668252884aeSStefan Eßer if (!BC_STATUS_IS_ERROR(s)) { 669252884aeSStefan Eßer if (BC_ERR(comment)) 67050696a6eSStefan Eßer bc_parse_err(&vm.prs, BC_ERR_PARSE_COMMENT); 671252884aeSStefan Eßer else if (BC_ERR(string)) 67250696a6eSStefan Eßer bc_parse_err(&vm.prs, BC_ERR_PARSE_STRING); 673252884aeSStefan Eßer #if BC_ENABLED 6745d934bc0SStefan Eßer else if (BC_IS_BC) bc_vm_endif(); 675252884aeSStefan Eßer #endif // BC_ENABLED 676252884aeSStefan Eßer } 677252884aeSStefan Eßer 678252884aeSStefan Eßer err: 679252884aeSStefan Eßer BC_SIG_MAYLOCK; 680252884aeSStefan Eßer 681252884aeSStefan Eßer bc_vm_clean(); 682252884aeSStefan Eßer 683*10328f8bSStefan Eßer #if !BC_ENABLE_MEMCHECK 684*10328f8bSStefan Eßer assert(vm.status != BC_STATUS_ERROR_FATAL); 685*10328f8bSStefan Eßer 686*10328f8bSStefan Eßer vm.status = vm.status == BC_STATUS_QUIT || !BC_I ? 687*10328f8bSStefan Eßer vm.status : BC_STATUS_SUCCESS; 688*10328f8bSStefan Eßer #else // !BC_ENABLE_MEMCHECK 689252884aeSStefan Eßer vm.status = vm.status == BC_STATUS_ERROR_FATAL || 690252884aeSStefan Eßer vm.status == BC_STATUS_QUIT || !BC_I ? 691252884aeSStefan Eßer vm.status : BC_STATUS_SUCCESS; 692*10328f8bSStefan Eßer #endif // !BC_ENABLE_MEMCHECK 693252884aeSStefan Eßer 694252884aeSStefan Eßer if (!vm.status && !vm.eof) { 695252884aeSStefan Eßer bc_vec_empty(&buffer); 696252884aeSStefan Eßer BC_LONGJMP_STOP; 697252884aeSStefan Eßer BC_SIG_UNLOCK; 698252884aeSStefan Eßer goto restart; 699252884aeSStefan Eßer } 700252884aeSStefan Eßer 701252884aeSStefan Eßer bc_vec_free(&buf); 702252884aeSStefan Eßer bc_vec_free(&buffer); 703252884aeSStefan Eßer 704252884aeSStefan Eßer BC_LONGJMP_CONT; 705252884aeSStefan Eßer } 706252884aeSStefan Eßer 707252884aeSStefan Eßer #if BC_ENABLED 708252884aeSStefan Eßer static void bc_vm_load(const char *name, const char *text) { 709252884aeSStefan Eßer 710252884aeSStefan Eßer bc_lex_file(&vm.prs.l, name); 711252884aeSStefan Eßer bc_parse_text(&vm.prs, text); 712252884aeSStefan Eßer 713252884aeSStefan Eßer while (vm.prs.l.t != BC_LEX_EOF) vm.parse(&vm.prs); 714252884aeSStefan Eßer } 715252884aeSStefan Eßer #endif // BC_ENABLED 716252884aeSStefan Eßer 717252884aeSStefan Eßer static void bc_vm_defaultMsgs(void) { 718252884aeSStefan Eßer 719252884aeSStefan Eßer size_t i; 720252884aeSStefan Eßer 721252884aeSStefan Eßer vm.func_header = bc_err_func_header; 722252884aeSStefan Eßer 723252884aeSStefan Eßer for (i = 0; i < BC_ERR_IDX_NELEMS + BC_ENABLED; ++i) 724252884aeSStefan Eßer vm.err_ids[i] = bc_errs[i]; 72550696a6eSStefan Eßer for (i = 0; i < BC_ERR_NELEMS; ++i) vm.err_msgs[i] = bc_err_msgs[i]; 726252884aeSStefan Eßer } 727252884aeSStefan Eßer 728252884aeSStefan Eßer static void bc_vm_gettext(void) { 729252884aeSStefan Eßer 730252884aeSStefan Eßer #if BC_ENABLE_NLS 731252884aeSStefan Eßer uchar id = 0; 732252884aeSStefan Eßer int set = 1, msg = 1; 733252884aeSStefan Eßer size_t i; 734252884aeSStefan Eßer 735252884aeSStefan Eßer if (vm.locale == NULL) { 736252884aeSStefan Eßer vm.catalog = BC_VM_INVALID_CATALOG; 737252884aeSStefan Eßer bc_vm_defaultMsgs(); 738252884aeSStefan Eßer return; 739252884aeSStefan Eßer } 740252884aeSStefan Eßer 741252884aeSStefan Eßer vm.catalog = catopen(BC_MAINEXEC, NL_CAT_LOCALE); 742252884aeSStefan Eßer 743252884aeSStefan Eßer if (vm.catalog == BC_VM_INVALID_CATALOG) { 744252884aeSStefan Eßer bc_vm_defaultMsgs(); 745252884aeSStefan Eßer return; 746252884aeSStefan Eßer } 747252884aeSStefan Eßer 748252884aeSStefan Eßer vm.func_header = catgets(vm.catalog, set, msg, bc_err_func_header); 749252884aeSStefan Eßer 750252884aeSStefan Eßer for (set += 1; msg <= BC_ERR_IDX_NELEMS + BC_ENABLED; ++msg) 751252884aeSStefan Eßer vm.err_ids[msg - 1] = catgets(vm.catalog, set, msg, bc_errs[msg - 1]); 752252884aeSStefan Eßer 753252884aeSStefan Eßer i = 0; 754252884aeSStefan Eßer id = bc_err_ids[i]; 755252884aeSStefan Eßer 75650696a6eSStefan Eßer for (set = id + 3, msg = 1; i < BC_ERR_NELEMS; ++i, ++msg) { 757252884aeSStefan Eßer 758252884aeSStefan Eßer if (id != bc_err_ids[i]) { 759252884aeSStefan Eßer msg = 1; 760252884aeSStefan Eßer id = bc_err_ids[i]; 761252884aeSStefan Eßer set = id + 3; 762252884aeSStefan Eßer } 763252884aeSStefan Eßer 764252884aeSStefan Eßer vm.err_msgs[i] = catgets(vm.catalog, set, msg, bc_err_msgs[i]); 765252884aeSStefan Eßer } 766252884aeSStefan Eßer #else // BC_ENABLE_NLS 767252884aeSStefan Eßer bc_vm_defaultMsgs(); 768252884aeSStefan Eßer #endif // BC_ENABLE_NLS 769252884aeSStefan Eßer } 770252884aeSStefan Eßer 7715d934bc0SStefan Eßer static void bc_vm_exec(void) { 772252884aeSStefan Eßer 773252884aeSStefan Eßer size_t i; 774252884aeSStefan Eßer bool has_file = false; 7753aa99676SStefan Eßer BcVec buf; 776252884aeSStefan Eßer 777252884aeSStefan Eßer #if BC_ENABLED 778252884aeSStefan Eßer if (BC_IS_BC && (vm.flags & BC_FLAG_L)) { 779252884aeSStefan Eßer 780252884aeSStefan Eßer bc_vm_load(bc_lib_name, bc_lib); 781252884aeSStefan Eßer 782252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH 783252884aeSStefan Eßer if (!BC_IS_POSIX) bc_vm_load(bc_lib2_name, bc_lib2); 784252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 785252884aeSStefan Eßer } 786252884aeSStefan Eßer #endif // BC_ENABLED 787252884aeSStefan Eßer 788252884aeSStefan Eßer if (vm.exprs.len) { 7893aa99676SStefan Eßer 7903aa99676SStefan Eßer size_t len = vm.exprs.len - 1; 7913aa99676SStefan Eßer bool more; 7923aa99676SStefan Eßer 7933aa99676SStefan Eßer BC_SIG_LOCK; 7943aa99676SStefan Eßer bc_vec_init(&buf, sizeof(uchar), NULL); 7953aa99676SStefan Eßer 7963aa99676SStefan Eßer #ifndef NDEBUG 7973aa99676SStefan Eßer BC_SETJMP_LOCKED(err); 7983aa99676SStefan Eßer #endif // NDEBUG 7993aa99676SStefan Eßer 8003aa99676SStefan Eßer BC_SIG_UNLOCK; 8013aa99676SStefan Eßer 802252884aeSStefan Eßer bc_lex_file(&vm.prs.l, bc_program_exprs_name); 8033aa99676SStefan Eßer 8043aa99676SStefan Eßer do { 8053aa99676SStefan Eßer 8063aa99676SStefan Eßer more = bc_read_buf(&buf, vm.exprs.v, &len); 8073aa99676SStefan Eßer bc_vec_pushByte(&buf, '\0'); 8085d934bc0SStefan Eßer bc_vm_process(buf.v); 8093aa99676SStefan Eßer 810*10328f8bSStefan Eßer bc_vec_popAll(&buf); 8113aa99676SStefan Eßer 8123aa99676SStefan Eßer } while (more); 8133aa99676SStefan Eßer 8143aa99676SStefan Eßer BC_SIG_LOCK; 8153aa99676SStefan Eßer bc_vec_free(&buf); 8163aa99676SStefan Eßer 8173aa99676SStefan Eßer #ifndef NDEBUG 8183aa99676SStefan Eßer BC_UNSETJMP; 8193aa99676SStefan Eßer #endif // NDEBUG 8203aa99676SStefan Eßer 8213aa99676SStefan Eßer BC_SIG_UNLOCK; 8223aa99676SStefan Eßer 8235d934bc0SStefan Eßer if (!vm.no_exit_exprs) return; 824252884aeSStefan Eßer } 825252884aeSStefan Eßer 826252884aeSStefan Eßer for (i = 0; i < vm.files.len; ++i) { 827252884aeSStefan Eßer char *path = *((char**) bc_vec_item(&vm.files, i)); 828252884aeSStefan Eßer if (!strcmp(path, "")) continue; 829252884aeSStefan Eßer has_file = true; 830252884aeSStefan Eßer bc_vm_file(path); 831252884aeSStefan Eßer } 832252884aeSStefan Eßer 833*10328f8bSStefan Eßer #if BC_ENABLE_AFL 834*10328f8bSStefan Eßer __AFL_INIT(); 835*10328f8bSStefan Eßer #endif // BC_ENABLE_AFL 836*10328f8bSStefan Eßer 837252884aeSStefan Eßer if (BC_IS_BC || !has_file) bc_vm_stdin(); 8383aa99676SStefan Eßer 8393aa99676SStefan Eßer // These are all protected by ifndef NDEBUG because if these are needed, bc is 840*10328f8bSStefan Eßer // going to exit anyway, and I see no reason to include this code in a release 8413aa99676SStefan Eßer // build when the OS is going to free all of the resources anyway. 8423aa99676SStefan Eßer #ifndef NDEBUG 8433aa99676SStefan Eßer return; 8443aa99676SStefan Eßer 8453aa99676SStefan Eßer err: 8463aa99676SStefan Eßer BC_SIG_MAYLOCK; 8473aa99676SStefan Eßer bc_vec_free(&buf); 8483aa99676SStefan Eßer BC_LONGJMP_CONT; 8493aa99676SStefan Eßer #endif // NDEBUG 850252884aeSStefan Eßer } 851252884aeSStefan Eßer 852252884aeSStefan Eßer void bc_vm_boot(int argc, char *argv[], const char *env_len, 8535d934bc0SStefan Eßer const char* const env_args) 854252884aeSStefan Eßer { 855252884aeSStefan Eßer int ttyin, ttyout, ttyerr; 856252884aeSStefan Eßer struct sigaction sa; 857252884aeSStefan Eßer 858252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 859252884aeSStefan Eßer 860252884aeSStefan Eßer ttyin = isatty(STDIN_FILENO); 861252884aeSStefan Eßer ttyout = isatty(STDOUT_FILENO); 862252884aeSStefan Eßer ttyerr = isatty(STDERR_FILENO); 863252884aeSStefan Eßer 864252884aeSStefan Eßer vm.flags |= ttyin ? BC_FLAG_TTYIN : 0; 865252884aeSStefan Eßer vm.flags |= (ttyin != 0 && ttyout != 0 && ttyerr != 0) ? BC_FLAG_TTY : 0; 866252884aeSStefan Eßer vm.flags |= ttyin && ttyout ? BC_FLAG_I : 0; 867252884aeSStefan Eßer 868252884aeSStefan Eßer sigemptyset(&sa.sa_mask); 869252884aeSStefan Eßer sa.sa_handler = bc_vm_sig; 870252884aeSStefan Eßer sa.sa_flags = SA_NODEFER; 871252884aeSStefan Eßer 872252884aeSStefan Eßer sigaction(SIGTERM, &sa, NULL); 873252884aeSStefan Eßer sigaction(SIGQUIT, &sa, NULL); 874252884aeSStefan Eßer sigaction(SIGINT, &sa, NULL); 875252884aeSStefan Eßer 876252884aeSStefan Eßer #if BC_ENABLE_HISTORY 877252884aeSStefan Eßer if (BC_TTY) sigaction(SIGHUP, &sa, NULL); 878252884aeSStefan Eßer #endif // BC_ENABLE_HISTORY 879252884aeSStefan Eßer 88050696a6eSStefan Eßer bc_vm_init(); 881252884aeSStefan Eßer 882252884aeSStefan Eßer vm.file = NULL; 883252884aeSStefan Eßer 884252884aeSStefan Eßer bc_vm_gettext(); 885252884aeSStefan Eßer 886252884aeSStefan Eßer bc_file_init(&vm.ferr, STDERR_FILENO, output_bufs + BC_VM_STDOUT_BUF_SIZE, 887252884aeSStefan Eßer BC_VM_STDERR_BUF_SIZE); 888252884aeSStefan Eßer bc_file_init(&vm.fout, STDOUT_FILENO, output_bufs, BC_VM_STDOUT_BUF_SIZE); 889252884aeSStefan Eßer vm.buf = output_bufs + BC_VM_STDOUT_BUF_SIZE + BC_VM_STDERR_BUF_SIZE; 890252884aeSStefan Eßer 891252884aeSStefan Eßer vm.line_len = (uint16_t) bc_vm_envLen(env_len); 892252884aeSStefan Eßer 893252884aeSStefan Eßer bc_vec_clear(&vm.files); 894252884aeSStefan Eßer bc_vec_clear(&vm.exprs); 895252884aeSStefan Eßer 896252884aeSStefan Eßer bc_program_init(&vm.prog); 897252884aeSStefan Eßer bc_parse_init(&vm.prs, &vm.prog, BC_PROG_MAIN); 898252884aeSStefan Eßer 899252884aeSStefan Eßer #if BC_ENABLE_HISTORY 900252884aeSStefan Eßer if (BC_TTY) bc_history_init(&vm.history); 901252884aeSStefan Eßer #endif // BC_ENABLE_HISTORY 902252884aeSStefan Eßer 903252884aeSStefan Eßer #if BC_ENABLED 904252884aeSStefan Eßer if (BC_IS_BC) vm.flags |= BC_FLAG_S * (getenv("POSIXLY_CORRECT") != NULL); 905252884aeSStefan Eßer #endif // BC_ENABLED 906252884aeSStefan Eßer 907252884aeSStefan Eßer bc_vm_envArgs(env_args); 908252884aeSStefan Eßer bc_args(argc, argv); 909252884aeSStefan Eßer 9103aa99676SStefan Eßer #if BC_ENABLED 911252884aeSStefan Eßer if (BC_IS_POSIX) vm.flags &= ~(BC_FLAG_G); 9123aa99676SStefan Eßer #endif // BC_ENABLED 913252884aeSStefan Eßer 91450696a6eSStefan Eßer BC_SIG_UNLOCK; 91550696a6eSStefan Eßer 91650696a6eSStefan Eßer bc_vm_exec(); 91750696a6eSStefan Eßer } 91850696a6eSStefan Eßer #endif // !BC_ENABLE_LIBRARY 91950696a6eSStefan Eßer 92050696a6eSStefan Eßer void bc_vm_init(void) { 92150696a6eSStefan Eßer 92250696a6eSStefan Eßer BC_SIG_ASSERT_LOCKED; 92350696a6eSStefan Eßer 92450696a6eSStefan Eßer memcpy(vm.max_num, bc_num_bigdigMax, 92550696a6eSStefan Eßer bc_num_bigdigMax_size * sizeof(BcDig)); 92650696a6eSStefan Eßer memcpy(vm.max2_num, bc_num_bigdigMax2, 92750696a6eSStefan Eßer bc_num_bigdigMax2_size * sizeof(BcDig)); 92850696a6eSStefan Eßer bc_num_setup(&vm.max, vm.max_num, BC_NUM_BIGDIG_LOG10); 92950696a6eSStefan Eßer bc_num_setup(&vm.max2, vm.max2_num, BC_NUM_BIGDIG_LOG10); 93050696a6eSStefan Eßer vm.max.len = bc_num_bigdigMax_size; 93150696a6eSStefan Eßer vm.max2.len = bc_num_bigdigMax2_size; 93250696a6eSStefan Eßer 93350696a6eSStefan Eßer bc_vec_init(&vm.temps, sizeof(BcNum), NULL); 93450696a6eSStefan Eßer 935252884aeSStefan Eßer vm.maxes[BC_PROG_GLOBALS_IBASE] = BC_NUM_MAX_POSIX_IBASE; 936252884aeSStefan Eßer vm.maxes[BC_PROG_GLOBALS_OBASE] = BC_MAX_OBASE; 937252884aeSStefan Eßer vm.maxes[BC_PROG_GLOBALS_SCALE] = BC_MAX_SCALE; 938252884aeSStefan Eßer 9393aa99676SStefan Eßer #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 940252884aeSStefan Eßer vm.maxes[BC_PROG_MAX_RAND] = ((BcRand) 0) - 1; 9413aa99676SStefan Eßer #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 942252884aeSStefan Eßer 9433aa99676SStefan Eßer #if BC_ENABLED 94450696a6eSStefan Eßer #if !BC_ENABLE_LIBRARY 945252884aeSStefan Eßer if (BC_IS_BC && !BC_IS_POSIX) 94650696a6eSStefan Eßer #endif // !BC_ENABLE_LIBRARY 94750696a6eSStefan Eßer { 948252884aeSStefan Eßer vm.maxes[BC_PROG_GLOBALS_IBASE] = BC_NUM_MAX_IBASE; 94950696a6eSStefan Eßer } 9503aa99676SStefan Eßer #endif // BC_ENABLED 951252884aeSStefan Eßer } 952*10328f8bSStefan Eßer 953*10328f8bSStefan Eßer #if BC_ENABLE_LIBRARY 954*10328f8bSStefan Eßer void bc_vm_atexit(void) { 955*10328f8bSStefan Eßer 956*10328f8bSStefan Eßer bc_vm_shutdown(); 957*10328f8bSStefan Eßer 958*10328f8bSStefan Eßer #ifndef NDEBUG 959*10328f8bSStefan Eßer bc_vec_free(&vm.jmp_bufs); 960*10328f8bSStefan Eßer #endif // NDEBUG 961*10328f8bSStefan Eßer } 962*10328f8bSStefan Eßer #else // BC_ENABLE_LIBRARY 963*10328f8bSStefan Eßer int bc_vm_atexit(int status) { 964*10328f8bSStefan Eßer 965*10328f8bSStefan Eßer int s = BC_STATUS_IS_ERROR(status) ? status : BC_STATUS_SUCCESS; 966*10328f8bSStefan Eßer 967*10328f8bSStefan Eßer bc_vm_shutdown(); 968*10328f8bSStefan Eßer 969*10328f8bSStefan Eßer #ifndef NDEBUG 970*10328f8bSStefan Eßer bc_vec_free(&vm.jmp_bufs); 971*10328f8bSStefan Eßer #endif // NDEBUG 972*10328f8bSStefan Eßer 973*10328f8bSStefan Eßer return s; 974*10328f8bSStefan Eßer } 975*10328f8bSStefan Eßer #endif // BC_ENABLE_LIBRARY 976